一、Java框架基础反射

一、反射

1.1 Java 反射概述

1.1.1什么是反射

  • Java 反射有以下3个动态特性

    • 运行时创建实例
    • 运行期间调用方法
    • 运行时更改属性
  • 反射机制允许 Java 程序加载一个运行时才得知其名称的类,获悉其完整 API 信息,包括修饰符(诸如 public、static 等)、超类、实现的接口,也包括属性和方法的所有信息;

  • 并可生成其实例、对其属性赋值或调用其方法。

  • 通过 Java 反射可以实现一下功能。

    • 在运行时探知任意一个实例所属的类。
    • 在运行时构造任意一个类的实例。
    • 在运行时探知任意一个类所具有的方法和属性。
    • 在运行时调用任意一个实例的方法。

1.1.2 Java 反射常用API

  • Java 反射技术,常用的类:
    • java.lang.Class类:反射的核心类,反射所有的操作都是围绕该类来生成的。通过 Class 类可以获取类的属性、方法等内容信息。
    • java.lang.reflect.Constructor类:表示类的构造方法。
    • java.lang.reflect.Field 类:表示类的属性,可以获取和设置类中的属性的值。
    • java.lang.reflect.Method 类:表示类的方法,可以用来获取类中方法的信息或执行方法。

1.2 反射的应用

  • Java 程序中使用反射的基本步骤:
    • 导入 java.lang.reflect 包中的相关类。
    • 获得需要操作的类的 Class 实例。
    • 调用 Class 实例的方法获取 Field、Method 等实例。
    • 使用反射 API 操作实例成员。

1.2.1 获取类的信息

  • 一个类或接口被加载后,从系统中都能获得一个代表该类或接口的 Class 类型的实例,通过该实例就可以访问到 Java 虚拟机中的这个类或接口。
  1. 获取 Class 实例

Java 程序中获得 Class 实例通常有三种方式。

  • 调用类或接口实例的 getClass() 方法

    • getClass() 方法是 java.lang.Object 类中的一个方法,所有类和接口的实例都可以调用该方法
    • 该方法会返回该实例的所属类型所对应的 Class 实例。
    Class clz = obj.getClass(); //obj为某个类型的实例
    
  • 调用类或接口的 class 属性。

    • 在某些类或接口没有实例或无法创建实例的情况下,可以通过其 class 属性获取所对应的 Class 实例。
    • 这种方式需要在编译期就知道类或接口的名称。
    Class clz = Student.class;//Student 为自定义的学生类型
    
    • Student.class 将会返回 Student 类对应的 Class 类型的实例。
  • 使用 Class.forName() 方法。

    • 该方法是静态方法,需要传入字符串,字符串参数的值是 类所在的位置
    Class clz = Class.forName("com.mysql.cj.jdbc.Driver")
    
  1. 从 Class 实例获取信息
方法 说明
String getName() 以字符串形式返回该类型的名称
String getSimpleName() 以字符串形式返回该类型的简称
Package getPackage() 获取该类型所在的包
Class getSuperclass() 返回该类型的超类的 Class 实例
Class [] getInterfaces() 返回该类型所实现的全部接口的 Class 实例
int getModifiers() 返回该类型的所有修饰符,由访问修饰符对应的 int 常量组成
Class [] getDeclaredClasses() 返回该类型中包含的全部类的Class 实例
Class getDeclaringClass() 返回该类型所在的外部类的 Class 实例
  • 创建一个基类 BaseClass
public class BaseClass {
}
  • 创建 Person 类继承 BaseClass
public final class Person extends BaseClass implements java.io.Serializable{
    private String name;
    static  final int age=30;
    protected String address;
    public String message;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public Person(String name, String address, String message) {
        this.name = name;
        this.address = address;
        this.message = message;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                ", message='" + message + '\'' +
                '}';
    }

    private void silentMethod() throws IOException,NullPointerException {
        System.out.println("这是悄悄话");
    }
}

  • 创建测试类
public class Test {
    public static void main(String[] args) {
        Class c1= Person.class;
        String fullName=c1.getName();
        String simpleName=c1.getSimpleName();
        System.out.println("以下是"+fullName+"类的基本信息");
        System.out.println("--------------------------------");
        //获取 Person 类所在的包
        Package pkg=c1.getPackage();
        System.out.println(simpleName+"定义在"+pkg.getName()+"包中");
        System.out.println("--------------------------------");
        //获得 c1 所表示的实体(类、接口、基本类型或void)的父类的 Class
        //如果 c1 表示 Object 类、一个接口、一个基本类型或 void,则返回 null
        //如果 c1 表示一个数组类,则返回表示 Object 类的 Class 实例
        Class superClass = c1.getSuperclass();
        System.out.println(simpleName+"类的父类是"+superClass.getName());
        System.out.println("--------------------------------");
        //获得 c1 所表示的类实现的接口
        //如果 c1 表示一个不实现任何接口的类或接口,则此方法返回一个长度为 0 的数组
        //如果 c1 表示一个基本类型或 void,则此方法返回一个长度为 0 的数组
        Class [] interfaces=c1.getInterfaces();
        System.out.println(simpleName+"类所实现的接口:");
        for (Class anInterface : interfaces) {
            System.out.println("\t"+anInterface.getName());
        }
        System.out.println("--------------------------------");
        //每个修饰符对应一个 int 常量,返回的修饰符信息将类所拥有的修饰符以"或"运算组合
        //通过与 Modifier 类中的常量进行"与"运算即可判断该类型是否拥有某个修饰符
        int modifier =c1.getModifiers();

        System.out.println(simpleName+"类的修饰符:");
        if((modifier& Modifier.PUBLIC)==Modifier.PUBLIC){
            System.out.println("\t访问修饰符是:PUBLIC");
        }else{
            System.out.println("\t访问修饰符是:default(package)");
        }
        if((modifier& Modifier.FINAL)==Modifier.FINAL){
            System.out.println("\t这个类是final的");
        }
        if((modifier& Modifier.ABSTRACT)==Modifier.ABSTRACT){
            System.out.println("\t这个类是一个抽象类");
        }
        if((modifier& Modifier.INTERFACE)==Modifier.INTERFACE){
            System.out.println("\t这是一个接口");
        }
    }
}

一、Java框架基础反射_第1张图片

1.2.2 获取构造方法的信息

方法 说明
Constructor getConstructor(Class params) 返回该类型指定参数列表的 public 构造方法,构造方法的参数列表与 params 所指定的类型列表匹配
Constructor [] getConstructors() 返回该类型的所有 public 构造方法
Constructor getDeclaredConstructor(Class oarams) 返回该类型的指定参数列表的构造方法,访问级别不限
Constructor [] getDeclaredConstructors() 返回该类型的所有构造方法 访问级别不限
public class Test {
    public static void main(String[] args) throws NoSuchMethodException {
        Class c1= Person.class;

        //获取 Person 类声明的所有构造方法
        //它们是公共、保护、默认(包)访问和私有构造方法
        //如果此 Class 实例标识一个接口、一个基本类型、一个数组类或 void


        //获取所有用 public 修饰符修饰的构造函数
        Constructor[] constructors1 = c1.getConstructors();

        //获取所有的构造函数 没有修饰符限制
        Constructor[] constructors2 = c1.getDeclaredConstructors();

        //根据给的参数类型 找到相对应的 使用 public 修饰的构造函数
        Constructor constructor3 = c1.getConstructor(String.class);

        //根据给的参数类型找到相对应的构造函数 没有访问修饰符限制
        Constructor constructor4 = c1.getDeclaredConstructor(String.class);

        System.out.println("===============构造方法展示===============");
        for (Constructor constructor : constructors2) {
            System.out.println("访问修饰符:");
            //获取访问修饰符对应的常量
            int modifier=constructor.getModifiers();
            if((modifier& Modifier.PUBLIC)==Modifier.PUBLIC){
                System.out.println("PUBLIC");
            }else if((modifier& Modifier.PRIVATE)==Modifier.PRIVATE){
                System.out.println("PRIVATE");
            }else if((modifier& Modifier.PROTECTED)==Modifier.PROTECTED){
                System.out.println("PROTECTED");
            }else{
                System.out.println("default(package)");
            }
            //获取构造方法的参数列表
            Class [] parameter =constructor.getParameterTypes();
            if(parameter.length==0){
                System.out.println("该构造方法没有参数");
            }else{
                System.out.print("该构造方法的参数有:[");
                for (int i = 0; i < parameter.length; i++) {
                    if(i!=0){
                        System.out.print(", ");
                    }
                    System.out.print(parameter[i].getSimpleName());
                }
                System.out.println("]");
            }
            System.out.println("---------------------------------");
        }
    }
}

一、Java框架基础反射_第2张图片

1.2.3 获取类属性的信息

方法 说明
Field getField(String name) 返回该类型中指定名称的 public 属性
Field [] getFields() 返回该类型中的所有 public 属性
Field getDeclaredField(String name) 返回该类型中指定名称的属性,与属性的访问级别无关
Field getDeclaredFields() 返回该类型中的全部属性,与属性的访问级别无关
public class Test {
    public static void main(String[] args) throws NoSuchFieldException {
        Class c1 = Person.class;

        //获取所有用 public 修饰符修饰的属性
        Field[] field1 = c1.getFields();

        //获取所有的属性 没有修饰符限制
        Field[] field2 = c1.getDeclaredFields();

        //根据给的属性名 找到相对应的 使用 public 修饰的属性
        Field field3 = c1.getField("message");

        //根据给的属性名找到相对应的属性没有访问修饰符限制
        Field field4 = c1.getDeclaredField("name");

        System.out.println("=================属性展示=================");
        for (Field field : field2) {
            System.out.println("属性名:"+field.getName());
            System.out.println("属性类型:"+field.getType());
            int modifier=field.getModifiers();
            if((modifier& Modifier.PUBLIC)==Modifier.PUBLIC){
                System.out.println("PUBLIC");
            }else if((modifier& Modifier.PROTECTED)==Modifier.PROTECTED){
                System.out.println("PROTECTED");
            }else if((modifier& Modifier.PRIVATE)==Modifier.PRIVATE){
                System.out.println("PRIVATE");
            }else{
                System.out.println("default(package)");
            }
            if((modifier& Modifier.FINAL)==Modifier.FINAL){
                System.out.println("这时一个 final 属性");
            }
            if((modifier& Modifier.STATIC)==Modifier.STATIC){
                System.out.println("这时一个静态属性");
            }
            System.out.println("-----------------------------");
        }
    }
}

一、Java框架基础反射_第3张图片

1.2.4 获取该类型所包含的方法的信息

方法 说明
Method getMethod(String name,Class params) 返回该示例中指定的public 方法
Method [] getMethods() 返回该实例中所有的public方法
Method getDeclaredMethod(String name,Class params) 返回该实例中指定的方法,与方法访问级别无关
Method [] getDeclaredMethod() 返回该实例中的全部方法,与方法访问级别无关
package cn.zmt.cn;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Test03 {
    public static void main(String[] args) throws NoSuchMethodException {
        Class c1 = Person.class;

        //获取所有 public 修饰的方法
        Method[] methods1 = c1.getMethods();
        //获取所有的方法 没有访问修饰符限制
        Method[] methods2 = c1.getDeclaredMethods();
        //根据方法名和参数列表 获取到指定的 public 修饰的方法
        Method method3 = c1.getMethod("setName", String.class);
        //根据方法名和参数列表 获取到指定的方法 没有访问修饰符限制
        Method method4 = c1.getDeclaredMethod("setName", String.class);
        System.out.println("======================方法展示======================");
        for (Method method : methods2) {
            System.out.println("方法名:"+method.getName());
            System.out.println("返回值类型:"+method.getReturnType().getSimpleName());
            //获取方法的参数列表
            Class [] params=method.getParameterTypes();
            if(params.length==0){
                System.out.println("该方法没有参数");
            }else{
                System.out.print("该方法的参数列表为:[");
                for (int i = 0; i < params.length; i++) {
                    if(i!=0){
                        System.out.print(",");
                    }
                    System.out.print(params[i].getSimpleName());
                }
                System.out.println("]");
            }
            System.out.print("访问修饰符:");
            //获取访问修饰符对应的常量
            int modifier=method.getModifiers();
            if((modifier& Modifier.PUBLIC)==Modifier.PUBLIC){
                System.out.println("PUBLIC");
            }else if((modifier& Modifier.PRIVATE)==Modifier.PRIVATE){
                System.out.println("PRIVATE");
            }else if((modifier& Modifier.PROTECTED)==Modifier.PROTECTED){
                System.out.println("PROTECTED");
            }

            if((modifier& Modifier.FINAL)==Modifier.FINAL){
                System.out.println("这是一个 final 方法");
            }
            if((modifier& Modifier.STATIC)==Modifier.STATIC){
                System.out.println("这是一个静态方法");
            }
            if((modifier& Modifier.ABSTRACT)==Modifier.ABSTRACT){
                System.out.println("这是一个抽象方法");
            }
            if((modifier& Modifier.SYNCHRONIZED)==Modifier.SYNCHRONIZED){
                System.out.println("这是一个同步方法");
            }
            //获取方法所属的类或接口的 Class 实例
            Class declaringClass=method.getDeclaringClass();
            System.out.println("方法声明在:"+declaringClass.getName());

            Class [] exceptions=method.getExceptionTypes();
            if(exceptions.length==0){
                System.out.println("该方法没有声明异常");
            }else {
                System.out.print("该方法声明的异常有:[");
                for (int i = 0; i < exceptions.length; i++) {
                    if(i!=0){
                        System.out.print(",");
                    }
                    System.out.print(exceptions[i].getSimpleName());
                }
                System.out.println("]");
            }
            System.out.println("--------------------------------");
        }
    }
}

一、Java框架基础反射_第4张图片

  • Class 实例可以获得相关类型中的构造方法、属性、方法等成员信息。
    • 构造方法由 Constructor 类型表示
    • 属性由 Field 类型表示
    • 方法由 Method 类型表示。
  • Constructor、Field、Method 这三个类都定义在 java.lang.reflect 包下。

1.2.5 创建实例

  • 通过反射来创建 Java 类型的实例由两种方式。
    • 使用 Class 实例的 newInstrance() 方法创建相关类型的实例。
    • 使用 Constructor 实例创建相关类型的实例。

使用 newInstance() 方法创建实例

Class c1= Person.class;//加载 Person 类
        Object obj=c1.newInstance();//调用 Person 类的无参构造创建Person 类实例
        System.out.println(obj); //调用 Person 实例的 toString() 方法,属性均为默认值

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 如果创建 Java 实例时,需要使用指定的构造方法,则可以利用 Constructor 实例。
  • 每个 Constructor 实例对应一个构造方法。
  • 指定构造方法来创建 Java 对象的步骤如下:
    • 获取与该类型相关的 Class 实例。
    • 调用 Class 实例的方法获取表示指定构造方法的 Constructor 实例。
    • 调用 Constructor 实例的 newInstance() 方法来创建相关类型的实例。

1.2.6 访问类的构造函数

        //直接调用类的构造函数(有参/无参)
        Class c1= Student.class;
        Object o = c1.newInstance();
        System.out.println(o.toString());

        //通过 Class 实例调用 newInstance() 方法
        Constructor constructor1=Student.class.getConstructor();
        Object o1 = constructor1.newInstance();
        System.out.println(o1);

        //通过反射获取具体构造函数(有参/无参) 调用 newInstance() 方法
        Constructor constructor2=Student.class.getConstructor(String.class,int.class);
        Object o2 = constructor2.newInstance("张小胖",19);
        System.out.println(o2.toString());

        Constructor constructor3=Student.class.getDeclaredConstructor(String.class);
        //用于设置 public 访问修饰符级别外的是否可用
        constructor3.setAccessible(true);
        Object o3 = constructor3.newInstance("赵");
        System.out.println(o3);

1.2.7 访问类的属性

  • 使用 Field 实例可以对属性进行取值或赋值操作。
方法 说明
xxx getXxx(Object obj) xxx表示8中基本数据类型之一
Object get(Object obj) 以 Object 类型返回 obj 中相关的属性的值
void setXxx(Object obj,xxx val) 将 obj 中相关属性的值设置为 val。xxx 为八种基本数据类型之一
void set(Object obj,Object val) 将 obj 中相关属性的值设置为 val
void setAccessible(boolean fiag) 对相关属性设置访问权限。设置为 true 可以禁止 Java 语言访问检查

通过反射方式访问 Person 类的 name 属性,实现取值和赋值

public class Test {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
        //通过反射加载一个 Person 实例
        Class c1= Person.class;
        Object object = c1.newInstance();
        //获取 private String name 属性
        Field name=c1.getDeclaredField("name");
        //name 属性为 private ,这里已超出其访问范围,不能直接访问
        //通过 setAccessable 方法,设定为可以访问
        name.setAccessible(true);

        System.out.println("赋值前 name:"+name.get(object));
        //为name 赋值
        name.set(object,"赵");
        System.out.println("赋值后 name:"+name.get(object));
    }
}

  • setAccessible() 方法: 如果访问级别不是 public 只有给 true 值才能访问到

1.2.8 调用类的方法

  • Method 类中包含一个 invoke() 方法,通过 invoke() 方法,Method 实例可以调用 Java 类的实例方法和静态方法。
Object invoke(Object obj,Object args);
  • obj 是执行该方法的对象,args 是执行该方法时传入的参数。
public class Test {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        Class c1= Person.class;
        //没有参数可以不写或用null 表示
        Method getAge=c1.getDeclaredMethod("getAge",null);
        //getAge 方法为 default(package),这里已超出其访问范围,不能直接访问
        //通过setAccessable 方法,设定为可以访问
        getAge.setAccessible(true);
        //调用 getAge 方法并传参,没有参数可以不写或用 null 表示
        //getAge 方法为静态方法,调用时可以不指定具体 Person 实例
        Object returnAge = getAge.invoke(null, null);
        System.out.println("年龄是:"+returnAge);

        //创建 Person 实例
        Object person=c1.newInstance();

        Method silentMethod=c1.getDeclaredMethod("silentMethod",null);
        //通过 setAccessable 方法,设定可以访问
        silentMethod.setAccessible(true);
        //调用 silentMethod 方法并传参,没有参数可以不写或用null表示
        silentMethod.invoke(person,null);

        //根据方法名和参数列表获取 public void setName(String)方法
        Method setName=c1.getDeclaredMethod("setName", String.class);
        //setName 方法为 public 可以直接访问
        //调用 setName 方法并传参
        setName.invoke(person,"赵");
        //验证
        Object returnName=c1.getDeclaredMethod("getName",null).invoke(person);
        System.out.println("name是:"+returnName);
    }
}
   //通过 setAccessable 方法,设定可以访问
    silentMethod.setAccessible(true);
    //调用 silentMethod 方法并传参,没有参数可以不写或用null表示
    silentMethod.invoke(person,null);

    //根据方法名和参数列表获取 public void setName(String)方法
    Method setName=c1.getDeclaredMethod("setName", String.class);
    //setName 方法为 public 可以直接访问
    //调用 setName 方法并传参
    setName.invoke(person,"赵");
    //验证
    Object returnName=c1.getDeclaredMethod("getName",null).invoke(person);
    System.out.println("name是:"+returnName);
}

}


你可能感兴趣的:(python,开发语言,java)