反射的概念

本文详细介绍了Java反射机制,包括反射的概念、获取Class对象、通过反射创建对象以及获取类的其他结构如接口、父类、属性和方法。通过实例展示了如何利用反射进行动态操作,如调用私有方法和修改私有属性。反射机制使得Java具有一定的动态性,常用于框架和中间件开发。
摘要由CSDN通过智能技术生成

Java知识点总结:想看的可以从这里进入

11、反射


11.1、反射的概念

Java在编译过程中是把 Java 代码编成 class 文件。编译期做了一些翻译功能,并没有把代码放在内存中运行起来,运行期是把编译后的文件交给计算机执行,直到程序运行结束。

而Java 反射机制 (Reflection) 就是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制。也就是说反射机制指的是程序在运行时能够获取自身的信息。在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。(我们所写类中的属性和方法都有对应的类来描述,反射就是获取这些组成类的不同成分的对象)

  1. 动态语言:在运行时代码可以根据某些条件改变自身结构。如:JavaScript、Python

  2. 静态语言:运行时结构不可变的语言就是静态语言。如:C、C++

    Java因为反射机制的存在,使它有一定的动态性,所以算是半个动态语言

反射同样是很多框架设计和中间件程序中得到了广泛运用。

java.lang.Class 类是实现反射的关键所在,Class 类的一个实例表示 Java 的一种数据类型,包括类、接口、枚举、注解、数组、基本数据类型和 void。Class 没有公有的构造方法,是由 JVM 在类加载时自动创建的。

在知道类全限定名的情况下,使用Class 的静态方法forName(String)创建某个类的运行时对象。

反射中常用的类有:
Constructor 类:提供类的构造方法信息。
Field 类:提供类或接口中成员变量信息。
Method 类:提供类或接口成员方法信息。
Array 类:提供了动态创建和访问 Java 数组的方法。
Modifier 类:提供类和成员访问修饰符信息。
Class类:代表一个类,获取对象

11.2、获取Class类

我们知道Object 是所有类的直接 或间接的父类,那内部定义了一个方法 getClass(),它返回就是一个Class,而Class可以用来描述所有的类,这就是反射机制的根源。

JVM在加载类时,会为类生成一个Class类型的对象,这个对象包含了该类的所有结构及其相关的信息,所以可以通过Class完整地得到一个类中的所有被加载的结构

image-20230219131328427

class(外部类,内部类)、接口、数组、枚举、注解@interface等都可以获取Class对象。

获取Class对象的几种方式
1、在知道类的情况下,通过类的class
2、在知道类的实例时,通过getClass()方法
3、知道类的全路径时,通过Class.forName("路径+类名") 
try {
    Class c1 = Class.forName("JavaSE.serialization.Student");
    System.out.println("类全限定名:"+c1.getName());
    System.out.println("类名"+c1.getSimpleName());

    Class c2 = String.class;
    System.out.println("类全限定名:"+c2.getName());
    System.out.println("类名"+c2.getSimpleName());

    Persion persion = new Persion();
    Class c3 = persion.getClass();
    System.out.println("类全限定名:"+c3.getName());
    System.out.println("类名"+c3.getSimpleName());
} catch (ClassNotFoundException e) {
    throw new RuntimeException(e);
}

image-20230219150911763

11.3、反射创建对象

Class类中提供了一个方法 newInstance() ,这个方法可用用来创建对象,类最好要有一个无参构造,因为对象的创建需要明确构造方法,如果没有无参构造,还必须先获取构造器,知道参数类型后,才能明确怎么创建对象。

  1. 创建一个类

    interface ReflectionTestInterface{
    }
    abstract class ReflectionTestAbstract{
    }
    public class Persion implements ReflectionTest{
        private String name;
        private int age;
        public int height;
    	//public修饰的含参构造
        public Persion(String name, int age, int height) {
            this.name = name;
            this.age = age;
            this.height = height;
        }
    	//public修饰的含参构造
        public Persion(String name, int age) {
            this.name = name;
            this.age = age;
        }
    	//private修饰的含参构造
        private Persion(String name) {
            this.name = name;
        }
    	//无参构造
        public Persion() {
        }
    	//私有方法
        private void hidden(){
            System.out.println("私有方法");
        }
        //public方法
        public int getHeight() {
            return height;
        }
        public void setHeight(int height) {
            this.height = height;
        }
        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;
        }
    }
    
  2. 通过反射获取构造方法

    • getConstructors():获取public修饰的构造方法

      try {
          System.out.println("===获取public修饰的构造方法===");
          Constructor[] constructors = clazz.getConstructors();
          for(Constructor c : constructors){
              System.out.println(c);
          }
      } catch (Exception e) {
      	e.printStackTrace();
      }
      
      image-20230219175238250
    • getDeclaredConstructors():所有的构造方法(含private修饰的)

      try {
          System.out.println("===所有的构造方法(含private修饰的)===");
          Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
          for(Constructor c : declaredConstructors){
              System.out.println(c);
           }
      } catch (Exception e) {
      	e.printStackTrace();
      }
      
      image-20230219175400427
    • getConstructor(null):获取无参构造

      try {
          System.out.println("===获取无参构造方法===");
          Constructor constructor = clazz.getConstructor(null);
          System.out.println(constructor);
      } catch (Exception e) {
      	e.printStackTrace();
      }
      

      image-20230219175547445

    • 根据参数类型获取构造方法

      //获取有一个参数为String的构造方法。
      System.out.println("===根据参数类型获取构造方法===");
      Constructor declaredConstructor = null;
      try {
          System.out.println("===含有一个String参数的构造方法===");
          declaredConstructor = clazz.getDeclaredConstructor(String.class);
          System.out.println(declaredConstructor);
      } catch (Exception e) {
          e.printStackTrace();
      }
      

      image-20230219180204623

  3. 根据构造方法创建对象

    try {
        System.out.println("===调用构造方法创建对象===");
        System.out.println("===使用无参的构造创建对象===");
        Constructor constructor = clazz.getConstructor(null);
        Persion persion = (Persion) constructor.newInstance();
        System.out.println(persion);
    
        System.out.println("===根据参数类型获取构造方法并创建对象===");
        Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class);
        System.out.println("参数为String类型的构造方法:"+declaredConstructor);
        //获取权限,可直接调用private修饰的方法
        declaredConstructor.setAccessible(true);
        //创建对象
        Persion p = (Persion)declaredConstructor.newInstance("张三");
        System.out.println(p.getName());
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    image-20230219180757771

11.4、获取类其他结构

11.4.1、获取接口

通过反射获取类实现的接口的Class对象

System.out.println("===获取实现的接口===");
Class[] interfaces = clazz.getInterfaces();
for (Class c:interfaces){
	System.out.println(c);
}

image-20230219181342282

11.4.2、获取父类

通过反射获取类继承的父类的Class对象

System.out.println("===获取继承的父类===");
Class superclass = clazz.getSuperclass();
System.out.println(superclass);

image-20230219181526221

11.4.3、获取属性

通过反射获取属性

  1. clazz.getFields():获取非private修饰的属性

    System.out.println("===获取public的属性===");
    Field[] fields = clazz.getFields();
    for(Field f :fields){
        System.out.println(f);
    }
    

    image-20230219184520362

  2. clazz.getDeclaredFields():获取所有的属性

    System.out.println("===获取所有的属性===");
    Field[] declaredFields = clazz.getDeclaredFields();
    for(Field f : declaredFields){
        System.out.println(f);
    }
    

    image-20230219184530336

  3. 获取指定属性,并修改、获取值

    System.out.println("===获取指定属性,并修改、获取值===");
    try {
        Field f = clazz.getDeclaredField("name");   //("属性名")
        System.out.println(f);
        
        f.setAccessible(true); //可以获取private的使用权限
        Object o = clazz.getConstructor().newInstance();	//反射创建对象
        f.set(o ,"张三"); //反射修改值
        System.out.println( f.get(o));  //反射获取值
    } catch (Exception e) {
        e.printStackTrace();
    }
    

    image-20230219184549913

  4. 获取属性的权限、类型、名字

    System.out.println("===获取属性的权限、类型、名字===");
    for(Field f : declaredFields){
        System.out.print(Modifier.toString(f.getModifiers())+" ");  //权限
        System.out.print(f.getType().getSimpleName()+" ");            //类型
        System.out.print(f.getName());                            //名字
        System.out.println(";");
    }
    
    image-20230219184556497
  5. 修改、获取属性值

    System.out.println("===修改、获取属性值===");
    try {
        Field f = clazz.getDeclaredField("age");   //("属性名")
        f.setAccessible(true); //可以获取private的使用权限
    
        Persion p = (Persion)clazz.getConstructor().newInstance();
        f.set(p ,18);//修改值
        System.out.println( f.get(p));  //获取值
    
    } catch (Exception e) {
        e.printStackTrace();
    }
    

    image-20230219184645178

11.4.4、获取方法

通过反射获取方法

  1. 获取所有public方法,包括父类继承的

    System.out.println("===获取所有public方法,包括父类继承的===");
    Method[] methods = clazz.getMethods();
    for(Method m : methods){
        System.out.println(m);
    }
    
    image-20230219184815703
  2. 获取自定义的所有方法

    System.out.println("===获取自定义的所有方法===");
    Method[] declaredMethods = clazz.getDeclaredMethods();
    for(Method m : declaredMethods){
        System.out.println(m);
    }
    
    image-20230219184837453
  3. 获取方法的权限修饰符、返回值、方法名、参数类型

    System.out.println("===获取方法的权限修饰符、返回值、方法名、参数类型===");
    for(Method m : declaredMethods){
        System.out.print(Modifier.toString(m.getModifiers())+" ");  //权限修饰符
        System.out.print(m.getReturnType().getSimpleName()+" ");    //返回值
        System.out.print(m.getName());                              //方法名
        Parameter[] parameters = m.getParameters();         //参数类型数组,需遍历
        System.out.print("(");
        for(Parameter p : parameters){
            System.out.print(p.getType().getSimpleName()+",");
        }
        System.out.println(");");
    }
    

    image-20230219184851909

  4. 获取指定方法并调用

    System.out.println("===获取指定方法并调用===");
    try {
        //获取名为getName的方法,无参数传递
        Method getName = clazz.getMethod("getName", null);
        System.out.println(getName);
        getName.setAccessible(true); //可以获取private的使用权限
        //获取名为setName的方法,传递的参数类型为String
        Method setName = clazz.getMethod("setName", String.class);
        System.out.println(setName);
        setName.setAccessible(true); //可以获取private的使用权限
        //创建一个对象
        Object o = clazz.getConstructor().newInstance();
        //反射调用setName方法
        setName.invoke(o,"张三");
        //反射调用getName方法
        System.out.println(getName.invoke(o));
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    image-20230219184906664
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

辰 羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值