Java反射学习小结

JAVA反射学习小结

将类的各个组成部分封装为其他对象

可以参照一下上面类加载的图片,可以知道反射就是将里面的成员方法封装为Method对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BDGXOTvL-1626659342271)(D:\Program Files (x86)]\IDEAProJect\Java入门笔记\Java入门\java进阶\image-20210713131749315.png)

好处

  • 可以再程序运行期间 , 操作这些对象

  • 可以解耦 , 提高程序的可扩展性

Class对象的获取方式

因为要使用反射来获取成员方法构造方法和成员变量需要用到Class类对象,所以需要学会获取Class类对象

以下为获取方法

  • 在源码阶段使用
    • Class.forName(“全类名”); //将字节码文件加载进内存,返回class对象
      • 多用于配置文件中,将类名定义在配置文件中.
      • 用于读取文件,加载类
  • 在Class对象阶段
    • 类名.class //通过类名的class属性来获取
      • 多用于参数的传递
  • 运行时阶段使用
    • 对象.getClass(); //在Object中定义的通用方法
      • 用于对象来获取字节码文件
//1.Class.forName("全类名");
//这里的全类名指的就是将package后面的内容加上 .文件名
Class cls1 = Class.forName("po.Person");
System.out.println(cls1);
//class po.Person

//2. 类名.class
Class cls2 = Person.class;
System.out.println(cls2);

//3. 对象.class();
Person p = new Person();
Class cls3 = p.getClass();
System.out.println(cls3);

//同一个字节码文件(.class)在一次程序运行中只会被加载一次,无论通过哪一种方式获取的Class对象都是同一个

Class对象的功能

获取功能

获取成员变量
  • Field[] getFields() 获取所有public修饰的成员变量
  • Field getField(String name) 获取指定的public修饰的成员变量
  • Field[] getDeclaredFields()
  • Field getDeclaredField(String name)
Class personClass = Person.class;

Field[] fields = personClass.getFields();
for (Field field : fields) {
    //遍历获取到的成员变量们
    System.out.println(field);
}

System.out.println("------------");
Field a = personClass.getField("a");

//成员变量有2个方法,get和set
Person p = new Person();
p.a = "abc";
Object o = a.get(p);
System.out.println(o);
//输出abc,为a变量所对应的值
a.set(p,"张三");
System.out.println(p.a);
//输出张三,为a所被修改后的值

System.out.println("------------");
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
    System.out.println(declaredField);
    //获取成员方法们
    /*这个是不考虑修饰符的
    * private java.lang.String po.Person.Name
      private int po.Person.age
      public java.lang.String po.Person.a
    protected java.lang.String po.Person.b
    java.lang.String po.Person.c
    private java.lang.String po.Person.d*/
}
Field name = personClass.getDeclaredField("Name");
p.setName("王五");
//这样直接获取到的私有的成员变量会报错
//所以要使用暴力反射
name.setAccessible(true);
Object o1 = name.get(p);
System.out.println(o1);
//输出设置的name为王五
成员变量的使用
//这里的a是获取的成员变量,定义在Person这个类中的public String a;
//成员变量有2个方法,get和set
Person p = new Person();
p.a = "abc";
Object o = a.get(p);
System.out.println(o);
//输出abc,为a变量所对应的值
a.set(p,"张三");
System.out.println(p.a);
//输出张三,为a所被修改后的值
获取构造方法们
  • Constructor<?>[] getConstructors()
  • Constructor getConstructor(类<?>… parameterTypes)
  • Constructor getDeclaredConstructor(类<?>… parameterTypes)
  • Constructor<?>[] getDeclaredConstructors()
Class personClass = Person.class;
Constructor constructor = personClass.getConstructor(String.class, int.class);
//因为用于区分构造方法的主要是靠传入的参数,所以这里我们传入String和int类型的数据
System.out.println(constructor);

//获取到的constructor对象主要是用来创建对象用的
Object object = constructor.newInstance("张三", 18);
System.out.println(object);
//Person{Name='张三', age=18, a='null', b='null', c='null', d='null'},调用对应的Person的toString方法

System.out.println("-----------------");
//也可以使用空参的构造器
Constructor constructor1 = personClass.getConstructor();
Object o = constructor1.newInstance();
//这样这里就不用传递参数了
System.out.println(o);
//Person{Name='null', age=0, a='null', b='null', c='null', d='null'}

//为了简化这部分的操作,class里面也有个newInstance方法可以使用
Object o1 = personClass.newInstance();
System.out.println(o1);
//用于调用空参的构造方法
//Person{Name='null', age=0, a='null', b='null', c='null', d='null'}

//constructor.setAccessible(true);
//这里一样可以使用暴力破解的方法
获取成员方法们
  • Method[] getMethods()
  • Method getMethod(String name, 类<?>… parameterTypes)
  • Method[] getDeclaredMethods()
  • Method getDeclaredMethod(String name, 类<?>… parameterTypes)
Class personClass = Person.class;

Method eat_Method = personClass.getMethod("eat");
//获取方法名称
Person p = new Person();
eat_Method.invoke(p);
//这个invoke需要传入对象和传入参数
//我在吃饭

//用传入的参数.class来区分重构的方法
Method eat_Method2 = personClass.getMethod("eat",String.class);
eat_Method2.invoke(p,"shit");
//我在次shit

System.out.println("-------------------");
//获取所有public修饰的方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
    System.out.println(method);
    //这里打印的除了Person中定义的public方法,还有Object所定义的方法
    String name = method.getName();
    System.out.println("方法名为"+name);
    //可以像下面这样获取方法
    if(name.equals("setAge")){
        method.invoke(p,18);
    }
}
System.out.println(p);
//Person{Name='null', age=18, a='null', b='null', c='null', d='null'}
获取类名
  • String getName()
Class personClass = Person.class;

        //获取类名
        String name = personClass.getName();
        System.out.println(name);
        //po.Person
通过反射越过泛型检查

如果在定义一些含有泛型的变量的时候,在调用该变量的一些方法就会有一个泛型的检查(如定义一个ArrayList的集合),这里可以通过反射来绕开这个检查

ArrayList<String> strList = new ArrayList<>();
strList.add("aaa");
strList.add("bbb");
//	strList.add(100);
//获取ArrayList的Class对象,反向的调用add()方法,添加数据
Class listClass = strList.getClass(); //得到 strList 对象的字节码 对象
//获取add()方法
Method m = listClass.getMethod("add", Object.class);
//这里传入Object.class是关键
//调用add()方法
m.invoke(strList, 100);
	
//遍历集合
for(Object obj : strList){
	System.out.println(obj);
}
//aaa
//bbb
//100

案例

写一个框架,在不改变该类的任何代码的情况下,可以创建任意的对象并执行其中任意的方法

实现

  • 配置文件
  • 反射
/*加载配置文件*/
Properties pro = new Properties();
//使用的这个Properties类可以将 .properties后缀的文件加载进内存
ClassLoader classLoader = 案例.class.getClassLoader();
//获取目前执行的这个案例的类加载器
InputStream is = classLoader.getResourceAsStream("pro.properties");
pro.load(is);

//加载进内存后就是获取方法和类
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");

//获取类对象,将该类加载进内存
Class cls = Class.forName(className);
//创建对象
Object o = cls.newInstance();
//获取方法对象
Method method = cls.getMethod(methodName);
//运行方法
method.invoke(o,"shi");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值