25.java-反射

反射

  • 框架 : 半成品软件
    • 它需要我们对他进行, 进一步的丰富
    • 我们也需要它现有的框架体系
  • 反射机制

    是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
    对于任意一个对象,都能够调用它的任意属性和方法;
    这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。

大白话的理解 : 反射其实就是对类的一种解刨

​ 反射操作的是字节码对象

​ 字节码文件–Class类–字节码对象

获取Class类对象的三种方式

  • 三种方式分类

    • Class.forName(全类名)方法

      //1.Class类中的静态方法forName("全类名")
                  //全类名:包名 + 类名
              Class clazz = Class.forName("com.itheima.myreflect2.Student");
      
    • 类名.class属性

      //2.通过class属性来获取
              Class clazz2 = Student.class;
      
    • 对象名.getClass()方法

      //3.利用对象的getClass方法来获取class对象
              //getClass方法是定义在Object类中.
              Student s = new Student();
              Class clazz3 = s.getClass();
          }
      }
      

反射获取构造方法并使用

​ Class类获取构造方法对象的方法

方法介绍
方法名说明
Constructor<?>[] getConstructors()返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors()返回所有构造方法对象的数组
Constructor getConstructor(Class<?>… parameterTypes)返回单个公共构造方法对象
Constructor getDeclaredConstructor(Class<?>… parameterTypes)返回单个构造方法对象
public static void main(String[] args) throws Exception {
	Class<?> aClass = Class.forName("com.Student");
        //反射空参构造方法(解剖)
        Constructor<?> constructor = aClass.getConstructor();
        //使用空参构造方法对象,构造对象
        Object o = constructor.newInstance();

        //反射带参构造方法(解剖)
    	//小括号中,一定要跟构造方法的形参保持一致
        Constructor<?> constructor1 = aClass.getConstructor(String.class);
    	//使用有参构造方法对象,构造对象
        Object o2 = constructor1.newInstance("张三");

        //[暴力反射]带参构造方法(解剖)
        Constructor<?> constructor2 = aClass.getDeclaredConstructor(String.class);
        //开启权限
        constructor2.setAccessible(true);
    	//使用有参构造方法对象,构造对象
        Object o3 = constructor2.newInstance("王飞杨");
    }
}

Constructor类用于创建对象的方法

方法介绍
方法名说明
T newInstance(Object…initargs)根据指定的构造方法创建对象
setAccessible(boolean flag)设置为true,表示取消访问检查
 private static void method4() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        //获取一个私有的构造方法并创建对象
        //1.获取class对象
        Class clazz = Class.forName("com.itheima.myreflect3.Student");

        //2.获取一个私有化的构造方法.
        Constructor constructor = clazz.getDeclaredConstructor(String.class);

        //被private修饰的成员,不能直接使用的
        //如果用反射强行获取并使用,需要临时取消访问检查
        constructor.setAccessible(true);

        //3.直接创建对象
        Student student = (Student) constructor.newInstance("zhangsan");

        System.out.println(student);
    }

    private static void method3() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        //简写格式
        //1.获取class对象
        Class clazz = Class.forName("com.itheima.myreflect3.Student");

        //2.在Class类中,有一个newInstance方法,可以利用空参直接创建一个对象
        Student student = (Student) clazz.newInstance();//这个方法现在已经过时了,了解一下

        System.out.println(student);
    }

    private static void method2() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        //1.获取class对象
        Class clazz = Class.forName("com.itheima.myreflect3.Student");

        //2.获取构造方法对象
        Constructor constructor = clazz.getConstructor();

        //3.利用空参来创建Student的对象
        Student student = (Student) constructor.newInstance();

        System.out.println(student);
    }

    private static void method1() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        //1.获取class对象
        Class clazz = Class.forName("com.itheima.myreflect3.Student");

        //2.获取构造方法对象
        Constructor constructor = clazz.getConstructor(String.class, int.class);

        //3.利用newInstance创建Student的对象
        Student student = (Student) constructor.newInstance("zhangsan", 23);

        System.out.println(student);
    }
小结
  • 获取class对象

    三种方式: Class.forName(“全类名”), 类名.class, 对象名.getClass()

  • 获取里面的构造方法对象

    getConstructor (Class<?>... parameterTypes) getDeclaredConstructor (Class<?>… parameterTypes)

  • 如果是public的,直接创建对象

    newInstance(Object… initargs)

  • 如果是非public的,需要临时取消检查,然后再创建对象

    setAccessible(boolean) 暴力反射

反射获取成员变量并使用

  • Class类获取成员变量对象的方法
方法分类
方法名说明
Field[] getFields()返回所有公共成员变量对象的数组
Field[] getDeclaredFields()返回所有成员变量对象的数组
Field getField(String name)返回单个公共成员变量对象
Field getDeclaredField(String name)返回单个成员变量对象

Method类用于执行方法的方法

方法介绍
方法名说明
Object invoke(Object obj, Object… args)运行方法

参数一: 用obj对象调用该方法

参数二: 调用方法的传递的参数(如果没有就不写)

返回值: 方法的返回值(如果没有就不写)

案例解析
public class ReflectDemo2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//        Object invoke(Object obj, Object... args):运行方法
//        参数一:用obj对象调用该方法
//        参数二:调用方法的传递的参数(如果没有就不写)
//        返回值:方法的返回值(如果没有就不写)

        //1.获取class对象
        Class clazz = Class.forName("com.itheima.myreflect5.Student");
        //2.获取里面的Method对象  function4
        Method method = clazz.getMethod("function4", String.class);
        //3.运行function4方法就可以了
        //3.1创建一个Student对象,当做方法的调用者
        Student student = (Student) clazz.newInstance();
        //3.2运行方法
        Object result = method.invoke(student, "zhangsan");
        //4.打印一下返回值
        System.out.println(result);
    }
}
 /*
        需求: 请向一个泛型为 Integer 的集合,  添加一个 String 字符串
                普及: Java中的泛型是假的, 只在编译期间有效, 运行的时候, 就没有泛型了.
                        运行的时候: 肯定过了编译阶段, 肯定有字节码对象.
               结论 : Java中的泛型, 到运行期间, 就会被擦除掉.
     */
    public static void main(String[] args) throws Exception {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(4);
        list.add(3);

        //获取字节码对象
        Class<? extends ArrayList> aClass = list.getClass();

        //反射内部成员方法
        Method add = aClass.getMethod("add", Object.class);
        //运行成员方法
        add.invoke(list,"abc");

        System.out.println(list);
    }

综合案例

需求:1,编写三个任意的Javabean类,Student类,Teacher类,Worker类。

​ 属性均为:name,age

​ 方法要求:

​ Student里面写学习study和吃饭eat的方法(方法无参无返回)

​ Teacher里面写上课teach和吃饭eat的方法(方法无参无返回)

​ Worker里面写工作work和睡觉sleep的方法(方法无参无返回)

​ 2,本地新建配置文件properties

​ 属性:classname=Student类的全类名

​ methodname=study

​ 3,在测试类中读取properties文件中的两个属性值

​ 4,利用反射创建对象学生类的对象,并调用方法

​ 5,修改配置文件,不修改代码,运行老师类中的上课方法

​ 6,修改配置文件,不修改代码,运行工人类中的工作方法

public static void main(String[] args) throws Exception {
        Properties prop = new Properties();
        //获取配置文件的输入流
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("studentClass.properties");
        //加载配置文件的键值对到集合
        prop.load(is);
        is.close();
        //根据建获取值
        String className = prop.getProperty("classname");
        String methodname = prop.getProperty("methodname");
        //获取类的字节码对象
        Class<?> aClass = Class.forName(className);
        //反射内部的构造方法
        Constructor<?> constructor = aClass.getConstructor();
        Object o = constructor.newInstance();
        //反射内部的成员方法
        Method method = aClass.getMethod(methodname);
        //调用方法
        method.invoke(o);
    }
小结

通过字节码对象反射内部成员

  • 构造方法:Constructor类(创建对象)
  • 成员变量:Field类(设置\获取)
  • 成员方法:Method类(调用)

方法引用

介绍 :
  • 方法引用是 JDK8 开始出现的, 主要的作用, 是对Lambda表达式进行进一步的简化
格式 :

方法引用使用一对冒号 ::

方法引用通过方法的名字来指向一个方法。

方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

  • 引用前 :
public class A {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a","b","c","d");
        
        list.forEach(s -> System.out.println(s));
    }
}
  • 引用后 :
public class A {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "a", "b", "c", "d");

        list.forEach(System.out::println);
    }
}

咋回事 ??? !!!

  • 引用静态方法 :
public class A {
    /*
    	所谓方法引用, 其实就是方法的调用
    	
    	之前: A.method();
    	现在: A::method();
        
        就是一个格式的转变而已
        
        ------------------------------------------
        
        参数呢?
        
        根据可推导, 可省略原则, 参数只有一个 s
        
        method方法, 也恰好只要一个 s
        
        那方法调用起来, 这一个参数, 只可能进入 method 方法中.
    */
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "a", "b", "c", "d");

        list.forEach(s -> A.method(s));
        list.forEach(A::method);
    }

    public static void method(String s) {
        System.out.println(s.toUpperCase());
    }
}

  • 引用普通成员方法 :
1. 创建对象
2. 对象名::方法名

public class A {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "a", "b", "c", "d");

        list.forEach(s -> System.out.println(s));

        A a = new A();

        list.forEach(a::method);

    }

    public void method(String s) {
        System.out.println(s.toUpperCase());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值