反射(reflection),通过反射创建对象
阅读原文时间:2023年07月08日阅读:1

简单尝试:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class animal {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class name = Class.forName("com.zjl.test.reflection.cat");
Object o = name.newInstance();
Method who = name.getMethod("who");
who.invoke(o);
}
}

一、反射机制:

1.反射机制允许程序在执行期借助于Reflection
API取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到
2.加载完类之后,在堆中就产生了一个Class类型
的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为:反射

应用实例:

获取class类的四种方法:

public class GetClass_ {
public static void main(String[] args) throws ClassNotFoundException {

    //1. Class.forName  
    String classAllPath = "com.hspedu.Car"; //通过读取配置文件获取  
    Class<?> cls1 = Class.forName(classAllPath);  
    System.out.println(cls1);

    //2. 类名.class , 应用场景: 用于参数传递  
    Class cls2 = Car.class;  
    System.out.println(cls2);

    //3. 对象.getClass(), 应用场景,有对象实例  
    Car car = new Car();  
    Class cls3 = car.getClass();  
    System.out.println(cls3);

    //4. 通过类加载器【4种】来获取到类的Class对象  
    //(1)先得到类加载器 car  
    ClassLoader classLoader = car.getClass().getClassLoader();  
    //(2)通过类加载器得到Class对象  
    Class cls4 = classLoader.loadClass(classAllPath);  
    System.out.println(cls4);

    //cls1 , cls2 , cls3 , cls4 其实是同一个对象  
    System.out.println(cls1.hashCode());  
    System.out.println(cls2.hashCode());  
    System.out.println(cls3.hashCode());  
    System.out.println(cls4.hashCode());

    //5. 基本数据(int, char,boolean,float,double,byte,long,short) 按如下方式得到Class类对象  
    Class<Integer> integerClass = int.class;  
    Class<Character> characterClass = char.class;  
    Class<Boolean> booleanClass = boolean.class;  
    System.out.println(integerClass);//int

    //6. 基本数据类型对应的包装类,可以通过 .TYPE 得到Class类对象  
    Class<Integer> type1 = Integer.TYPE;  
    Class<Character> type2 = Character.TYPE; //其它包装类BOOLEAN, DOUBLE, LONG,BYTE等待  
    System.out.println(type1);

    //两个类型是相同的:  
    System.out.println(integerClass.hashCode());//?  
    System.out.println(type1.hashCode());//?

}  

}

二、类加载

基本说明:

反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。

1.静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
2动态加载:运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖性

3.举例说明
类加载时机:
1.当创建对象时(new)      //静态加载

2.当子类被加载时,父类也加载           //静态加载
3.调用类中的静态成员时                //静态加载

4.通过反射         //动态加载

类加载:

类加载各阶段完成任务:

加载阶段:

JVM在该阶段的主要目的是将字节码从不同的数据源(可能是 class 文件、也可能是jar包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的
java.lang.Class对象

连接阶段-验证:

连接阶段-准备:

变量的准备简介:

连接阶段-解析:

1.虚拟机将常量池内的符号引用替换为直接引用的过程。

初始化(Initiaalization):

1.到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行
0方法的过程。
2.()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有
静态变量的赋值动作和静态代码块中的语句,并进行合并。
3.虚拟机会保证一个类的()方法在多线程环境中被正确地加锁、同步,如果
多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行()方法完毕[debug源码]

通过反射获取类的结构信息:

java.lang.class类:

1. getName:获取全类名
2. getSimpleName:获取简单类名
3. getFields:获取所有public修饰的属性,包含本类以及父类的

4. getDeclaredFields:获取本类中所有属性
5. getMethods:获取所有public修饰的方法,包含本类以及父类的

6. getDeclaredMethods:获取本类中所有方法
7. getConstructors: 获取所有public修饰的构造器,本类

8. getDeclaredConstructors:获取本类中所有构造器
9. getPackage:以Package形式返回包信息
10.getSuperClass:以Class形式返回父类信息

11.getlnterfaces:以Class[形式返回接口信息
12.getAnnotations:以Annotation[]形式返回注解信息

java.lang.reflect.Field类:

1. getModifiers:以int形式返回修饰符
[说明:默认修饰符是0,public是1,private是2,protected是4,static是8,final是16], public(1) + static (8) = 9
2.getType:以Class形式返回类型
3.getName:返回属性名

java.lang.reflect.Method类:

1.getModifiers:以int形式返回修饰符
[说明:默认修饰符是0,public 是1,private是2,protected是4,static是8,final是16]
2.getReturnType:以Class形式获取返回类型

3.getName:返回方法名
4. getParameterTypes:以Class[返回参数类型数组

java.lang.reflect.Constructor类:

1.getModifiers: 以int形式返回修饰符

2.getName:返回构造器名(全类名)
3.getParameterTypes:以Class[]返回参数类型数组

三、通过反射实现类加载:

访问构造器:

1、方法一:调用类中的public修饰的无参构造器

2、方式二:调用类中指定构造器

3. Class类相关方法
newlnstance:调用类中的无参构造器,获取对应类的对象
getConstructor(Class…clazz):根据参数列表,获取对应的public构造器对象getDecalaredConstructor(Class…clazz):根据参数列表,获取对应的所有构造器对象
4. Constructor类相关方法

setAccessible:暴破
newlnstance(Object…obj):调用构造器

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

public class ReflectCreateInstance {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//1、获取User的class对象
Class aClass = Class.forName("com.zjl.test.reflection.User");
//2、通过public的无参构造器创建实例
Object o = aClass.newInstance();
System.out.println(o);
//3、通过public的有参构造器创建实例
//得到构造器对象
Constructor constructor = aClass.getConstructor(String.class);
//创建实例,并传入参数
Object who = constructor.newInstance("who");
System.out.println(who);
//4.通过非public的有参构造器创建实例
//得到一个private的构造器对象
Constructor declaredConstructor = aClass.getDeclaredConstructor(int.class, String.class);
//对该构造器进行暴破,使得可以通过反射语句访问private的构造器,方法,属性
declaredConstructor.setAccessible(true);
//创建一个private对象的实例并赋值
Object o1 = declaredConstructor.newInstance(20, "Where");
System.out.println(o1);
}
}
class User{
private int age = 10;
private String name = "hello";

public User(){

}

public User(String name) {  
    this.name = name;  
}

 private User(int age, String name) {  
    this.age = age;  
    this.name = name;  
}

@Override  
public String toString() {  
    return "User{" +  
            "age=" + age +  
            ", name='" + name + '\\'' +  
            '}';  
}  

}

访问类中的属性成员:

1.根据属性名获取Field对象
Field f =clazz对象.getDeclaredField(属性名);
2.暴破:f.setAccessible(true);1/f 是Field
3.访问
f.set(o,值);1/ o表示对象

syso(f.get(o))://o表示对象

4.注意:如果是静态属性,则set和get中的参数o,可以写成null

通过反射访问类中的方法成员:

1.根据方法名和参数列表获取Method方法对象:Method m =
clazz.getDeclaredMethod(方法名,XX.class);
2.获取对象:Object o=clazz.newlnstance);
3.暴破:m.setAccessible(true);
4.访问:Object returnValue = m.invoke(o,实参列表);

5.注意:如果是静态方法,则invoke的参数o,可以写成null!