java 类加载器、反射 2019-07-19

 

字节码对象,当我们保存后程序产生的.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 @Override32 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 }

 

Copyright © 2019 hjc黄金城新网站 All Rights Reserved
李高飞
地址:阿拉善盟市中国,内蒙古
全国统一热线:18565524491