反射

反射

1. 概述

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

  • 相关的类

    • Class ***

    • Constructor

    • Method

    • Filed

    • Modifier

2. Class 概述

  • Class 没有公共构造方法。class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

  • 任何的一个类智能对应唯一的一个Class 对象。唯一的大Class 对象,是通过jvm类加载机制实现的。

3. 获得一个类的 Class 对象的三种方式

package com.qf.reflect;
/**
* 反射:reflection
*
* 概念:**JAVA反射机制**是在【运行状态】中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;
* 这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
*
* 实现反射机制最核心的类:一个类的 Class 对象。
* 通过 操作 一个 类的Class 对象,可以访问类中的方法,创建对象等等。
*
* 相关的类:
* java.lang.Class
* 描述类的类。描述类中有什么方法,有什么属性,有什么父类,有什么父接口,有什么构造方法,有什么内部类。等等..
* 通过该类对象,可以知道对应的类的结构。
* java.lang.reflect.Method
* 描述类中的方法的类。修饰符、方法名、参数列表...
* java.lang.reflect.Field.
* 描述类中的属性的类。
* java.lang.reflect.Constructor
* 描述类中的构造方法的类。
* java.lang.reflect.Modifier
* 描述类成员的各种修饰符。
*
* 如何获得一个类的Class对象。
* 三种方式:
* 1:类名.class
* 使用的场景:
* 1:作为对象的监视器使用,同步锁。
* 2:作为方法的实参。
* 3:没有执行类加载的最后一步,类的初始化。
*
* 2:通过 对象.getClass();
* Object 类的 getClass() 返回的是 当前对象对应的类型的Class 对象。
* 使用的场景:
* 1:判断两个对象是否是同种类型。判断对象你的实际类型。
* instanceof 没有该方法准确。
* 2:有执行类加载的最后一步,类的初始化。
*
* 3:使用 Class 类中的静态方法。Class.forName(类的全路径名);
* 1:有执行类加载的最后一步,类的初始化。
*
*
*
*/
public class TestReflect {

public static void main(String[] args)throws Exception {
// 类名.class
Class<A> clazz1 = A.class;

// 通过 对象.getClass();
A a = new A();
Class<? extends A> clazz2 = a.getClass();
//
A a1 = new B();
System.out.println(a1 instanceof A);//true
System.out.println(a1.getClass() == A.class);//false
//
//// 使用 Class 类中的静态方法。Class.forName(类的全路径名);
Class<?> clazz3 = Class.forName("com.qf.reflect.A");

System.out.println(clazz1 == clazz2);//true
System.out.println(clazz2 == clazz3);//true
}

}

class A{

static{
System.out.println("A");
}
private int i;

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + i;
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;

if(obj instanceof A){
A a = (A)obj;
}

if (getClass() != obj.getClass())
return false;
A other = (A) obj;
if (i != other.i)
return false;
return true;
}


}

class B extends A{

}

 

4. 基本数据类型和数组的Class对象

  • Integer.TYPE

  • int[].class

  • void.class

  • package com.qf.reflect;
    /**
    * 非类类型的Class对象介绍:
    * java 中,除了 类类型有对应的Class 对象之外。
    * 基本数据类型   数组,都有对应的Class 对象。
    */
    public class TestOtherClass {

    public static void main(String[] args) {
    // 八种基本数据类型 对应的 Class 对象。 作为方法的实参。
    System.out.println(byte.class);
    System.out.println(short.class);
    System.out.println(int.class);
    System.out.println(long.class);
    System.out.println(float.class);
    System.out.println(double.class);
    System.out.println(boolean.class);
    System.out.println(char.class);

    // 判断一个Class 对象是否是基本数据类型。
    System.out.println(int.class.isPrimitive());//true
    System.out.println(A.class.isPrimitive());//false

    System.out.println(void.class.isPrimitive());//true

    System.out.println(Integer.TYPE == int.class);//true
    System.out.println(Integer.TYPE == Integer.class);//false

    // 了解
    int[] arr = {12,3,4};
    int[] arr1 = {43,45,45,43,32};
    // 同类的数组,维度相同,公用了一个Class 对象。
    System.out.println(arr.getClass() == arr1.getClass());//true
    }

    }
  •  

5. Class 的常用方法

  • getName()

    • 获取类的全路径名称。包名+类名

  • getSimpleName()

    • 获取简单的类的名字。

  • getPackage()

    • 获取类的包的名称。

  • getSuperClass()

    • 返回的时候当前类的直接的父类的 Class 对象。

  • getInterfaces()

    • 获取当前对象的类型的实现的所有的接口。

  • getConstructors();

    • 获取当前对象的类型的所有的构造方法。

  • getConstructor();

    • 获取某一个构造方法。

    • newInstance()

  • getConstructor(...);

    • newInstance(...)

  • getMethods();

    • 获取的是当前对象的类中的所有的共有的方法,包括父类的。

  • getDeclaredMethods();

    • 获取本类中定义的所有的方法,包括私有的。

  • getDeclaredMethod(...)

    • invoke

    • setAccessible(true)

  • getMethod(...)

  • getFields();

    • 获取的是当前对象的类中的所有的共有的属性,包括父类的。

  • getDeclaredFields();

    • 获取本类中定义的所有的属性,包括私有的。

  • getDeclaredField(...);

    • setAccessible

    • set(..)

    • get()

  • package com.qf.reflect;

    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    /**
    * 重点:方法的调用 + 对象的创建。
    *
    */

    public class TestDemo {

    public static void main(String[] args) throws Exception {
    // testMethod();
    // testField();
    testConstructor();
    }

    /**
    * 通过反射的方式去创建对象。
    */
    private static void testConstructor() throws Exception{
    Class<Student> clazz = Student.class;

    // 获取类的构造方法对象。
    // clazz.getConstructors()
    Constructor<Student> constructor = clazz.getDeclaredConstructor(int.class,String.class);

    Student student = constructor.newInstance(100,"jerry");

    System.out.println(student);

    // 不通过 Constructor 去创建一个对象。使用默认无参的构造方法。
    Student student2 = clazz.newInstance();
    System.out.println(student2);

    }

    // 通过反射来访问字段(不建议直接访问属性)
    private static void testField() throws Exception {
    // 获取 Class 对象
    Class<?> clazz = Class.forName("com.qf.reflect.Student");

    Student student = new Student(100, "男");

    // 获取字段
    // clazz.getDeclaredFields()
    Field genderField = clazz.getDeclaredField("gender");
    genderField.setAccessible(true);
    // 获取某个对象的指定字段的值。
    String gender = (String) (genderField.get(student));
    System.out.println(gender);

    // 修改。
    genderField.set(student, "boy");

    System.out.println(student.getGender());

    // 静态属性,get 和 set 方法的第一个参数是 null 即可。
    }

    // 通过反射的方式调用类中的某个方法。
    private static void testMethod() throws Exception {
    // 实例方法的调用。
    // 获取某个类的Class 对象。
    Student student = new Student(100, "男");
    Class<? extends Student> clazz = student.getClass();

    // 获取某个类中的实例方法。 无参的实例方法。
    Method show = clazz.getDeclaredMethod("show");
    // 调用方法。实例方法的第一个参数是,需要传入一个实例对象。
    show.invoke(student);

    // 调用带参数的实例方法。 带一个参数,是从哪列表是对应的形参列表的所有的数据类型的Class对象。
    Method show1 = clazz.getDeclaredMethod("show", int.class);
    show1.invoke(student, 1000);

    // 调用私有的方法。
    Method showScore = clazz.getDeclaredMethod("showScore");
    // 设置跳过访问权限的检查。
    showScore.setAccessible(true);
    showScore.invoke(student);

    // 访问静态方法。
    Method show2 = clazz.getDeclaredMethod("show1");
    // 不依赖于任何对象,第一个参数传入 null 即可。
    show2.invoke(null);

    // 本类 +父类的共有的方法的获取方式。
    // clazz.getMethod(name, parameterTypes)
    }

    // 常用方法
    private static void test1() {
    Class<Student> clazz = Student.class;
    System.out.println(clazz.getName());
    System.out.println(clazz.getSimpleName());

    System.out.println(clazz.getSuperclass().getSuperclass() == Object.class);// true

    System.out.println(clazz.getPackage().getName());
    }

    }

    class Student extends Person {
    public int score;
    private String gender;

    public Student() {
    }

    public Student(int score, String gender) {
    super();
    this.score = score;
    this.gender = gender;
    System.out.println(1);
    }



    @Override
    public String toString() {
    return "Student [score=" + score + ", gender=" + gender + "]";
    }

    public void show() {
    System.out.println("gender = " + gender);
    }

    public void show(int num) {
    System.out.println("num = " + num);
    }

    private void showScore() {
    System.out.println("score = " + score);
    }

    public static void show1() {
    System.out.println("show1");
    }

    public String getGender() {
    return gender;
    }

    }

    class Person {
    public int age;
    private String name;

    private void testPerson() {
    }

    public void testPerson(int i) {
    }
    }
  •  

6 案例

  • 案例1:使用反射给集合添加元素

  • package com.qf.reflect;

    import java.lang.reflect.Method;
    import java.util.ArrayList;

    /**
    * 反射的应用
    *
    */
    public class TestDemo2 {

    public static void main(String[] args) throws Exception {
    test1();
    }

    // 通过泛型,实现跳过编译期的检查,容器中添加元素。
    private static void test1() throws Exception{
    ArrayList<String> list = new ArrayList<>();
    list.add("abc");

    Class<? extends ArrayList> clazz = list.getClass();
    Method addMethod = clazz.getDeclaredMethod("add", Object.class);

    addMethod.invoke(list, true);
    addMethod.invoke(list, new Student());

    System.out.println(list);

    }

    }
  •  

  • 案例2:反射实现开闭原则,读取本地配置文件

  • package com.qf.reflect;

    import java.io.FileInputStream;
    import java.util.Collection;
    import java.util.Iterator;
    import java.util.Properties;

    /**
    * 真正意义上的实现开闭原则。
    * 利用反射实现。
    *
    */
    public class TestDemo3 {

    public static void main(String[] args) throws Exception{
    UsbSocket socket = new Computer();

    Properties prop = new Properties();
    prop.load(new FileInputStream("./res/config.ini"));

    // 就获取到了所有的子类的全路径名。
    Collection<Object> values = prop.values();
    Iterator<Object> iterator = values.iterator();
    while (iterator.hasNext()) {
    String className = (String)iterator.next();
    // System.out.println(className);
    Class<?> clazz = Class.forName(className);
    UsbPlug newInstance = (UsbPlug)clazz.newInstance();
    socket.load(newInstance);
    }
    }
    }

    interface UsbPlug{
    void run();
    }

    interface UsbSocket{
    void load(UsbPlug plug);
    }

    class Computer implements UsbSocket{
    @Override
    public void load(UsbPlug plug) {
    plug.run();
    }
    }

    class Fun implements UsbPlug{
    @Override
    public void run() {
    System.out.println("小风扇开始转动,吹出了凉爽的风。");
    }
    }

    class Light implements UsbPlug{
    @Override
    public void run() {
    System.out.println("usb 小灯照亮了大家学习的脸。。");
    }
    }

    class Disk implements UsbPlug{
    public void run() {
    System.out.println("硬盘开始传输 佳欣喜欢的视频..。");
    }
    }
  •  

  • 案例3:内省:PropertyDescriptor

    • new PropertyDescriptor(.....);

    • getWriteMethod

    • //  自省类。
      private static void test2() throws Exception{
      Stu stu = Stu.class.newInstance();
      // 获取某个类的某个属性的 PropertyDescriptor 的对象。
      PropertyDescriptor ageDescriptor = new PropertyDescriptor("age", Stu.class);

      // 获取操作该属性的 getter 和 setter
      // setter
      Method writeMethod = ageDescriptor.getWriteMethod();
      // getter
      Method readMethod = ageDescriptor.getReadMethod();

      // 调用方法,设置属性值。
      writeMethod.invoke(stu, 100);

      System.out.println(stu);
      }
    •  

7 反射的优缺点

  • 优点

    • 首先,反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力。 其次,通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类。 再次,使用反射机制能够在运行时构造一个类的对象、判断一个类所具有的成员变量和方法、调用一个对象的方法。 最后,反射机制是构建框架技术的基础所在,使用反射可以避免将代码写死在框架中。

  • 缺点:

    • 影响性能、降低代码的可读性。

posted @   ITboy搬砖人  阅读(95)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示