day22Java-Reflect-反射

博客
Java-(高级)

类加载器

在写反射时,先介绍类加载器,因为反射都是在操作运行时Class文件对象,一个java文件,首先要编译成class文件,在使用类加载器加载到内存中。

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

加载 
	1.就是指将class文件读入内存,并为之创建一个Class对象。
	2.任何类被使用时系统都会建立一个Class对象。
连接
	1.验证 是否有正确的内部结构,并和其他类协调一致
	2.准备 负责为类的静态成员分配内存,并设置默认初始化值
	3.解析 将类的二进制数据中的符号引用替换为直接引用
初始化 就是我们以前讲过的初始化步骤

1.类加载器图解
在这里插入图片描述

2.类加载器的组成

	1)BootStrap:引导类加载器:加载都是最基础的文件 
		也被称为引导类加载器,负责Java核心类的加载。
			比如System,String等。在JDK中JRE的lib目录下rt.jar文件中。
	2)ExtClassLoader:扩展类加载器:加载都是基础的文件
		负责JRE的扩展目录中jar包的加载。
			在JDK中JRE的lib目录下ext目录。
	3)AppClassLoader:应用类加载器:三方jar包和自己编写java文件
		负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径。

3.类初始化时机

	1.创建类的实例
	2.访问类的静态变量,或者为静态变量赋值
	3.调用类的静态方法
	4.使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
	5.初始化某个类的子类
	6.直接使用java.exe命令来运行某个主类
反射

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

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象。

反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。

要想这样使用,首先你必须得到class文件对象,其实也就是得到Class类的对象。

Class类:
  		成员变量	Field
  		构造方法	Constructor
  		成员方法	Method
	
反射-获取class文件对象的方式

获取class文件对象的方式:
A:Object类的getClass()方法
B:数据类型的静态属性class
C:Class类中的静态方法
public static Class forName(String className)

一般我们到底使用谁呢?
		A:自己玩	任选一种,第二种比较方便
  		B:开发	第三种
  			为什么呢?因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中。

代码演示

public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        //A:Object类的getClass()方法
        Person p = new Person();
        Class c = p.getClass();
        Person p2 = new Person();
        Class c1 = p2.getClass();
        System.out.println(p==p2);//false
        System.out.println(c==c1);//true

        //B:数据类型的静态属性class
        Class c2 = Person.class;
        System.out.println(c1==c2);//true

        //C:Class类中的静态方法
        Class c3 = Class.forName("com.ginger.demo01.Person");
        System.out.println(c2==c3);//true
    }
}

结果

false
true
true
true
反射-通过反射获取构造方法对象相关方法

Class类中的方法:
Constructor[] getConstructors():获取公共构造方法对象
Constructor<?>[] getDeclaredConstructors():获取所有构造方法对象(包括私有)
Constructor getConstructor(Class<?>… parameterTypes):获取单个公共构造方法对象
Constructor getDeclaredConstructor(Class<?>… parameterTypes): 获取单个公共构造方法对象(包括私有)

Constructor类中的方法:
public void setAccessible(boolean flag):值为true,取消 Java 语言访问检查。
T newInstance(Object… initargs):使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

反射获取构造方法共用的Person类

public class Person {
    private String name;
    int age;
    public String address;

    public Person() {
    }

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

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

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

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

    public void method(String s) {
        System.out.println("method" + s);
    }

    public String getString(String s, int i) {
        return s + "--" + i;
    }

    private void function() {
        System.out.println("function");
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}
反射-通过反射获取无参构造方法对象

代码演示

public class RefletcDemo {
    public static void main(String[] args) throws Exception {
        //获取class文件对象
        Class c = Class.forName("com.ginger.demo02.Person");

        //Constructor[] getConstructors():获取公共构造方法
        Constructor[] consArr1 = c.getConstructors();
        for (Constructor cons1 : consArr1) {
            System.out.println(cons1);
        }
        System.out.println("----------------------------------------------");
        //Constructor<?>[] getDeclaredConstructors():返回所有构造方法包括私有
        Constructor[] consArr2 = c.getDeclaredConstructors();
        for (Constructor cons2 : consArr2) {
            System.out.println(cons2);
        }
        System.out.println("----------------------------------------------");

        //获取无参构造方法
        //Constructor<T> getConstructor(Class<?>... parameterTypes):获取单个构造
        //参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象
        Constructor cons3 = c.getConstructor();//返回构造方法对象

        //T newInstance(Object... initargs):使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
        Object o = cons3.newInstance();//等价于//Person p  = new Person();
        System.out.println(o);

        Person p2 = (Person) o;
        p2.show();
    }
}

结果:

public com.ginger.demo02.Person(java.lang.String,int,java.lang.String)
public com.ginger.demo02.Person(java.lang.String,int)
public com.ginger.demo02.Person()
----------------------------------------------
public com.ginger.demo02.Person(java.lang.String,int,java.lang.String)
public com.ginger.demo02.Person(java.lang.String,int)
private com.ginger.demo02.Person(java.lang.String)
public com.ginger.demo02.Person()
----------------------------------------------
Person{name='null', age=0, address='null'}
show

反射-通过反射获取带三个参数构造方法对象

需求:通过反射去获取该构造方法并使用:
public Person(String name, int age, String address)

Person p = new Person(“亚索”,33,“艾欧尼亚”);
System.out.println§;

代码演示

public class RefletcDemo {
    public static void main(String[] args) throws Exception {
        //获取Class对象
        Class c1 = Class.forName("com.ginger.demo03.Person");

        //获取带参构造方法对象
        //Constructor<T> getConstructor(Class<?>... parameterTypes)
        Constructor cons = c1.getConstructor(String.class, int.class, String.class);

        //通过带参的构造方法对象,创建对象。
        //T newInstance(Object... initargs)
        Object o = cons.newInstance("亚索", 33, "艾欧尼亚");//等价于Person p = new Person("亚索",33,"艾欧尼亚");
        System.out.println(o);

        Person p = (Person) o;
        p.show();
    }
}

结果:

Person{name='亚索', age=33, address='艾欧尼亚'}
show
反射-通过反射获取私有构造方法对象

需求:通过反射获取私有构造方法并使用
private Person(String name)

Person p = new Person(“影流之主”);
System.out.println§;
代码演示

public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        //获取Class对象
        Class c1 = Class.forName("com.ginger.demo04.Person");

        //获取私有带参构造方法对象
        //NoSuchMethodException:没有这样的方法
        //Constructor cons = c1.getConstructor(String.class);//只能获取公共方法,所以就报错了。
        Constructor cons = c1.getDeclaredConstructor(String.class);//可以获取私有构造方法

        //public void setAccessible(boolean flag):值为true,取消 Java 语言访问检查。
        //设置为true就可以访问私有构造方法
        cons.setAccessible(true);
        //IllegalAccessException:非法异常
        Object o = cons.newInstance("影流之主");//因为是私有方法不能访问所以报错了。
        System.out.println(o);

        Person p = (Person)o;
        p.show();
    }
}

结果:

Person{name='影流之主', age=0, address='null'}
show
反射-通过反射获取成员变量对象相关方法

Class类中的方法:
Field[] getFields():获取公共成员变量对象
Field[] getDeclaredFields():获取所有成员变量对象(包括私有)
Field getField(String name):获取单个公共成员变量
Field getDeclaredField(String name):获取单个成员变量对象(包括私有)

Field类中的方法:
void set(Object obj,Object value):将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
void setAccessible(boolean flag):值为true,取消 Java 语言访问检查。
反射获取构造方法共用的Person类

public class Person {
    private String name;
    int age;
    public String address;

    public Person() {
    }

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

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

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

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

    public void method(String s) {
        System.out.println("method" + s);
    }

    public String getString(String s, int i) {
        return s + "--" + i;
    }

    private void function() {
        System.out.println("function");
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}
反射-通过反射获取不同修饰符的成员变量对象

代码演示

public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        //获取Class对象
        Class c1 = Class.forName("com.ginger.demo05.Person");

        //获取多个成员变量对象
        //Field[] getFields():获取公共成员变量对象
        //Field[] fields1 = c1.getFields();//获取公共成员变量对象
        //for (Field field : fields1) {
        //    System.out.println(field);
        //}
        //System.out.println("---------------------------------------");
        //Field[] getDeclaredFields():获取所有成员变量对象(包括私有)
        //Field[] field2 = c1.getDeclaredFields();//获取所有成员变量对象
        //for (Field field : field2) {
        //    System.out.println(field);
        //}
        //System.out.println("---------------------------------------");

        /*
            Person p  = new Person(); p.address="艾欧尼亚"; System.out.println(p);
         */
        //通过无参构造创建对象
        Constructor cons = c1.getConstructor();
        Object obj = cons.newInstance();

        //获取单个成员变量对象
        //获取address字段并赋值
        //Field getField(String name):获取单个公共成员变量
        Field field3 = c1.getField("address");

        // public void set(Object obj,Object value):将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
        field3.set(obj, "艾欧尼亚");//把obj对象的addressField字段设置为"艾欧尼亚"。
        System.out.println(obj);
        System.out.println("---------------------------------------");

        //获取name字段并赋值
        //NoSuchFieldException
        //Field field4 = c1.getField("name");

        //Field getDeclaredField(String name):获取单个成员变量对象(包括私有)
        Field field4 = c1.getDeclaredField("name");//获取单个私有成员变

        //void setAccessible(boolean flag):值为true,取消 Java 语言访问检查。
        field4.setAccessible(true);
        field4.set(obj, "影流之主");
        System.out.println(obj);
        System.out.println("---------------------------------------");

        //获取age字段并赋值
        //NoSuchFieldException
        //Field file5 = c1.getField("age");

        Field file6 = c1.getDeclaredField("age");
        file6.set(obj,33);
        System.out.println(obj);
    }
}

结果:

Person{name='null', age=0, address='艾欧尼亚'}
---------------------------------------
Person{name='影流之主', age=0, address='艾欧尼亚'}
---------------------------------------
Person{name='影流之主', age=33, address='艾欧尼亚'}
反射-通过反射获取成员方法对象相关方法

Class类中的方法:
Method[] getMethods():获取公共成员方法对象(包括从父类继承的公共方法)
Method[] getDeclaredMethods():获取自己所有成员方法对象(包括私有)
Method getMethod(String name, Class<?>… parameterTypes):获取单个公共成员方法对象
Method getDeclaredMethod(String name, Class<?>… parameterTypes):获取单个公共成员方法对象(包括私有)

Method类中的方法:
Object invoke(Object obj, Object… args):对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
void setAccessible(boolean flag):值为true,取消 Java 语言访问检查。
反射获取构造方法共用的Person类

public class Person {
    private String name;
    int age;
    public String address;

    public Person() {
    }

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

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

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

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

    public void method(String s) {
        System.out.println("method" + s);
    }

    public String getString(String s, int i) {
        return s + "--" + i;
    }

    private void function() {
        System.out.println("function");
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}
反射-通过反射获取不同修饰符的成员方法对象

代码演示

public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        //创建class对象
        Class c1 = Class.forName("com.ginger.demo06.Person");
        //Method[] getMethods():获取公共成员方法对象(包括从父类继承的公共方法)
        /*Method[] methods1 = c1.getMethods();
        for (Method method : methods1) {
            System.out.println(method);
        }
        System.out.println("------------------------------------");*/
        //Method[] getDeclaredMethods():获取自己所有成员方法对象(包括私有)
        /*Method[] methods2 = c1.getDeclaredMethods();
        for(Method method:methods2){
            System.out.println(method);
        }
        System.out.println("------------------------------------");*/
        //通过无参创建对象
        Constructor cons = c1.getConstructor();
        Object obj = cons.newInstance();

        //获取单个成员方法对象
        //Method getMethod(String name, Class<?>... parameterTypes):获取单个公共成员方法对象
        //第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型
        Method m1 = c1.getMethod("show");
        //执行方法
        // obj.m1();  错误
        //第一个参数表示对象是谁,第二参数表示调用该方法的实际参数
        //invoke()方法返回值是,obj对象调用方法(这里是show)的返回值。show()方法没有返回值,这里返回是null。
        Object o = m1.invoke(obj);//调用obj对象的m1方法
        System.out.println(o);//null
        System.out.println("------------------------------------");

        Method m2 = c1.getMethod("method", String.class);
        m2.invoke(obj, "-影流之主");
        System.out.println("------------------------------------");

        Method m3 = c1.getMethod("getString", String.class, int.class);
        Object s = m3.invoke(obj, "格雷福斯-", 45);
        System.out.println(s);
        System.out.println("------------------------------------");

        //NoSuchMethodException:未发现该方法
        //Method m4 = c1.getMethod("function");

        //Method getDeclaredMethod(String name, Class<?>... parameterTypes):获取单个公共成员方法对象(包括私有)
        Method m4 = c1.getDeclaredMethod("function");
        //IllegalAccessException:非法的访问异常
        m4.setAccessible(true);//取消 Java 语言访问检查。
        m4.invoke(obj);
    }
}

结果:

show
null
------------------------------------
method-影流之主
------------------------------------
格雷福斯---45
------------------------------------
function
反射练习-通过配置文件运行类中的方法

class.txt文件内容:
通过修改className的值,实现了我不需要修改代码,只用修改配置文件就可以实现调用不同类的work方法。

className=com.ginger.demo01.Teacher
method=work

Student类

public class Studnet {
    public void work(){
        System.out.println("学生要学习");
    }
}

Teacher类

public class Teacher {
    public void work(){
        System.out.println("老师要教书");
    }
}

测试

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //没使用反射前
        //如果我有一个需求,随着实际的变化我需要老师、学生、工程师、或者医生类,每个类中都有一个work
        //方法,不同的对象做不同的工作。
        //Student s =  new Student(); 某个时间我又不要学生对象
        //work();

        //Teacher t = new Teacher();
        //work();

        //Doctor d  = new Doctor();
        //work();
        //或者某个时间我需要工程师对象,这时候就得要改代码,一般情况下代码是不能改的。可能会牵扯很多的代码。

        //使用反射后
        Properties p = new Properties();
        //读取数据
        p.load(new FileReader("class.txt"));

        //通过建获取值
        String className = p.getProperty("className");
        String method = p.getProperty("method");

        //获取class文件对象
        Class c1 = Class.forName(className);

        //通过无参构造创建对象
        Constructor cons = c1.getConstructor();
        Object obj = cons.newInstance();

        //获取方法对象
        Method m1 = c1.getMethod("work");
        m1.invoke(obj);
    }
}

结果:

老师要教书
反射练习-ArrayList<Integer>的一个对象,在这个集合中添加一个字符串数据,如何实现呢?

首先要明白的是集合的泛型,其实是编译器器看的,在java文件编译成class文件的时候,是根本没有泛型的,这个问题就是绕过编译器就可以实现。

通过反编译查看创建的一个ArrayList集合,根本没有泛型。

public class ArrayListDemo{
	public ArrayListDemo(){
	}
	public static void main(String args[]){
		ArrayList list = new ArrayList();
	}
}

代码实现

public class ArrayListDemo {
    public static void main(String[] args) throws Exception {
        //创建集合对象
        ArrayList<Integer> list = new ArrayList<>();

        //其实就是通过反射获取到list集合字节码文件对象,在使用add方法添加一个字符串即可。
        Class c1 = list.getClass();

        //获取list集合的add方法对象
        Method m1 = c1.getMethod("add", Object.class);
        //执行方法
        m1.invoke(list,"hello");
        System.out.println(list);
    }
}

结果:

[hello]
反射练习-public void setProperty(Object obj, String propertyName, Object value){}此方法可将obj对象中名为propertyName的属性的值设置为value。

代码演示

public class ToolDemo {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Student s = new Student();
        Tool.setProperty(s, "name", "疾风剑豪");
        System.out.println(s);

        Tool.setProperty(s, "age", 35);
        System.out.println(s);
    }
}
class Student {
    private String name;
    public int age;

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

Tool工具类

public class Tool {

    public static void setProperty(Object obj, String propertyName, Object value) throws NoSuchFieldException, IllegalAccessException {
        //获取class文件对象
        Class c1 = obj.getClass();
        //获取字段对象
        //防止是私有成员
        Field field = c1.getDeclaredField(propertyName);
        //取消Java的访问检查
        field.setAccessible(true);
        //设置obj对象属性值
        field.set(obj,value);
    }
}

结果:

Student{name='疾风剑豪', age=0}
Student{name='疾风剑豪', age=35}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值