黑马程序员——反射和类的加载

时间:2023-02-18 20:29:25

——- android培训java培训、期待与您交流! ———-

类的加载

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

加载

就是指将class文件读入内存,并为之创建一个Class对象。
任何类被使用时系统都会建立一个Class对象。

连接

验证 是否有正确的内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值
解析 将类的二进制数据中的符号引用替换为直接引用

初始化

就是初始化步骤

三种类的加载器 ClassLorder

Bootstrap ClassLoader 根类加载器,加载JAVA中的核心类库 JDK\JR7\Lib

Extension ClassLoader 扩展类加载器,加载java扩展类库 JDK\JR7\Lib\ext

System ClassLoader 系统类加载器, 加载我们写的类 java 命令 后类名

加载器只要将class文件,放入内存后,就会有一个对象产生,对象是JVM自动创建的字节码文件对象。

反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

java.lang.Class 类,描述运行时期一个class文件的对象
Class 找获取class文件对象中成员的方法

构造方法,也会被看成一个对象,就有这个对象描述类,用于操作构造方法
java.lang.reflect.Constructor 提供方法操作构造方法

成员变量,也会被看成一个对象,就有这个对象描述类,用于操作成员变量
java.lang.reflect.Field 提供方法操作造变量

成员方法,也会被看成一个对象,有这个对象描述类,用于操作成员方法
java.lang.reflect.Method 提供方法操作成员方法

反射:
获取一个类的class文件对象 Class类型使用Class类中的方法解剖这个class文件。 获取出class文件中定义的所有成员,交给不同的对象,进行处理

获取一个类的字节码文件对象
三种方式
第一种使用 对象获取
使用对象的方法 getClass获取

//创建Person对象
Person p = new Person();
//调用 Object类的方法getClass()获取字节码文件对象
Class c = p.getClass();

第二种,使用类的静态属性class获取
每一个类都有一个静态属性 class 获取类的字节码文件对象

//直接使用类名.class获取
Class c1 = Person.class;

第三种,使用Class类的静态方法forName(字符串的类名)
类名,要写全类名 包名.类名

//Class类的静态方法forName
Class c2 = Class.forName("cn.itcast.reflect.Person");

Class类

提供一些获取方法,从一个类的class文件中获取构造方法
1. 获取 所有的公共权限构造方法
Constructor[] getConstructors() 返回构造方法对象
Constructor getConstructor(Class…c) 返回指定的构造方法

Constructor 类中有一个方法,可以运行可以到的构造方法
Object newInstance(Object…obj)
运行获取到的指定构造方法,但是传递相对应参数

Class clazz = Class.forName("cn.itcast.reflect.Person");
// 调用Class方法 getConstructors 获取公共构造器,返回一个Constructor
Constructor[] cons = clazz.getConstructors();
for(Constructor c :cons){
System.out.println(c);
}
// 获取空参数构造方法
Constructor con = clazz.getConstructor();
// Constructor类的方法newInstance(Object...obj)运行获取到的构造器
Object o = con.newInstance();

获取成员变量
Class类提供获取方法,从一个类的class文件中获取成员变量
Field[] getFields()
Field getField(字符串的变量名) 获取指定变量

Field类方法
void set(Object obj, Object value) 修改成员变量值

Class clazz = Class.forName("cn.itcast.reflect.Person");
//使用Class类的方法getFields()类中的所有公共权限成员变量
Field[] field = clazz.getFields();
for(Field f : field){
System.out.println(f);
}
//指定公共权限成员变量
Object obj = clazz.newInstance();
Field field = clazz.getField("name");
//调用field类方法 set修改值
field.set(obj, "李四");
System.out.println(obj);

获取成员方法
Class类提供获取方法,从一个类的class文件中获取成员方法
自己的,继承,实现的 public权限

Method[] getMethods()获取全部公共方法,包括继承的
Method getMethod(字符串方法名,Class…c)获取指定的方法

Method类方法
invoke(Object obj, Object…o)运行获取到的方法
对象,调用方法中实际传递的参数

Class clazz = Class.forName("cn.itcast.reflect.Person");

//使用class类的方法 getMethods() 成员方法
Method[] methods = clazz.getMethods();
for(Method m : methods){
System.out.println(m);
}

//获取show方法,Class类的方法getMethod()
Method method = clazz.getMethod("show");
//运行show方法 空参数的 使用Method类的方法 invoke
Object obj = clazz.newInstance();
method.invoke(obj);

//d获取show方法,带参 int double String
Method method = clazz.getMethod("show",int.class,double.class,String.class);
method.invoke(obj, 12,34.56,"QQ");

反射通过配置文件运行

配置文件 写运行类,运行的方法
读取配置文件,获取键值对
类名,和方法名,交给反射运行
配置文件一般使用XML

public class ReflectTest {
public static void main(String[] args)throws Exception {
//创建集合对象
Properties pro = new Properties();
//创建IO流的,读取配置文件
FileInputStream fis = new FileInputStream("c:\\config.txt");
//集合方法load 读取到的键值对,存储到集合
pro.load(fis);
fis.close();

String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");

//获取指定类的class文件对象
Class clazz = Class.forName(className);
Object o = clazz.newInstance();
//通过字节码文件对象Class类,获取指定方法
Method m = clazz.getMethod(methodName);
//运行方法
m.invoke(o);
}
}

反射泛型的擦除

集合 泛型是Integer 集合存储 String
泛型,伪泛型,编译后的class文件中,没有泛型
ArrayList.class 反射 玩的就是class , 泛型擦除,反射绕过编译器检查

public class ReflectTest1 {
public static void main(String[] args)throws Exception {
ArrayList<Integer> array = new ArrayList<Integer>();
array.add(123);
//.array.add("a");
//获取ArrayList类的class文件对象
Class clazz = array.getClass();
//通过字节码文件对象Class方法getMethod获取集合方法add
Method method = clazz.getMethod("add", Object.class);
method.invoke(array, "QQQ");

}

反射修改不知道的变量名

public void setProperty
(Object obj, String propertyName, Object value){},
此方法可将obj对象中名为propertyName的属性的值设置为value。

public class ReflectTest2 {
public static void main(String[] args) throws Exception{
Person p = new Person();

new ReflectTest2().setProperty(p, "age", 26);
}
//传递一个类的对象,一个类的成员变量名,值
public void setProperty (Object obj, String propertyName, Object value)throws Exception{
//对象传递了,获取class文件对象
Class clazz = obj.getClass();
System.out.println(clazz);
//获取对象中成员变量
Field field = clazz.getField(propertyName);
System.out.println(field);
field.set(obj, value);
System.out.println(obj);
}
}