0
点赞
收藏
分享

微信扫一扫

浅谈java反射机制-------反射机制的由来(8.26更新)


java反射机制

  • ​​问题提出​​
  • ​​代码实现​​
  • ​​代码实现----多态​​
  • ​​代码实现----反射​​
  • ​​创建对象的方式:​​
  • ​​类中有无参构造-----​​
  • ​​类中没有无参构造------​​
  • ​​getDeclaredConstructor()与getConstructor()的区别​​
  • ​​创建对象之前的工作----加载类的字节码信息​​
  • ​​通过反射还能获取啥信息?​​
  • ​​获得属性,方法,注解------​​
  • ​​测试代码---------------获取属性相关信息​​
  • ​​测试代码---------------获取方法相关信息​​
  • ​​测试代码---------------获取注解相关信息​​
  • ​​通过反射调用方法-----​​

问题提出

一个公司要开发本公司APP,某程序员在支付功能处给出了两种解决方案-----
第一种---------
利用多态来完成

第二种--------
是利用反射机制完成

代码实现

代码实现----多态

class AlipayM  implements WoerMa{
@Override
public void payOnline() {
System.out.println("阿里支付");
}
}
class WechatPayM implements WoerMa {
@Override
public void payOnline() {
System.out.println("微信支付");
}
}
class WoermaCard implements WoerMa {
@Override
public void payOnline() {
System.out.println("沃尔玛钱包");
}
}
public class ZhaoHang implements WoerMa{
@Override
public void payOnline() {
System.out.println("招行支付");
}
}

测试方法-----

public class WoermaTest {
public static void main(String[] args) {
String string= "微信";
switch(string){
case "招行" :
pay(new ZhaoHang());
break;
case "阿里":
pay(new AlipayM());
break;
case "微信":
pay(new WechatPayM());
break;
default:
pay(new WoermaCard());
}

}
public static void pay(WoerMa woerMa){
woerMa.payOnline();
}

}

以上方式虽然用了多态的方式(参数为接口,传入的为参数的实现类)解决了一些问题,但仍然会有维护起来比较繁琐的问题既要维护实现类,又要维护测试类.

代码实现----反射

需要修改测试类即可,

以后再次添加支付方式时只需要维护该实现类即可;

public class WoermaTest {
public static void main(String[] args) {
String string= "com.woerma.client.ZhaoHang";
try {
Class client=Class.forName(string);//通过路径来获得类

Object obj= client.newInstance();
//在最新版本中通过newInstance()方法直接获得实例已被弃用;
//此种方式要求的是类中有无参的构造
Method method=client.getMethod("payOnline");
method.invoke(obj);

} catch (Exception e) {
e.printStackTrace();
}
}

可以通过获得构造方法来间接获得实例;
通过获得构造方法来间接获得实例适用于有参和无参的构造;

public class WoermaTest {
public static void main(String[] args) {
String string= "com.woerma.client.ZhaoHang";
try {
Class client=Class.forName(string);//通过路径来获得类
Constructor constructor = client.getConstructor();
Object obj = constructor.newInstance();

Method method=client.getMethod("payOnline");
method.invoke(obj);

} catch (Exception e) {
e.printStackTrace();
}
}


}

创建对象的方式:

1、使用Class对象的newInstance()方法创建该Class对象的实例,此时该Class对象必须要有无参数的构造方法,在最新的JDK版本中这种方式已被弃用;

2、使用Class对象获取指定的Constructor对象,再调用Constructor的newInstance()方法创建对象类的实例,此时可以选择使用某个构造方法。如果这个构造方法被私有化起来,那么必须先申请访问,将可以访问设置为true;

类中有无参构造-----

class Alibaba{

public Alibaba() {
System.out.println("创建对象成功");
}
}
public class reflecTest {
public static void main(String[] args) throws ClassNotFoundException {
//创建对象
//传统方式
new Alibaba();
//反射方式
Class Ali=Class.forName("com.woerma.client.Alibaba");
Ali.newInstance();
}
}

浅谈java反射机制-------反射机制的由来(8.26更新)_反射

以上通过无参来直接获得类的实例的方式在新版本种已被废弃;

类中没有无参构造------

如果依旧是上面的代码----会出现错误,

浅谈java反射机制-------反射机制的由来(8.26更新)_System_02

class Alibaba{
String name;
int productNum;

public Alibaba(String name, int productNum) {
this.name = name;
this.productNum = productNum;
System.out.println(name+"------"+productNum);
System.out.println("创建有参对象成功");

}


}
public class reflecTest {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//创建对象
//传统方式
new Alibaba("圆珠笔",100);
//反射方式
Class Ali=Class.forName("com.woerma.client.Alibaba");
Constructor constructor = Ali.getConstructor(String.class,int.class);//参数类型
/*或者这个方法---- Constructor constructor = Ali.getDeclaredConstructor(String.class,int.class);*/
Object o = constructor.newInstance("圆珠笔",100);


}
}

浅谈java反射机制-------反射机制的由来(8.26更新)_反射_03


接下来看构造方法私有化的情况下

class Alibaba{
private String name;
private int productNum;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getProductNum() {
return productNum;
}

public void setProductNum(int productNum) {
this.productNum = productNum;
}

private Alibaba(String name, int productNum) {
this.name = name;
this.productNum = productNum;
System.out.println(name+"------"+productNum);
System.out.println("创建有参对象成功");

}
static Alibaba alibaba= new Alibaba("圆珠笔",100);
public static Alibaba getInstance(){
return alibaba;
}
}
public class reflecTest {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//创建对象
//传统方式
Alibaba.getInstance();//单例设计
//反射方式
Class Ali=Class.forName("com.woerma.client.Alibaba");
// Constructor constructor = Ali.getConstructor(String.class,int.class);//参数类型
Constructor constructor = Ali.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);//获得访问权限
Object o = constructor.newInstance("圆珠笔",100);


}
}

浅谈java反射机制-------反射机制的由来(8.26更新)_System_04

getDeclaredConstructor()与getConstructor()的区别

从代码中观察----

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

class A{
String name;
public A() {
System.out.println("获得了无参实例");
}
private A(String name){
System.out.println("获得了有参实例");
}

}
public class ReflectTest0001 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class cla=Class.forName("com.woerma.client.A");
Constructor constructor = cla.getConstructor(String.class);
Constructor declaredConstructor = cla.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
constructor.newInstance("李四");
declaredConstructor.setAccessible(true);
declaredConstructor.newInstance("张三");
}
}

在访问公有构造器时两者都可以,但是当用getConstructor()访问私有构造器时取出现了----错误

浅谈java反射机制-------反射机制的由来(8.26更新)_反射_05

所以两者区别如下----

getConstructor()返回指定参数类型public的构造器。
getDeclaredConstructor()返回指定参数类型的private和public构造器。

同时要注意在访问私有构造时要先设定方位权限为true,不然getDeclaredConstructor()也不能访问;

由此来看单例设计也并不安全,

来看枚举类中的反射情况-----

enum  ThreeColor{
RED("红"),
GREEN("绿"),
YELLOW("黄");
String desc;
ThreeColor(String desc){
this.desc=desc;
}

public String getDesc() {
return desc;
}

public void setDesc(String desc) {
this.desc = desc;
}
}
public class ReflectTest0001 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class cla=Class.forName("com.woerma.client.ThreeColor");
Constructor declaredConstructor = cla.getDeclaredConstructor(String.class);
declaredConstructor.setAccessible(true);
declaredConstructor.newInstance("红");
}
}

对枚举而言,连构造器都获得不了,所以没法获得实例,所以对于实例个数限定的可以用枚举来以确保内存的安全性

同理就可以理解 对应其他的getDeclaredxxx()方法和getxxx()方法的区别

创建对象之前的工作----加载类的字节码信息

四种方式可以加载类的字节码信息-----

class Student{}

public class Person {
public static void main(String[] args) throws ClassNotFoundException {
//方式一----直接通过系统内置类加载器获得
Class aClass = Student.class;
//方式二----通过调用对象的getClass()方法获得
Student per= new Student();
Class aClass1 = per.getClass();
System.out.println(aClass);
//方式三---
Class aClass2=Class.forName("com.gavin.flect.Student");
//方式四-----
ClassLoader classLoader=Person.class.getClassLoader();//获得来的加载器
Class aClass3 = classLoader.loadClass("com.gavin.flect.Student");//通过类加载器来完成字节码信息的加载
System.out.println(aClass==aClass1);
System.out.println(aClass1==aClass2);
System.out.println(aClass2==aClass3);
}
}

最常用的为第三种;

通过反射还能获取啥信息?

简单地说是能获取该类在运行时所有的信息-----属性,方法等;
也能获得父类的一些信息;

获得属性,方法,注解------

通过反射获得属性(包括修饰符,属性名)和方法(包括参数类型,返回值)----

package com.gavin.flect;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
* @author : Gavin
* @date: 2021/8/26 - 08 - 26 - 15:47
* @Description: com.gavin.flect
* @version: 1.0
*/

class FatherTest {
@MySon(name="李二狗他爸",age=48)
void eat(String food){//default
System.out.println("我爱吃----"+food);
}
}
class SonTest extends FatherTest{
//属性区
public static String name;
private int age;
String gender;
//构造方法区

public SonTest(String name, int age) {
this.name = name;
this.age = age;
}

private SonTest(String name) {
this.name = name;
}

//方法区
@MySon(name="李二狗",age=18)
void eat(String food){//default
System.out.println("我爱吃----"+food);
}
public String show(String show,int age){
return "我"+age+"岁就会表演---"+show;
}
protected int getAge(){
return 19;
}

private static void call(){
System.out.println("有事给我打电话");
}
}

测试代码---------------获取属性相关信息

class Test{
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class cla=Class.forName("com.gavin.flect.SonTest") ;
//获得属性
Field name = cla.getField("name");//getField()只能获得public修饰的属性
System.out.println(name);
System.out.println(name.getName());//获取属性名
int modifiers = name.getModifiers();//获取属性修饰符
System.out.println(Modifier.toString(modifiers));//打印修饰符
System.out.println("1-----------------");
Field[] shuxing = cla.getDeclaredFields();//getDeclaredFields可获得所有
for ( Field f:shuxing
) {
System.out.println(f.toString());
}
}
}

浅谈java反射机制-------反射机制的由来(8.26更新)_System_06

测试代码---------------获取方法相关信息

class Test{
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class cla=Class.forName("com.gavin.flect.SonTest") ;

//获取方法
Method[] dMethods = cla.getMethods();//获取当前类中的所有被public修饰的方法包括父类中的被public修饰的
for (Method d:dMethods
) {
System.out.println(d);
}
System.out.println("1----------------------");
Method show = cla.getMethod("show", String.class, int.class);//getMethod只能获得public修饰的方法
System.out.println(show);
int modifiers = show.getModifiers();//获得方法的修饰符
System.out.println(Modifier.toString(modifiers));//打印修饰符
System.out.println("2----------------------");
Class cla1=Class.forName("com.gavin.flect.SonTest") ;
Method[] declaredMethods1 = cla1.getDeclaredMethods();//获得当前类中的所有方法---不包括父类
for (Method d :
declaredMethods1) {
System.out.println(d);
}

}
}

浅谈java反射机制-------反射机制的由来(8.26更新)_创建对象_07

测试代码---------------获取注解相关信息

class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class cla = Class.forName("com.gavin.flect.SonTest");

Method eat = cla.getDeclaredMethod("eat", String.class);
Annotation[] declaredAnnotations = eat.getDeclaredAnnotations();//得到该方法上的所有注解----RetentionPolicy.RUNTIME条件下的
for (Annotation an :
declaredAnnotations) {
System.out.println(an);
}
Annotation annotation = eat.getAnnotation(MySon.class);
System.out.println(annotation);

}
}
}

浅谈java反射机制-------反射机制的由来(8.26更新)_System_08


在SonTest类中补充方法funmethod()----获取参数的注解----

private void funmethod(@MySon int a,@Myfather(height = 188.8) double b){

}

测试类—

class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class cla = Class.forName("com.gavin.flect.SonTest");
Method funmethod = cla.getDeclaredMethod("funmethod", int.class, double.class);
Annotation[][] parameterAnnotations = funmethod.getParameterAnnotations();
for (Annotation [] p:parameterAnnotations
) {
for (Annotation pp:p
) {
System.out.println(pp);
}
}

}
}

浅谈java反射机制-------反射机制的由来(8.26更新)_java_09

通过反射调用方法-----

class Test {
public static void main(String[] args) throws Exception {
Class cla = Class.forName("com.gavin.flect.SonTest");//加载类字节码信息
Constructor de = cla.getDeclaredConstructor(String.class);//获得构造方法
de.setAccessible(true);//私有构造要设置权限可访问
Object o = de.newInstance("李二狗");//实例化----可以转型也可以不转
Method eat=cla.getDeclaredMethod("eat", String.class);//获得方法
eat.invoke(o,"鱼");//运行方法----invoke(对象,方法参数)

}
}

浅谈java反射机制-------反射机制的由来(8.26更新)_创建对象_10


未完待续…21.8.26


举报

相关推荐

0 条评论