java基础(十六):反射

2021/12/15 17:17:32

本文主要是介绍java基础(十六):反射,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

反射

运行程序:

  • 编译:将.java文件编译生成对应的.class文件(字节码文件)

  • 运行:基于字节码文件调用操作系统的资源执行程序

类加载:

  • 将字节码文件从硬盘加载到内存中(静态常量池)

面向对象:

  • 万物皆对象

  • 类 — 属性:特征 方法:行为

  • 定义类:class 类名

Class类

  • 当前类的字节码文件的对象类 — 表示类的类

  • 类中包含的内容:

    • 构造方法 (Constructor)、属性 (Field)、方法 (Method)、注解 , 如:@overwrite (Annotation)

可变参数

  • 在方法的参数列表中,可以通过定义可变参数从而实现方法的参数个数由调用者确定;

  • 格式:数据类型 … 名称

注意

  1. 方法参数列表中只能定义一个可变参数

  2. 方法参数列表中可以同时定义单个参数和可变参数,但是可变参数必须放到参数列表的最后

public class ChangeDemo {
    public static void main(String[] args) {
        System.out.println(add(3,5));
        int[] arr = new int[]{3,1,5,7,6};
        System.out.println(add(arr));

    }

    public static int add(int ... arr){
        // 以数组的形式传入
        int sum = 0;
        for (int i : arr){
            sum += i;
        }
        return sum;
    }
}

优点:

  1. 简化了代码,提高了代码的复用性;

  2. 提高了代码的灵活性;

反射概念

  • 无需通过new就能创建当前正在运行的类或者接口实现类的对象

  • 获取类的Class

    • 类. class — > 返回Class类型的对象

      Class clz = String.class;
      System.out.println(clz);  // class java.lang.String
      Class clz1 = int.class;
      System.out.println(clz1);  // int
      

      类名.class调用类的class属性可以获取到该类的Class对象

    • 对象.getClass()方法获取该对象对应的类的Class对象

      String ss = new String();
      System.out.println(ss.getClass());  // class java.lang.String
      

      前提是有当前类的对象

    • 根据类名获取该类对应的Class对象

      Class.forName(全路径的类名);

      Class clz = Class.forName("java.lang.String");
      System.out.println(clz);  // class java.lang.String
      

Class类:

  • 方法:
    • static Class<?> forName(String className) : 返回与带有给定字符串名的类或接口相关联的 Class 对象。
    • T newInstance(): 创建此 Class 对象所表示的类的一个新实例。 注意:该方法仅仅适用于通过无参构造来创建对象;如果类中没有无参构造,则通过该方法创建对象会运行抛出异常 (这种方法已经过时)
    • 获取构造方法
      • Constructor<T> getConstructor(Class<?>... parameterTypes) :返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
      • Constructor<?>[] getConstructors():返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
      • 以上两个方法只能返回public修饰的构造方法
      • Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) :返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。
      • Constructor<?>[] getDeclaredConstructors():返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。
    • 获取属性
      • Field getField(String name): 返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共字段。
      • Field[] getFields() : 返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
      • 以上两个方法只能返回public修饰的属性
      • Field getDeclaredField(String name) : 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
      • Field[] getDeclaredFields() : 返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。
    • 获取方法
      • Method getMethod(String name, Class<?>... parameterTypes): 第一个参数表示方法名称, 第二个参数表示当前方法的参数列表的类型的Class对象,返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
      • Method[] getMethods():返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
      • Method getDeclaredMethod(String name, Class<?>... parameterTypes): 返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
      • Method[] getDeclaredMethods():返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

Constructor类:

  • 方法
    • T newInstance(Object... initargs) : 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
    • setAccessible(boolean flag): 将flag设置为true,可以进行暴力破解,不受权限控制
    • Class<?>[] getExceptionTypes(): 返回一组表示声明要抛出的异常类型的 Class 对象,这些异常是由此 Constructor 对象表示的底层构造方法抛出的。
    • Class<?>[] getParameterTypes() : 按照声明顺序返回一组 Class 对象,这些对象表示此 Constructor 对象所表示构造方法的形参类型。

Field类:

  • 方法:
    • Object get(Object obj):返回指定对象上此 Field 表示的字段的值。
    • void set(Object obj, Object value):将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
    • Class<?> getType():返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。

Method 类:

  • 方法:
    • Object invoke(Object obj, Object... args):第一个参数指定调用哪个对象身上的方法,第二个参数:实参的值;对带有指定参数的指定对象调用由此 Method 对象表示的底层方法
    • Class<?> getReturnType():返回一个 Class 对象,该对象描述了此 Method 对象所表示的方法的正式返回类型

优点:

  • 提高了代码的灵活性和扩展性

缺点:

  • 可以绕过泛型的检查,可能会导致集合的使用出问题

  • 打破了面向对象封装

示例:模拟数据库操作

public class DataBaseDemo {
    public static void main(String[] args) throws Exception {
        // 加载配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream(".\\dataBase.properties"));
        String value = properties.getProperty("DBName");
        System.out.println(value);
        // 使用类名(value)创建对象
        Class clz = Class.forName(value);
        System.out.println(clz);  // class cn.ysu.reflect.MySql
        // newInstance() 获取Class对象对应的类的实例 (过时)
        // 只能用于无参构造
        // Object o = clz.newInstance();

        // 通过有参构造创建对象
        Constructor constructor = clz.getConstructor(String.class);
        // 通过构造方法的 newInstance() 获取对象
        Object o = constructor.newInstance("root");

        // 获取私有构造方法
        Constructor constructor1 = clz.getDeclaredConstructor(String.class, String.class);
        System.out.println(constructor1);  // 私有 private cn.ysu.reflect.MySql(java.lang.String,java.lang.String)
        // 暴力破解
        constructor1.setAccessible(true);
        // 获取对象
        Object o1 = constructor1.newInstance("root", "123");
        System.out.println(o1); // cn.ysu.reflect.MySql@723279cf

        DataBase db = (DataBase) o;
        db.insert();

          // 获取抛出异常的构造方法 Class<?>[] getExceptionTypes()
//        Constructor constructor = clz.getConstructor(String.class);
//        Class[] exces = constructor.getExceptionTypes();
//        for (Class c : exces){
//            System.out.println(c);  // class java.lang.Exception
//        }

        // 获取public修饰的属性
        Field field = clz.getField("id");
        System.out.println(field);  // public java.lang.String cn.ysu.reflect.DataBase.id
        //  Object get(Object obj): 获取当前属性的值
        Object val = field.get(o);
        System.out.println(val);  // root
        // 设置属性值 void set(Object obj, Object value)
        field.set(o,"zss");
        System.out.println(field.get(o));  // zss

        Field field2 = clz.getDeclaredField("sql");
        // 暴力破解
        field2.setAccessible(true);
        field2.set(o1,"SELECT * FROM student");
        Object psw = field2.get(o1);
        System.out.println(psw);  // SELECT * FROM student

        // 获取方法
        Method method = clz.getMethod("insert");
        // 调用方法,需要指定调用的对象和参数值
        method.invoke(o);
        // 获取私有方法
        Method method1 = clz.getDeclaredMethod("delete");
        // 调用方法
        method1.setAccessible(true);
        // 获取方法返回值类型的对象
        Class c = method1.getReturnType();
        System.out.println(c);  // boolean
        Object oo = method1.invoke(o);
        System.out.println(oo);  // true

    }
}
abstract class DataBase{
    public String id;
    public String psw;
    public abstract void insert();
}

class MySql extends DataBase{

    private String sql;

    public MySql(String id) throws Exception {
        if (id == null){
            throw new Exception();
        }
        this.id = id;
        System.out.println("通过有参构造创建对象,一个参数");
    }

    private MySql(String id, String psw){
        this.psw = psw;
        this.id = id;
        System.out.println("通过有参构造创建对象,两个参数");
    }

    public void insert(){
        System.out.println("从Mysql数据库中插入数据");
    }

    private boolean delete(){
        System.out.println("从Mysql数据库中删除数据");
        return true;
    }
}

class Oracle extends DataBase{
    public void insert(){
        System.out.println("从Oracle数据库中插入数据");
    }
}

dataBase.properties文件内容

DBName = cn.sss.reflect.MySql


这篇关于java基础(十六):反射的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程