反射、类加载器、getClassLoader()、getResourceAsStream、配置文件配置

一、反射

反射:是框架设计的灵魂

  • 框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
  • 反射:将类的各个组成部分封装为其他对象,这就是反射机制 (下图蓝色部分)
  • 类加载器也见下图
    在这里插入图片描述

反射的好处:

  1. 可以在程序运行过程中,操作这些对象。
  2. 可以解耦,提高程序的可扩展性。

1.1获取Class模板的3种方式:

它们是什么时候获取的可见上图

  1. Class.forName(“全类名”(需写包名.类名)):将字节码文件加载进内存,返回Class对象(需要传入类名的字符串)(加载、链接、初始化
    eg:Class cls1 = Class.forName(“cn.xxx.domain.Person”);

多用于配置文件,将类名定义在配置文件中。读取文件,加载类
Class.forName 的参数 2 为 false 时不会被初始化

  1. 类名.class:通过类名的属性class获取(只进行加载,不链接和初始化

多用于参数的传递
类加载器的 loadClass 方法不会被初始化

  1. 对象.getClass():getClass()方法在Object类中定义着。(肯定会链接初始化,因为new对象了)

多用于对象的获取字节码的方式 *

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

/**
 * @author QLBF
 * @version 1.0
 * @date 2020/11/10 15:00
 */
class Person{
    private String name;
    private int age;
    public Person() {
    }
    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 Person(String name, int age) {

        this.name = name;
        this.age = age;
    }
}
public class ReflectDemo1 {
    /**
     获取Class对象的方式:
     1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象,得抛出异常
     2. 类名.class:通过类名的属性class获取
     3. 对象.getClass():getClass()方法在Object类中定义着。
     */
    public static void main(String[] args) throws Exception {
        //下面的泛型可以删
        //1.Class.forName("全类名")
        Class cls1 = Class.forName("Person");
        System.out.println(cls1);
        //2.类名.class
        Class cls2 = Person.class;
        System.out.println(cls2);
        //3.对象.getClass()
        Person p=new Person();
        Class cls3 = p.getClass();
        System.out.println(cls3);

        //== 比较三个对象
        System.out.println(cls1 == cls2);//true
        System.out.println(cls1 == cls3);//true
        System.out.println(cls2 == cls3);//true

    }
}

1.2使用Class

Class对象功能:
* 获取功能:

  1. 获取成员变量们

    • Field[] getFields()获取所有public修饰的成员变量,不能获得私有的

    • Field getField(String name)获取指定名称的 public修饰的成员变量,也不能获得私有的

    • Field[] getDeclaredFields()获取所有的成员变量,不考虑修饰符,可以获得私有变量,但得忽略访问权限修饰符的安全检查 (protected,default也要):setAccessible(true)(暴力反射)

    • Field getDeclaredField(String name)跟上面类型,指定获得变量(可私有,忽略安全检查就行)

    Field(上面获得的都是Field):成员变量
    操作:
    1.5 设置值 void set(Object obj, Object value)
    1.6获取值 get(Object obj)

  2. 获取构造方法们

    • Constructor<?>[] getConstructors()

    • Constructor getConstructor(类<?>… parameterTypes)

    • Constructor getDeclaredConstructor(类<?>… parameterTypes)

    • Constructor<?>[] getDeclaredConstructors()

    Constructor:构造方法
    用来创建对象
    2.1 T newInstance(Object… initargs)
    2.2 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法(也可以用2.1,麻烦点而已)

  3. 获取成员方法们:

    • Method[] getMethods()

    • Method getMethod(String name, 类<?>… parameterTypes)

    • Method[] getDeclaredMethods()

    • Method getDeclaredMethod(String name, 类<?>… parameterTypes)

获取方法名:method.getName();
Method:方法对象
执行方法:

  • Object invoke(Object obj, Object… args)

    1. 获取类名
      • String getName()
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
 * @author QLBF
 * @version 1.0
 * @date 2020/11/10 15:00
 */
class Person{
    private String name;
    private int age;

    public String a;
    public int b;
    protected String c;
    String d;
    private String e;
    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
//        this.a = a;
//        this.b = b;
//        this.c = c;
//        this.d = d;
//        this.e = e;
    }

    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 String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

    public int getB() {
        return b;
    }

    public void setB(int b) {
        this.b = b;
    }

    public String getC() {
        return c;
    }

    public void setC(String c) {
        this.c = c;
    }

    public String getD() {
        return d;
    }

    public void setD(String d) {
        this.d = d;
    }

    public String getE() {
        return e;
    }

    public void setE(String e) {
        this.e = e;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", a='" + a + '\'' +
                ", b=" + b +
                ", c='" + c + '\'' +
                ", d='" + d + '\'' +
                ", e='" + e + '\'' +
                '}';
    }

    public void eat(){
        System.out.println("eat...");
    }

    public void eat(String food){
        System.out.println("eat--"+food);
    }
}
public class ReflectDemo1 {
    public static void main(String[] args) throws Exception {
        //show_Field();
        //show_constryctor();
        show_method();

    }

    private static void show_method() throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        /*
          3. 获取成员方法们:
             * Method[] getMethods()
             * Method getMethod(String name, 类<?>... parameterTypes)

             * Method[] getDeclaredMethods()
             * Method getDeclaredMethod(String name, 类<?>... parameterTypes)
         */
        //获取指定名称的方法,得传方法名和参数
        Method eat1 = personClass.getMethod("eat");
        Person p=new Person();
        //执行方法
        eat1.invoke(p);//eat...

        Method eat2 = personClass.getMethod("eat", String.class);
        eat2.invoke(p,"apple");
        System.out.println(p);//eat--apple

        System.out.println("-----------------");
        //获取所有public修饰的方法,Object的方法也会被打印
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            //System.out.println(method);//Object的方法也会被打印
            //获取方法名:
            String name = method.getName();
            //System.out.println(name);
        }

        //获取类名
        String className = personClass.getName();
        System.out.println(className);//Person,如果还有包名会被输出

    }

    private static void show_constryctor() throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        /*
            2. 获取构造方法们
                 * Constructor<?>[] getConstructors()
                 * Constructor<T> getConstructor(类<?>... parameterTypes)

                 * Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
                 * Constructor<?>[] getDeclaredConstructors()
         */
        //Constructor<T> getConstructor(类<?>... parameterTypes)
        //这里传入参数得用类型名.class
        Constructor constructor = personClass.getConstructor(String.class, int.class);
        System.out.println(constructor);//public Person(java.lang.String,int)
        //创建对象
        Object per = constructor.newInstance("李四", 29);
        System.out.println(per);//Person{name='李四', age=29, a='null', b=0, c='null', d='null', e='null'}

        System.out.println("--------");
//        Constructor[] constructors = personClass.getConstructors();
//        for (Constructor constructor1 : constructors) {
//            System.out.println(constructor1);
//        }

        //无参的构造方法1
        Constructor constructor1 = personClass.getConstructor();
        System.out.println(constructor1);//public Person()

        //空参
        Object o = personClass.newInstance();
        System.out.println(o);//Person{name='null', age=0, a='null', b=0, c='null', d='null', e='null'}
    }

    private static void show_Field() throws Exception {
        //0.获取Person的Class对象
        Class<Person> personClass = Person.class;
        /*
             1. 获取成员变量们
                 * Field[] getFields()
                 * Field getField(String name)

                 * Field[] getDeclaredFields()
                 * Field getDeclaredField(String name)

         */
        //1.Field[] getFields()获取所有public修饰的成员变量
        Field[] fields = personClass.getFields();
        for (Field field : fields) {
            System.out.println(field);//public java.lang.String Person.a, public int Person.b

        }

        //2.Field getField(String name)
        Field b = personClass.getField("b");
        //System.out.println(b);// public int Person.b
        //获取成员变量b 的值
        Person p=new Person();
        Object value = b.get(p);
        System.out.println(value);
        //设置b的值
        b.set(p,128);
        System.out.println(p);

        System.out.println("-----3-----------");
        //3.Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符
//        Field[] declaredFields = personClass.getDeclaredFields();
//        for (Field declaredField : declaredFields) {
//            System.out.println(declaredField);//啥都获取到了
//        }

        //Field getDeclaredField(String name)
        Field e = personClass.getDeclaredField("e");
        //忽略访问权限修饰符的安全检查
        e.setAccessible(true);//暴力反射
        e.set(p,"张三");
        Object value2 = e.get(p);
        System.out.println(value2);//张三
        System.out.println(p);//Person{name='null', age=0, a='null', b=128, c='null', d='null', e='张三'}
    }
}

1.2getClassLoader()

每一个class对象都有一个getClassLoader()方法
eg:ClassLoader classLoader = A.class.getClassLoader(); getClassLoader方法就是获得A的字节码文件的类加载器(把字节码文件加载进内存)

/**
 * @author QLBF
 * @version 1.0
 * @date 2020/11/11 12:30
 */
class Student{
    String name;


    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }

    public void eat(){
        System.out.println("eat..");
    }
}
public class fanshe {
    public static void main(String[] args) {
        //获取class对象
        Class class1 = Student.class;
        System.out.println(class1);//class Student

        //ClassLoader classLoader = Student.class.getClassLoader();
        //System.out.println(classLoader);//jdk.internal.loader.ClassLoaders$AppClassLoader@726f3b58

        ClassLoader classLoader = class1.getClassLoader();
        System.out.println(classLoader);//jdk.internal.loader.ClassLoaders$AppClassLoader@726f3b58
    }
}

二、反射的魅力

**反射的魅力在与:只改配置文件,而不用直接修改java代码。**这样的好处在与:上线部署后你要改代码的话,得重新编译执行,再上线。而你修改配置文件就不用编译啥的了,因为它是个物理地址.

在这里插入图片描述
我们得不动ReflectTest(相当于一个框架)
首先在src文件新建一个File文件(命名为1.properties,这里命名是随便的,你改为1不要properties后缀也行的,只不过有后缀让别人清楚这是配置文件而已!!!
在这里插入图片描述
1.properties里面写(真实情况下,下面不可以注释的):

className=Student //这里得写Person的全类名(这里每包名,有包名要点,className是自己写的,你只要对应你的ReflectTest就行)
methodName=eat  //对应Person类的方法,不用()
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * @author QLBF
 * @version 1.0
 * @date 2020/11/11 12:30
 */
class Student{
    String name;


    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }

    public void eat(){
        System.out.println("eat..");
    }
}
class Person{
    public void sleep(){
        System.out.println("sleep...");
    }
}
public class ReflectTest {

    public static void main(String[] args) throws Exception {
         /*
            前提:不能改变该类的任何代码。可以创建任意类的对象,可以执行任意方法
         */
      /*  Person p = new Person();
        p.eat();*/
/*
        Student stu = new Student();
        stu.sleep();*/

        //1.加载配置文件
        //1.1创建Properties对象
        Properties pro = new Properties();
        //1.2加载配置文件,转换为一个集合
        //1.2.1获取class目录下的配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("1.properties");
        pro.load(is);//得抛出异常

        //2.获取配置文件中定义的数据
        String classname = pro.getProperty("className");//className对应你配置文件的=左边的名字,获得你的全类名
        String methodname = pro.getProperty("methodName");//methodName也类似上面的,获得你的方法名

        //3.加载该类进内存,看上面的博客方法
        Class cls = Class.forName(classname);
        //4.创建对象,因为不知道是什么对象,所以创建一个obj的
        Object obj = cls.newInstance();
        //5.获取方法对象
        Method method = cls.getMethod(methodname);
        //6.执行方法
        method.invoke(obj);
    }
}

输出:eat…

我们不需要改动ReflectTest 的代码就可以运行Student类里面的sleep方法,只需要把对应的配置文件改为在这里插入图片描述
就行了,再运行ReflectTest 就会输出:sleep…

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值