java 类加载器反射
Posted 呐呐呐那
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 类加载器反射相关的知识,希望对你有一定的参考价值。
字节码对象,当我们保存后程序产生的.class文件是编译后的文件,当我们运行程序的时候,程序去读取.class文件,这个文件会存到内存中,在堆中创建一个.class文件对象
当程序要使用某个类的时候,该类还没有到内存中去,会通过加载,连接,初始化3步对这个类进行初始化
加载,将class文件对象加载到内存中去,创建一个class对象,任何类在被使用时都会创一个class对象
连接,1.检验,检查语法是否有问题,跟其他类是否协调
2.准备,给静态成员变量初始化值
3.解析,将符号引用改成直接引用
例如:int a = 1;解析就是把a直接改成1了
类什么时候初始化
1.创建类的时候
2.类的静态方法
3.类的静态成员变量赋值的时候
4.反射创建某个类的时候
5.调用某个类的子类的时候
6.直接运行程序的时候
类的加载器组成
反射
对于java中任意一个类,我们可以知道他的方法和属性,对于任意一个对象,我们可以调用他的方法和属性,解剖出来,这叫做java的反射机制
首先我们要获取这个类的字节码对象,对他进行操作
有3种方式
我们先创建一个类person
1 package com.orcale.damo01; 2 3 public class Person { 4 public String name; 5 private int age; 6 static{ 7 System.out.println("静态代码块"); 8 } 9 public Person(){ 10 System.out.println("空参构造"); 11 } 12 public Person(String name,int age){ 13 this.name= name; 14 this.age= age; 15 System.out.println("有参构造"); 16 } 17 private Person(int age,String name){ 18 this.age = age; 19 this.name= name; 20 System.out.println("有参构造"); 21 } 22 public void eat(){ 23 System.out.println("吃饭"); 24 } 25 public void work(String name){ 26 System.out.println(name+"走路"); 27 } 28 private void run(String name){ 29 System.out.println(name+"跑步"); 30 } 31 @Override 32 public String toString() { 33 return "Person [name=" + name + ", age=" + age + "]"; 34 } 35 }
通过对象获取字节码对象
1 Person p = new Person(); 2 Class c = p.getClass();
System.out.println(c);
通过类名获取
1 Class c1 = Person.class;
通过class的静态方法获取forName(完成的类名,包名)
1 Class c2 = Class.forName("com.orcale.damo01.Person"); 2 System.out.println(c2);
获取公共的构造方法
1 Class c = Person.class; 2 Constructor con =c.getConstructor(这里如果是有参构造就写参数);
就表示为
Constructor con =c.getConstructor(Sting.calss,int.class)数据类型在前,class在后面,具体看构造参数
3 System.out.println(con);
获取所有的公共的构造方法
1 Class c = Person.class; 2 Constructor[] con = c.getConstructors(); 一个对象数组,把所有的构造方法都放进去 3 for(Constructor co:con){ 4 System.out.println(co); 5 }
获取公共的方法
1 Class c = Person.class; 2 Constructor con =c.getConstructor(String.class,int.class); 3 //因为Person类中没有单独String name的构造方法,所以写了2个, 4 Object obj = c.newInstance(); 5 //创建一个对象祖宗类,然后用字节码对象获取方法 6 //getMethod("第一个写需要调用的方法名字",写需要传入的参数); 7 Method me = c.getMethod("work", String.class); 8 //调用方法用invoke方法(第一个写对象,第二个写需要传入的实参) 9 me.invoke(obj, "小明");
获取所有的公共方法和获取所有的公共构造方法差不多,整个数组遍历就可以了
获取所有的公共成员变量
1 Class c= Person.class; 2 Field[] f= c.getFields(); //通过Field【】方法数组 3 for(Field ff:f){ 4 System.out.println(ff); 5 }
获取指定的公共成员变量
1 Class c= Person.class; 2 Field f= c.getField("name"); 3 System.out.println(f);
修改公共的成员变量赋值
1 Class c= Person.class; 2 Field f= c.getField("name"); 3 Object obj = c.newInstance(); 4 //调用set方法对name赋值,然后输出对象的属性 5 f.set(obj, "小明"); 6 System.out.println(obj)
获取私有的构造方法
原理是通过setAccessible方法,避开了对类的加载器对类的检查,不建议对私有的构造方法和属性操作,不然还私有干啥没有意义了
1 Class c =Person.class; 2 Constructor con = c.getDeclaredConstructor(int.class,String.class); 3 con.setAccessible(true);//暴力反射开关 4 Object obj = con.newInstance(12,"dd"); 5 System.out.println(obj);
获取私有的成员变量
Class c= Person.class; Field field = c.getDeclaredField("age"); //获取私有的的成员变量 Object obj = c.newInstance(); field.setAccessible(true); //暴力开关 field.set(obj, 11); System.out.println(obj);
练习:有一个AarrayList<String> list,然后往里面添加int类型数据,泛型擦除(字节码文件中没有泛型)
1 ArrayList<String> arr = new ArrayList<String>(); 2 arr.add("abc"); 3 Class c= arr.getClass(); 4 Method addd = c.getMethod("add", Object.class); 5 addd.invoke(arr, 1); 6 for(Object obj:arr){ 7 System.out.println(obj); 8 }
以上是关于java 类加载器反射的主要内容,如果未能解决你的问题,请参考以下文章