反射

反射

反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息(属性,构造器,方法),并能操作的属性和方法,反射在设计模式和框架都会用到。

反射机制可以完成:

  1. 判断任意一个对象所属的类
  2. 在运行时构造任意一个对象
  3. 在运行时得到任意一个对象的成员变量和方法
  4. 在运行时调用任意一个对象的成员变量和方法
  5. 生成动态代理

反射有关的类:

  1. java.lang.Class,代表一个类,Class对象表示某个类加载后在堆中的对象
  2. java.lang.reflect.Method 代表类的方法
  3. java.lang.reflect.Field 代表类的成员属性
  4. java.lang.reflect.Constructor 代表类的构造方法
public class Cat {
    private String name;
    public int age = 10;

    public Cat(){

    }
    public Cat(String name,int age){
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

//反射的简单使用
Class clazz = Class.forName("reflect.Cat");
//获取类的方法
Method method = clazz.getMethod("getAge");
//获取类的属性
Field age = clazz.getField("age");
//获取类的构造器
Constructor constructor = clazz.getConstructor();
//构建一个对象
Object o = constructor.newInstance();
System.out.println(o.getClass());
System.out.println(clazz + " " + method + " " + age);
//运行方法
System.out.println(method.invoke(o));

反射机制的优点和缺点

优点:可以动态的创建和使用对象,使用灵活,没有反射机制,框架就失去了底层支持

缺点:使用反射机制,基本上是解释执行,对执行速度有影响

优化

关闭访问检查,Method,Field,Constructor都有setAccessible()方法,主要用于访问安全检查的开关,设置为true可以关闭检查。

Class

  1. Class也是类,因此也继承Object类

  2. Class对象不是new出来的,而是由系统创建出来的,是由类加载创建在堆中

    Class clazz = Class.forName("reflect.Cat");
    
  3. 对于每个Class对象在堆内存中只会有一份,因为类只会加载一次

  4. 每个类的实例都会记住自己是由哪个Class实例生成的

  5. 通过一个Class可以得到一个类的完整结构,通过一系列的API

  6. Class对象存放在堆中

  7. 类的字节码二进制数据,是放在方法区,有的地方称为类的元数据

Class常用方法

Class clazz = Class.forName("reflect.Car");
//显示该类是哪个类的对象
System.out.println(clazz);
//显示该类的名字,全类名
System.out.println(clazz.getName());
//显示类的包名
System.out.println(clazz.getPackage().getName());
//显示该类的运行类型
System.out.println(clazz.getClass());
//创建该类对象
Object o = clazz.newInstance();
System.out.println(o);
//获取对象属性
Field brand = clazz.getField("brand");
System.out.println(brand.get(o));//输出属性的值
//重新给属性设置值
brand.set(o,"奔驰");
System.out.println(brand.get(o));
//获取多个属性
Field[] fields = clazz.getFields();
for(Field e : fields){
    //获取每个属性的名字
    System.out.println(e.getName());
}
/*
class reflect.Car
reflect.Car
reflect
class java.lang.Class
Car{brand='宝马', price=500000, color='白色'}
宝马
奔驰
brand
price
color
*/

获取Class对象方法

//第一种通过Class.forName,主要在编译阶段
Class clazz1 = Class.forName("reflect.Car");
System.out.println(clazz1);

//第二种通过类。class获取
Class clazz2 = Car.class;
System.out.println(clazz2);

//第三种通过对象实例.getClass()获取
Car car = new Car();
Class clazz3 = car.getClass();
System.out.println(clazz3);
//通过类加载器获取
ClassLoader classLoader = car.getClass().getClassLoader();
Class clazz4 = classLoader.loadClass("reflect.Car");
System.out.println(clazz4);

//基本数据类型通过.class获取
Class clazz5 = int.class;
System.out.println(clazz5);

//基本类型的包装类通过类名.TYPE获取
Class clazz6 = Integer.TYPE;
System.out.println(clazz6);

类加载

反射机制是Java实现动态语言的关键,也就是通过反射实现类的动态加载
静态加载:编译的时候加载相关的类,如果没有则报错,依赖性很强
动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,也不会报错

类的加载时机:

  1. 使用new创建对象的时候
  2. 创建子类对象,父类也会被加载
  3. 使用类的静态属性
  4. 通过反射

Class常用方法

//Class类中常用方法
Class clazz = Class.forName("reflect.Person");
//获取类的全类名
System.out.println(clazz.getName());
//获取类的名字
System.out.println(clazz.getSimpleName());
//返回包名
System.out.println(clazz.getPackage());
//返回父类类信息
Class superClass = clazz.getSuperclass();
System.out.println(superClass);
//返回所有public属性包括父类的
Field[] fields = clazz.getFields();
for (Field field : fields) {
    System.out.println(field.getName());
}
//返回所有本类所有属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
    System.out.println(declaredField.getName());
}
//返回所有public方法,包括父类的
Method[] methods = clazz.getMethods();
for (Method method : methods) {
    System.out.println(method.getName());
}
//返回本类所有的方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
    System.out.println(declaredMethod.getName());
}
//返回所有public构造器
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
    System.out.println(constructor.getName());
}
//返回所有的构造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
    System.out.println(declaredConstructor.getName());
}

//返回所有接口
Class[] interfaces = clazz.getInterfaces();
for (Class anInterface : interfaces) {
    System.out.println(anInterface);
}

//返回所有注解
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
    System.out.println(annotation);
}

//返回所有本类所有属性
Class clazz = Class.forName("reflect.Person");
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
    System.out.println("该类的属性:" + declaredField.getName() +
                       "该属性的属性权限: " + declaredField.getModifiers() + "该属性的类型: " +
                       declaredField.getType());

}

//返回本类所有的方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
    System.out.println("该方法的名字:" + declaredMethod.getName() + "该方法的修饰符:" +
                       declaredMethod.getModifiers() + "该方法的返回值类型: " + declaredMethod.getReturnType());
    Class[] parameterTypes = declaredMethod.getParameterTypes();
    for (Class parameterType : parameterTypes) {
        System.out.println("该方法的参数类型: " + parameterType.getTypeName());
    }
}

创建对象

Class clazz = Class.forName("reflect.User");
//通过默认无参构造函数构建对象
Object o = clazz.newInstance();
System.out.println(o);
//通过公共有参构造函数构造对象
Constructor constructor = clazz.getConstructor(String.class);
Object o1 = constructor.newInstance("张三");
System.out.println(o1);

//通过公共有参构造函数构造对象
Constructor constructor1 = clazz.getConstructor(String.class, int.class);
Object o2 = constructor1.newInstance("李四", 20);
System.out.println(o2);
//通过私有构造函数构造对象
Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class, String.class);
declaredConstructor.setAccessible(true);
Object o3 = declaredConstructor.newInstance("王五", 30, "男");
System.out.println(o3);

访问属性

Class clazz = Class.forName("reflect.User");
Object o = clazz.newInstance();
//访问公有属性
Field name = clazz.getField("name");
name.set(o,"张三");
System.out.println(o);

//访问私有属性
Field salary = clazz.getDeclaredField("salary");
salary.setAccessible(true);
salary.set(o,2345.67);
System.out.println(o);
//访问静态属性
Field test = clazz.getDeclaredField("test");
test.setAccessible(true);
test.set(null,"获取");
System.out.println(test.get(null));

访问方法

Class clazz = Class.forName("reflect.User");
Object o = clazz.newInstance();
//访问公共方法
Method m1 = clazz.getMethod("m1");
m1.invoke(o);
//有参数的方法
Method m2 = clazz.getMethod("m2", String.class);
m2.invoke(o,"张三");

//私有有返回值的方法
Method m3 = clazz.getDeclaredMethod("m3");
m3.setAccessible(true);
Object invoke = m3.invoke(o);
System.out.println("返回值: " + invoke);
posted @ 2021-10-07 21:44  无涯子wyz  阅读(36)  评论(0)    收藏  举报