JAVA中的反射相关方法使用

本文介绍了Java中的反射机制,包括如何通过class属性、对象的getClass()方法和Class的forName()方法获取class对象。详细讲述了如何处理私有构造方法的反射访问,并列举了获取成员变量的Field方法,如getFields(), getDeclaredFields(), getField(), getDeclaredField()等。同时,还提供了使用反射给对象成员变量赋值的步骤。" 7345494,607125,BIOS内存初始化解析,"['系统初始化', '内存管理', '硬件配置', 'BIOS编程']

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

反射:指在运行时去获取一个类的变量和方法信息,然后通过获取到的信息来创建对象,调用方法的一种机制,由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译器就完成确定,在运行期仍然可以扩展。

简而言之就是:反射通过拿到类的构造方法来创建对象

获取class类的对象:我们要想通过反射去使用一个类,首先我们要获取到该类的字节码文件对象,也就是类型为class类型的对象
三种方法获取class类型的对象:

  1. 使用类的class属性来获取该类对应的class对象,比如:student.class将会返回student类对应的class对象
 //使用类的class属性来获取该类对应的class对象
       Class<Student> c1 = Student.class;
       System.out.print(c1);
       
       Class<Student> c2 = Student.class;
       System.out.print(c1 == c2);
  1. 调用对象的getClass()方法,返回该对象所属类对应的class对象,该方法是object类中的方法,所有的java对象都可以调用该方法
  //调用对象的getClass()方法,返回该对象所属类对应的class对象,该方法是object类中的方法,所有的java对象都可以调用该方法

       Student s =new Student();
       Class<?extends Student > c3 = s.getClass();
       System.out.print(c1 == c3);
  1. 使用class类中的静态方法forName(string classname),该方法需要传入字符串参数,该字符串参数的值是某个类的全路径,也就是完整包名的路径
Class类中用于获取构造方法的方法
1.    Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组
2.   Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组
3.    Constructor<T> getConstructor(Class<?>... parameterTypes) :返回单个公共构造方法对象
4.     Constructor<T> getDeclaredConstructor(类<?>... parameterTypes) :返回单个构造方法对象

 Constructor类中用于创建对象的方法
1. T newInstance():根据指定的构造方法创建对象

小练习:通过反射实现

Student s= new Student("小丁","40","西安");
System.out.print(s);
public static void main(String[] args)throws ClassNotFoundException,NoSuchMethodException,InstantiationException,InvocationTargetException,IllegalAccessException {
		//获取Class对象
        Class<?> c = Class.forName("Student");
        //基本数据类型也可以通过.class得到对应的class类型
        // public Student(String name,int age,String address)
        Constructor<?> con = c.getConstructor(String.class, int.class, String.class);

        Object obj = con.newInstance("zhuohai", 22, "xian");
        System.out.println(obj);
    }

练习2:

Student s= new Student("小丁");
System.out.print(s);
 public static void main(String[] args)throws ClassNotFoundException,NoSuchMethodException,InstantiationException,InvocationTargetException,IllegalAccessException {
        Class<?> c = Class.forName("Student");
        //基本数据类型也可以通过.class得到对应的class类型
          // private Student(String name,int age,String address)
        Constructor<?> con = c.getDeclaredConstructor(String.class, int.class, String.class);

        Object obj = con.newInstance("zhuohai", 22, "xian");
        System.out.println(obj);

    }

我们运行以上代码会发现代码抛以下异常了,这个是怎么回事呢?
私有的构造方法可以拿到,但是我们不可以通过私有的构造方法去构造,

Exception in thread "main" java.lang.IllegalAccessException: Class testcase can not access a member of class Student with modifiers "private"
	at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
	at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
	at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:413)
	at testcase.main(testcase.java:15)

解决方案如下:

public void setAccessible(boolean flag)  throws SecurityException
//将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
//值为 false 则指示反射的对象应该实施 Java 语言访问检查。
//首先,如果存在安全管理器,则在 ReflectPermission("suppressAccessChecks") 权限下调用 checkPermission 方法。
//如果 flag 为 true,并且不能更改此对象的可访问性(例如,如果此元素对象是 Class 类的 Constructor 对象),则会引发 SecurityException。
//如果此对象是 java.lang.Class 类的 Constructor 对象,并且 flag 为 true,则会引发 SecurityException。

我们可使用该方法进行暴力反射

 public static void main(String[] args)throws ClassNotFoundException,NoSuchMethodException,InstantiationException,InvocationTargetException,IllegalAccessException {
        Class<?> c = Class.forName("Student");
        //基本数据类型也可以通过.class得到对应的class类型
          // private Student(String name,int age,String address)
        Constructor<?> con = c.getDeclaredConstructor(String.class, int.class, String.class);

 		 //暴力反射
        //public void setAccessible(boolean flag)//值为true,取消访问检查
        con.setAccessible(true);
        Object obj = con.newInstance("zhuohai", 22, "xian");
        System.out.println(obj);

    }

反射获取成员变量并使用

  1. Field[] getFields()
    //返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
  2. Field[] getDeclaredFields()
    //返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。
  3. // Field getField(String name)
    // 返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
  4. // Field getDeclaredField(String name)
    // 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
  5. // void set(Object obj, Object value)//给obk对象的成员变量赋值为value
    // 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
  public static void main(String[] args)throws ClassNotFoundException,NoSuchMethodException,InstantiationException,InvocationTargetException,IllegalAccessException {
        Class<?> c = Class.forName("Student");

        //Field[]	getFields()
        //返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
        Field[] fields = c.getFields();
        for(Field field:fields){
            System.out.println(field);
        }
        System.out.println("----------------------");
        // Field[]	getDeclaredFields()
        //返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。
        Field[] allfields = c.getDeclaredFields();
        for(Field field:allfields){
            System.out.println(field);
        }
    }

如下图,是我们上段代码的返回结果
在这里插入图片描述
反射获取成员变量并使用的步骤:

  1. 获取class对象c
  2. 通过获取到的class对象c来获取成员变量
  3. 获取无参构造方法创建对象
  4. 给对象的成员变量进行赋值
 public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
        Class<?> c = Class.forName("Student");
        

        // Field getField(String name)
        // 返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
        Field addressfileld = c.getField("address");

        //获取无参构造方法创建对象
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();

        //Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。
        // void	set(Object obj, Object value)
        // 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
        addressfileld.set(obj,"xian");//给obj的成员变量addressfileld赋值为xian
        System.out.println(addressfileld);
        //以上代码主要为了实现下方的代码
        Student s =new Student();
        s.address = "xian";
        System.out.println(s);

    }



下面是全部练习代码

public class Student {
    //私有成员变量
    private String name;
    //默认成员变量
    int age;
    //公共成员变量
    public String address;

    //公共构造方法
    public Student(String name){
        this.name = name;
    }

    public Student(){

    }
    //默认构造方法
    Student(String name,int age){
        this.name = name;
        this.age = age;
    }
    //私有构造方法
    private Student(String name,int age,String address){
        this.name = name;
        this.age = age;
        this.address = address;
    }
    @Override
    public String toString(){
        return "Student{" +"name="+name+","+"age="+age+","+"address="+address+"}";
    }
}
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

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

//反射获取构造方法并使用
public class Test {
   public static void main(String[] args)throws ClassNotFoundException,NoSuchMethodException,InstantiationException,InvocationTargetException,IllegalAccessException{
       //使用类的class属性来获取该类对应的class对象
       Class<Student> c1 = Student.class;
       System.out.print(c1);
       
       Class<Student> c2 = Student.class;
       System.out.print(c1 == c2);

       //调用对象的getClass()方法,返回该对象所属类对应的class对象,该方法是object类中的方法,所有的java对象都可以调用该方法

       Student s =new Student();
       Class<?extends Student > c3 = s.getClass();
       System.out.print(c1 == c3);

       // 使用class类中的静态方法forName(string classname),该方法需要传入字符串参数,该字符串参数的值是某个类的全路径,也就是完整包名的路径
       //<?>为范型
       Class<?> c4 = Class.forName("Student");
        //Constructor<?>[] getConstructors()返回一个包含Constructor对象的数组。Constructor对象反映了由该class对象表示的类的所有公共构造函数
       Constructor<?>[] cons = c4.getConstructors();
       for(Constructor con:cons){
           System.out.println(con);
       }
       //Constructor<?>[] getDeclaredConstructors()返回反映由该Class对象表示的类声明的所有构造函数的Constructor对象的数组。

       Constructor<?>[] cons1 = c4.getDeclaredConstructors();
       for(Constructor con:cons1){
           System.out.println(con);
       }

        //反射通过拿到类的构造方法来创建对象
       //getDeclaredConstructor(类<?>... parameterTypes)
       //返回一个 Constructor对象,该对象反映 Constructor对象表示的类或接口的指定 类函数。
       //	getConstructor(Class<?>... parameterTypes)
       //返回一个Constructor对象,该对象反映由该Class对象表示的类的指定公共构造函数
       //参数:要获取的构造方法的参数的个数和数据类型对应的字节码文件对象

       Constructor<?> con = c4.getConstructor();

       //Constructor提供了一个类的单个构造函数的信息和访问权限
       //public T newInstance()
       //使用由此Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例
       Object obj = con.newInstance();

       System.out.println(obj);

      Constructor<?> cons = c4.getConstructor(0);

   }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值