天天看点

02-day1黑马javaweb笔记-反射:框架设计的灵魂02-day1黑马javaweb笔记-反射:框架设计的灵魂

02-day1黑马javaweb笔记-反射:框架设计的灵魂

框架

半成品软件。可以在框架的基础上进行软件开发,简化编码

反射

将类的各个组成部分封装为其他对象,这就是反射机制

好处:

1. 可以在程序运行过程中,操作这些对象。

2. 可以解耦,提高程序的可扩展性。

02-day1黑马javaweb笔记-反射:框架设计的灵魂02-day1黑马javaweb笔记-反射:框架设计的灵魂

获取Class对象的方式:

  1. Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象
    • 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
  2. 类名.class:通过类名的属性class获取
    • 多用于参数的传递
  3. 对象.getClass():getClass()方法在Object类中定义着。(有对象)
    • 多用于对象的获取字节码的方式
02-day1黑马javaweb笔记-反射:框架设计的灵魂02-day1黑马javaweb笔记-反射:框架设计的灵魂
package FanShe;

import day01.itcast.junit.test.Calculator;

public class main {
    public static void main(String[] args) throws ClassNotFoundException {
        //1
        Class aClass = Class.forName("day01.itcast.junit.test.Calculator");
        //2
        Class bClass = Calculator.class;
        //3
        Calculator calculator = new Calculator();
        Class cClass = calculator.getClass();

        System.out.println(aClass);
        System.out.println(bClass);
        System.out.println(cClass);

        //3个对象比较
        System.out.println(aClass==bClass);
        System.out.println(aClass==cClass);

        //新创建的对象就不会相同了
        Calculator calculator2 = new Calculator();

        System.out.println(calculator==calculator2);


    }
}
           

结论:

​ 同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

使用class对象

获取功能:

  1. 获取成员变量们
    • Field[] getFields() :获取所有public修饰的成员变量
    • Field getField(String name) 获取指定名称的 public修饰的成员变量
    • Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
    • Field getDeclaredField(String name)
  2. 获取构造方法们
    • Constructor<?>[] getConstructors()
    • Constructor getConstructor(类<?>… parameterTypes)
    • Constructor getDeclaredConstructor(类<?>… parameterTypes)
    • Constructor<?>[] getDeclaredConstructors()
  3. 获取成员方法们:
    • Method[] getMethods()
    • Method getMethod(String name, 类<?>… parameterTypes)
    • Method[] getDeclaredMethods()
    • Method getDeclaredMethod(String name, 类<?>… parameterTypes)
  4. 获取全类名
    • String getName()

创建好一个Person对象:

  1. 成员变量
  2. 构造方法
  3. 成员方法
  4. toString

Field:成员变量

设置值

  • void set(Object obj, Object value)

获取值

  • get(Object obj)

忽略访问权限修饰符的安全检查

  • setAccessible(true):暴力反射(getDeclaredFields是需要暴力反射的)

运行实例:

package FanShe;

import java.lang.reflect.Field;

public class ReflectDemo2 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        //获取成员变量门
        Class personClass = Person.class;

        //获取public修饰的成员变量
        Field[] fields = personClass.getFields();
        for(Field field:fields){
            System.out.println(field);
        }

        System.out.println("------");
        Field a = personClass.getField("add");
        //获取成员变量name的值
        Person person = new Person();
        Object value = a.get(person);
        System.out.println(value);

        //设置add的值
        a.set(person,"家");
        System.out.println(person);
    }
}


           
02-day1黑马javaweb笔记-反射:框架设计的灵魂02-day1黑马javaweb笔记-反射:框架设计的灵魂

Constructor:构造方法

  • 创建对象:
    • T newInstance(Object… initargs)
    • 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法
package FanShe;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflectDemo3 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //创建Constructor类
        Class personClass = Person.class;
        Constructor constructor = personClass.getConstructor(String.class, int.class);

        //创建对象
        Object person = constructor.newInstance("张三", 23);
        System.out.println(person);
    }
}

           
02-day1黑马javaweb笔记-反射:框架设计的灵魂02-day1黑马javaweb笔记-反射:框架设计的灵魂

Method:方法对象

* **执行方法**:
	* Object invoke(Object obj, Object... args)  
           
  • 获取方法名称:
    • String getName:获取方法名
package FanShe;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

public class ReflectDemo4 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //获取Person的Class对象
        Class personClass = Person.class;
        //获取指定名称的方法
        Method setName = personClass.getMethod("setName", String.class);
        Person person = new Person();

        //执行方法
        setName.invoke(person,"hello");

        System.out.println(person);

        //获取所有public修饰的方法,会获取到一些object的方法,应为默认都继承了object类
        Method[] methods = personClass.getMethods();
        for(Method method:methods){
            System.out.println(method);
        }

    }
}

           
02-day1黑马javaweb笔记-反射:框架设计的灵魂02-day1黑马javaweb笔记-反射:框架设计的灵魂

案例

​ 需求:写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法

  • 实现:

    配置文件

    2. 反射

  • 步骤:
    1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中

      2. 在程序中加载读取配置文件

      3. 使用反射技术来加载类文件进内存

      4. 创建对象

      5. 执行方法

1.创建配置文件,在src下创建一个pro.properties

写入内容,一个类名,一个方法名

className=day01.itcast.junit.test.CalculatorTest
methodName=printtest
           
02-day1黑马javaweb笔记-反射:框架设计的灵魂02-day1黑马javaweb笔记-反射:框架设计的灵魂
package FanShe;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //1.1创建Properties
        Properties pro = new Properties();
        //1.2加在配置文件,转换成为一个集合
        //1.2.1获取class目录下配置文件的目录
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("pro.properties");
        pro.load(is);

        //2.获取配置文件中定义的数据
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");

        //3.加在该类进内存
        Class cls = Class.forName(className);
        //4.创建对象
        Object o = cls.newInstance();
        //5.获取方法对象
        Method method = cls.getMethod(methodName);
        //6.运行程序
        method.invoke(o);
    }
}

           
02-day1黑马javaweb笔记-反射:框架设计的灵魂02-day1黑马javaweb笔记-反射:框架设计的灵魂

为什么需要这样编写代码?

因为很多项目在做好时,需要编译,但是编译好后,就不能修改代码了。

这样以来反射就祢补了这个缺陷,只需要修改文件中调用的类名和方法名即可。