反射

本文详细介绍了Java反射机制,包括获取类字节码文件的三种方式,如何通过反射创建对象,访问私有构造方法,操作成员变量以及调用成员方法。通过案例演示了如何利用反射在ArrayList中添加元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

反射

反射机制:

当一个类被加载进内存后,都会相应的有一个字节码文件(里面有类的信息)对象,我们去剖析这个类的的构成,还能调用该类中的功能,想要通过反射去调用类中的功能和属性,那必须先要得到,该类对应的字节码文件对象(Class)

获取换一个类的字节码文件对象的三种方式:

方式1:

通过Object类中的 getClass();

Student student = new Student();
Class aClass = student.getClass();
方式2:

每个类都有一个class 静态属性

 Class studentClass = Student.class;
方式3:

通过 Class 类中的一个静态方法来获取
static Class<?> forName (String className) 返回与带有给定字符串名的类或接口相关联的 Class 对象。通过一个类的全路径,就可以获取到该类的字节码文件对象
类的全路径: 该类带有包名的写法 例如: org.westos.demo2.Student 一个类全路径的写法

Class<?> aClass3 = Class.forName("org.westos.demo2.Student");
    System.out.println(aClass3== studentClass);
随便建一个学生类
public class Student {
}
测试类
public class MyDemo {
public static void main(String[] args) throws Exception {
    //方式1:通过Object类中的 getClass()
    Student student = new Student();
    Class aClass = student.getClass();
    Class aClass1 = student.getClass();
    System.out.println(aClass);
    System.out.println(aClass==aClass1);

    Student student2 = new Student();
    Class aClass2 = student2.getClass();
    System.out.println(aClass1==aClass2);

    //方式2,每个类都有一个class 静态属性
    Class studentClass = Student.class;
    System.out.println(studentClass==aClass);

    //方式3:通过 Class 类中的一个静态方法来获取
    Class<?> aClass3 = Class.forName("org.westos.demo2.Student");
    System.out.println(aClass3== studentClass);
}
}

类的构成:

成员方法,Method
构造方法 Constructor
成员变量 Field

使用反射剖析一个类

我们要使用反射去剖析一个类,必须先获取到该类所对应的字节码文件对象;
1.获取该类的字节码文件对象

Class clazz = Class.forName("org.westos.demo3.Student");

2.研究构造方法 那我们就得得到构造方法的对象

//A:
    //获取所有构造方法
    //public Constructor<?>[] getConstructors () 获取所有的构造方法不包含私有的
    //public Constructor<?>[] getDeclaredConstructors () 获取所有的构造方法 包括私有的
    //B:
    //获取单个构造方法
    //public Constructor<T> getConstructor (Class < ? >...parameterTypes)获取单个的构造方法 不包含私有的
    //public Constructor<T> getDeclaredConstructor (Class < ? >...parameterTypes)获取单个的构造方法包含私有的
随便建一个学生类
public class Student {
//提供构造方法

public Student() {
    System.out.println("空参构造执行了");
}

public Student(String name) {
    System.out.println("一个参数的构造执行了"+name);
}

private Student(String name, int age) {
    System.out.println("私有的构造方法执行了"+name+"=="+age);
}


}
测试类
public class MyTest {
public static void main(String[] args) throws Exception {
    Constructor[] constructors = clazz.getConstructors(); //获取该类中所有的构造方法对象,但是私有的构造方法获取不到
    for (Constructor constructor : constructors) {
        System.out.println(constructor);
    }
    System.out.println("--------------------");
    //获取该类中所有的构造方法对象,包括私有
    Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
    for (Constructor declaredConstructor : declaredConstructors) {
        System.out.println(declaredConstructor);
    }

    System.out.println("--------------------------------------");
    //获取单个的构造方法对象
    Constructor constructor = clazz.getConstructor(); //获取共有的
    System.out.println(constructor);
    System.out.println("-------------------------");
    //获取单个有参的构造方法对象
    //参数:就是你构造方法中参数类型的Class类型
    Constructor constructor1 = clazz.getConstructor(String.class);
    System.out.println(constructor1);

    System.out.println("-----------------------------");
    //获取私有的构造方法对象
    //Constructor constructor2 = clazz.getConstructor(String.class, int.class);
    //System.out.println(constructor2);
    Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class);
    System.out.println(declaredConstructor);

}
}
用反射创建一个类的对象:
获取空参构造方法对象:

使用newInstance(Object…initargs):

方式一:

Constructor constructor = clazz.getConstructor();
Object obj = constructor.newInstance();

方式二:

Object obj2 = clazz.newInstance();

public static void main(String[] args) throws Exception{
    //通过空参构造创建一个类的对象
    Class clazz= Class.forName("org.westos.demo3.Student");
    //获取空参构造方法对象
    Constructor constructor = clazz.getConstructor();
    Object obj = constructor.newInstance();
    System.out.println(obj);
    System.out.println("--------------------------------");
    //通过空参构造创建一个类的对象 方式2
    Object obj2 = clazz.newInstance();
    System.out.println(obj2);
}
通过反射获取带参构造方法并使用:

使用newInstance(Object…initargs):

 //我们能够获取到了,一个类的构造方法对象,能够什么,就能够创建该类对象
    Class clazz = Class.forName("org.westos.demo3.Student");
    //我们想要通过空参构造创建一个类的对象
    //获取空参构造对象
    Constructor constructor = clazz.getConstructor();
    //创建该类对象
    //newInstance(Object...initargs)
    //使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
    Object obj = constructor.newInstance();
    System.out.println(obj);
    System.out.println("-------------------------------");
过反射获取私有构造方法并使用:

我们以前创建对象的方式是

Student student = new Student();

使用反射来创建:

要点是用:con.setAccessible(true) ; 取消语法检查不然会报错 因为私有的外界不能直接访问;来暴力破解私有

Constructor constructor1 = clazz.getConstructor(String.class);
    Object obj2 = constructor1.newInstance("张三");
    System.out.println(obj2);

    System.out.println("-----------------------------------------------------");

    Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class);
    declaredConstructor.setAccessible(true); //暴利破解 取消语法检测
    Object obj3 = declaredConstructor.newInstance("李四", 24);
    System.out.println(obj3);
通过反射获取成员变量并使用:
A:获取所有成员变量

public Field[] getFields():
获取所有的成员变量包含从父类继承过来的
public Field[] getDeclaredFields() :
获取所有的成员变量 包含私有的 也包含从父类继承过来的成员变量

B:获取单个成员变量

public Field getField(String name)
public Field getDeclaredField(String name)

 public static void main(String[] args) throws Exception{
    //只要使用反射,就先获取该类的字节码文件对象
    Class clazz = Class.forName("org.westos.demo4.Student");
    //获取字段对象
    Field[] fields = clazz.getFields(); //获取所有公共的字段对象
    for (Field field : fields) {
        System.out.println(field);
    }
    System.out.println("-------------------------");
    //获取所有的字段对象,包括私有的
    Field[] declaredFields = clazz.getDeclaredFields();
    for (Field declaredField : declaredFields) {
        System.out.println(declaredField);
    }

    System.out.println("--------------------------------");
    //获取单个的字段对象
    Field age = clazz.getField("age");
    System.out.println(age);
    //获取私有的当个字段对象
    Field sex = clazz.getDeclaredField("sex");
    System.out.println(sex);

}
通过反射给字段设置值:
void set (Object obj, Object value):

将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

  • obj: 表示的就是对象

  • value: 表示的意思就是要具体赋的值
    (俗话:参1,你要给哪个对象设,参数2 就是你给字段设置的具体的值)

     public static void main(String[] args) throws Exception{
      Class clazz = Class.forName("org.westos.demo4.Student");
      //获取成员变量age;
     Field age = clazz.getDeclaredField("age");
     //创建对象
     Object obj = clazz.newInstance();
     //给字段设置值
     age.set(obj,100);
     Student student= (Student) obj;
     System.out.println(student.age);
    
     //通过字段对象获取字段的值
      Object o = age.get(obj);
     System.out.println(o);
    
     //给一个类中的私有字段设置值
     Field sex = clazz.getDeclaredField("sex");
     sex.setAccessible(true);//取消语法检测
     sex.set(obj,'男');
     Object o1 = sex.get(obj);
     System.out.println(o1); 
     }
    
通过反射获取无参无返回值成员方法并使用:
A:获取所有成员方法:

public Method[] getMethods() //获取所有的公共的成员方法不包含私有的 包含从父类继承过来的过来的公共方法
public Method[] getDeclaredMethods()//获取自己的所有成员方法 包含私有的

B:获取单个成员方法:

//参数1: 方法名称 参数2:方法行参的class 对象
public Method getMethod(String name,Class<?>… parameterTypes) //获取单个的方法 不包含私有的
public Method getDeclaredMethod(String name,Class<?>… parameterTypes) 获取单个方法包括私有的

		public static void main(String[] args) throws Exception{
    //先要获取该类的字节码文件对象
    Class clazz = Class.forName("org.westos.demo5.Student");
    //获取给类中的方法对象
    //获取所有的公共方法对象
    Method[] methods = clazz.getMethods(); //获取所有的公共的方法对象,包括父类的
    for (Method method : methods) {
        System.out.println(method.getName());
    }

    System.out.println("-----------------------------------------");
    //获取该类中所有的方法对象,包括私有的,不包含父类方法
    Method[] declaredMethods = clazz.getDeclaredMethods();
    for (Method declaredMethod : declaredMethods) {
        System.out.println(declaredMethod);
    }

    System.out.println("-------------------------------------------");

    //获取单个的公共方法
    //参1 就是你要获取的方法名,参数2,方法中参数类型的,class类型
    Method show = clazz.getMethod("show");
    System.out.println(show);
    //获取有参的方法对象
    Method test = clazz.getMethod("test", String.class);
    System.out.println(test);
    //获取私有的方法对象
    Method myMethod = clazz.getDeclaredMethod("myMethod", String.class, int.class);
    System.out.println(myMethod);

}



public static void main(String[] args) throws Exception {
    //获取字节码文件对象
    Class clazz = Class.forName("org.westos.demo5.Student");
    //以前
    //new Student().show();
    Method show = clazz.getMethod("show");
    //Object invoke (Object obj, Object...args)
    //对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
    Object obj = clazz.newInstance();
    show.invoke(obj);
    System.out.println("--------------------");
    Method show2 = clazz.getMethod("show2");
    Object value = show2.invoke(obj);
    System.out.println(value);

    System.out.println("------------------------------------");
    //调用有参的方法
    Method test = clazz.getMethod("test", String.class);
    test.invoke(obj, "zhangsan");

    //调用私有的方法
    Method myMethod = clazz.getDeclaredMethod("myMethod", String.class, int.class);
    myMethod.setAccessible(true);//取消语法检测
    myMethod.invoke(obj, "wnagwu", 25);
}

学生类

public class Student {

public void show(){
    System.out.println("我是一个无参数的公共方法");
}

public String show2() {
    System.out.println("我是一个无参数的公共方法,有返回值");
    return "一个字符串";
}

public void test(String name) {
    System.out.println("我是一个有参数的公共方法"+name);
}

private void myMethod(String name,int age) {
    System.out.println("我是一个有参数的私有方法" +name+"=="+age);
}
}

案例演示: 我给你ArrayList 的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?

public static void main(String[] args) throws Exception {
    ArrayList<Integer> list = new ArrayList<>();
    list.add(100);
    // list.add("100");
    //泛型:只在编译期有效,运行期就擦除了
    //反射就是运行期间
    Class aClass = list.getClass();
    //获取add()方法的方法对象
    Method add = aClass.getDeclaredMethod("add", Object.class);
    //让add()方法执行
    add.invoke(list, "abc");
    System.out.println(list);

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值