JAVA的反射机制

JAVA的反射机制

反射是框架设计的灵魂。

1、反射机制

反射是一种功能强大且复杂的机制,射机制可以用来:

  • 在运行中分析类的能力
  • 在运行中查看对象
    • 在运行状态中,对于任意一个类,都能够查看这个类的所有属性和方法
    • 在运行状态中,对于任意一个对象,都能够调用他的任意一个方法和属性
  • 实现通用的数组操作代码,
  • 利用Method对象。

反射的应用场景

1、Spring 实例化对象:当程序启动时,Spring 会读取配置文件applicationContext.xml并解析出里面所有的标签实例化到IOC容器中。
2、反射 + 工厂模式:通过反射消除工厂中的多个分支,如果需要生产新的类,无需关注工厂类,工厂类可以应对各种新增的类,反射可以使得程序更加健壮。
3、JDBC连接数据库:使用JDBC连接数据库时,指定连接数据库的驱动类时用到反射加载驱动类

2、Class类

1.在程序运行期间,java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。

2.这个信息跟踪着每个对象所属的类。

3.可以通过专门的Java类来访问这些信息,就是Class类。

3、如何获得Class类型的实例?

假设有一个学生类

public class Student {
    private String name;
    private int age;
    private List<String> hobby;

    public Student() {
    }

    public Student(String name, int age, List<String> hobby) {
        this.name = name;
        this.age = age;
        this.hobby = hobby;
    }

    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;
    }

    public List<String> getHobby() {
        return hobby;
    }

    public void setHobby(List<String> hobby) {
        this.hobby = hobby;
    }
    
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", hobby=" + hobby +
                '}';
    }
}

三种方法获取学生类的Class对象:

1.所有类都继承Object类,可以调用Object类中的getClass()方法会返回一个Class类型的实例。

​ 最常用的Class方法是getName,这个方法将会返回类的名字。

Student student = new Student();//这里产生了两个对象,一个是Student,一个是Class
Class stuClass = student.getClass();//获取Class对象
System.out.println(stuClass.getName());//输出 reflect.Student。类的全限定名=包名+类名,reflect是包名

2.任何数据类型都有一个静态的class属性,比如int.class (小写)

Class studentClass2 = Student.class;
System.out.println(studentClass2.getName());//输出 reflect.Student

3.还可以调用Class类的静态方法forName()来获取类名对应的Class对象。(常用)

  • 需要传的参数是类的全限定名,否则会出现异常。
  • 需要放在try/catch块中
  • 只有在className是类名或者接口时才能够执行,否则,会抛出一个checked exception(已检测异常)
try {
    String className="reflect.Student";
    Class studentClass3 = Class.forName(className);
    System.out.println(studentClass3.getName());//输出 reflect.Student
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

在运行期间,一个类,只有一个Class对象产生。

可以用==运算符实现两个类对象比较的操作。

System.out.println(studentClass == studentClass2);//true
System.out.println(studentClass2 == studentClass3);//true

4、构造类的实例化对象

可以通过反射来构造一个类的实例。

有两种方法

1、Class对象调用newInstance()方法。

结合forName使用

String className = "reflect.Student";
Class aClass = Class.forName(className);
Student student = (Student) aClass.newInstance();
student.setAge(1);
System.out.println(student.getAge());//输出1

这里没有new关键字,但是也能实例化一个Student。

注意:

newInstance方法调用默认的构造器(无参)来初始化新创建的对象,如果这个类没有默认的构造器(声明了有参的构造器且没有显式声明无参),则会抛出一个异常。

如果需要以这种方式向希望按照名称创建的类的构造器提供参数,则使用下面这种方法。

2、Constructor 构造器调用newInstance()方法

通过显式构造方法构造实例,需要提前从Class中调用getConstructor()方法获取对应的构造器,通过构造器去实例化对象。

List<String> list = new ArrayList<>();
list.add("篮球");		//Student的第三个参数
String className = "reflect.Student";
Class aClass = Class.forName(className);
//通过getConstructor()获取对应的参数的构造器
Constructor<?> constructor = aClass.getConstructor(String.class, int.class, List.class);
constructor.setAccessible(true);
//使用该构造器去实例化对象。
Student  student = (Student) constructor.newInstance("赵东来", 18, list);
System.out.println(student);

/*输出:
Student{name='赵东来', age=18, hobby=[篮球]}
*/

5、获取类的所有信息

在这里插入图片描述

1、获取类中的Field(变量)

  • getField(String name)

    返回一个由 name 指定的该类的 Field 公共成员对象 。

  • getDeclaredField(String name)

    返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。name 参数是一个 String,它指定所需字段的简称。

  • getDeclaredFields()

返回 Field 对象的一个数组。包括公共、保护、默认(包)访问和私有字段,但不包括继承的字段

2、获取类中的Constructor(构造器)

  • getConstructor(Class<?>... parameterTypes)

    返回与指定的 parameterTypes 相匹配的公共构造方法的 Constructor 对象

  • getConstructors()

    返回表示此类公共构造方法的 Constructor 对象数组

  • getDeclaredConstructor(Class<?>... parameterTypes)

    带有指定参数列表的构造方法的 Constructor 对象

  • getDeclaredConstructors()

    表示此类所有已声明的构造方法的 Constructor 对象的数组

3、获取类中的Method(普通方法)

  • getMethod(String name, Class<?>... parameterTypes)

    • 与指定的 name 和 parameterTypes 匹配的 公共成员Method 对象

    • name 参数是一个 String,用于指定所需方法的简称。parameterTypes 参数是按声明顺序标识该方法形参类型的 Class 对象的一个数组。如果 parameterTypes 为 null,则按空数组处理

  • getMethods()

    返回一个包含某些 Method 对象的数组,包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口的公共 member 方法。

  • getDeclaredMethod(String name, Class<?>... parameterTypes)

    返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。

  • getDeclaredMethods()
    返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

package com.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

//获取类运行时的结构
public class Test08 {
    public static void main(String[] args) throws Exception {
        Class c1 = Class.forName("com.reflection.User");

        /******Field*******/
        Field[] fields = c1.getFields();
        System.out.println(fields);  //输出空,因为User里的属性都是private,该方法只能获取到public

        fields = c1.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        /**
         * private java.lang.String com.reflection.User.name
         * private int com.reflection.User.id
         * private int com.reflection.User.age
         */
        //Field field = c1.getField("name");
        //System.out.println(field);//异常:NoSuchFieldException: name

        Field field = c1.getDeclaredField("name");
        System.out.println(field);//private java.lang.String com.reflection.User.name

        /******method*******/

        Method[] methods = c1.getMethods();//获得本类以及父类的public方法
        for (Method method : methods) {
            System.out.println("正常的:"+method);
        }
        /**
         * 正常的:public java.lang.String com.reflection.User.toString()
         * 正常的:public java.lang.String com.reflection.User.getName()
         * 正常的:public int com.reflection.User.getId()
         * 正常的:public void com.reflection.User.setName(java.lang.String)
         * 正常的:public void com.reflection.User.setId(int)
         * 正常的:public int com.reflection.User.getAge()
         * 正常的:public void com.reflection.User.setAge(int)
         * 正常的:public final void java.lang.Object.wait() throws java.lang.InterruptedException
         * 正常的:public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
         * 正常的:public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
         * 正常的:public boolean java.lang.Object.equals(java.lang.Object)
         * 正常的:public native int java.lang.Object.hashCode()
         * 正常的:public final native java.lang.Class java.lang.Object.getClass()
         * 正常的:public final native void java.lang.Object.notify()
         * 正常的:public final native void java.lang.Object.notifyAll()
         */

        methods = c1.getDeclaredMethods();//获得本类所有的方法,方法,包括private
        for (Method method : methods) {
            System.out.println("getDeclaredMethod:"+method);
        }
        /**
         * getDeclaredMethod:public java.lang.String com.reflection.User.toString()
         * getDeclaredMethod:public java.lang.String com.reflection.User.getName()
         * getDeclaredMethod:public int com.reflection.User.getId()
         * getDeclaredMethod:public void com.reflection.User.setName(java.lang.String)
         * getDeclaredMethod:private void com.reflection.User.test()
         * getDeclaredMethod:public void com.reflection.User.setAge(int)
         * getDeclaredMethod:public void com.reflection.User.setId(int)
         * getDeclaredMethod:public int com.reflection.User.getAge()
         */

        //获得指定方法
        //参数可以想象重载,相同方法名是以参数作为区别的
        Method setName = c1.getMethod("setName", String.class);
        Method getName = c1.getMethod("getName", null);
        System.out.println(setName);//public void com.reflection.User.setName(java.lang.String)
        System.out.println(getName);//public java.lang.String com.reflection.User.getName()


        System.out.println("----------------------------------------");
        /****************Constructor*********************/
        //获得构造器
        Constructor[] constructors = c1.getConstructors();//获得public的构造器
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        constructors = c1.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        //获得指定构造器
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        System.out.println("指定:"+constructor);//指定:public com.reflection.User(java.lang.String,int,int)

    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值