Java中的反射(一)

1.引进反射

1.1 Java文件和.class文件的关系

Java文件

Java文件中包含代码的多有内容,如类、接口、成员变量、成员方法

.class文件

.java文件通过 javac编译工具生成对应的.class字节码文件
使用JDK中提供的反编译工具,可以看到.class文件中包含有:
	Class 完整的包名.类名
	Field 成员变量,成员变量的名字和成员变量的数据类型(如果为引用数据类型,也是完整的包名.类名)
	Method 成员方法,方法权限修饰符,返回值类型,方法名,形参列表数据类型

总结

.class字节码文件中,包含了Java文件的所有内容。

1.2 程序加载过程和.class文件的关系

        在Java文件运行过程中,当前程序需要哪一个类【参与代码执行】,那么就需要【加载这个类】的.class字节码文件。
        .class字节码文件在程序的加载阶段,存在于内存的【代码区】。
        代码区存在一块空间==> .class ==> Java程序的所有内容

1.3 Java中的万物皆对象

        在Java代码中,把在【内存代码区】保存的【.class字节码内存空间】,看作是一个对象。而该对象中包含了对应的Java文件的所有内容。
图示:
在这里插入图片描述

1.4 Class到底是什么?

用例子说明:

class Person {
    int age;
    String name;
    
    public Person() {}
    
    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
    
    public void test() {
        sout("方法");
    }
}

class Dog {
    String name;
    char gender;
    
    public Dog() {}
    
    public Dog(String name, char gender) {
        this.name = name;
        this.gender = gender;
    }
    
    public void eat() {
        sout("狗狗吃肉");
    }
}

在这里插入图片描述

1.5Class类对象

        (1)【Class类对象】是自定义类(如Person、Dog类)生成的.class文件所占的【内存代码块空间】,而不是具体的类(如Person)。
        (2)自定义类是一个数据类型
        (3)【反射】是将该数据类型占用的内存代码块空间看作是一个Class对象。

2.反射理解

        反射主要是指程序可以【访问】、【检测】和【修改】它本身【状态】或【行为】的一种能力。
        某种程度上类似于光的反射,比如照镜子,人可以通反射看到自己的全身上下,但也仅能看。而Java中的反射又有所不同,它们不仅能【自描述】,还可以【自控制】。即反射不单单指反射本身,还包括对反射结果所采取的措施。
        也就是说,这类反射应用通过采用某种机制来实现对自己行为的描述和监测,并能根据自身行为的状态进行调整或修改。

3.反射重要的方法【重点】

3.1 Class涉及到的方法

(1)Class Class.forName(String packageNameAndClassName);
		Class类的静态成员方法,通过【完整的包名.类名】获取对应的.class 文件的Class对象(该对象即为.class文件所占的内存代码空间)
		因为只要自定义类【参与】代码的执行,则该类文件就会为加载。因此,该方法也可作为.class文件加载的方法。
(2)Class 类名.class;
		通过类名.class 方法,获取对应的Class类对象,通常用于方法的参数类型。
(3)Class 类对象.getClass();
		通过类对象获取对应.class文件的Class类对象、方法参数、或者说数据类型判断。

以上方法的代码演示

1)Class<?> forName = Class.forName("com.qfedu.a_reflect.Person");2)Class<com.qfedu.a_reflect.Person> cls = Person.class;3)Class<? extends Person> class1 = new Person().getClass();

注意:

  • 上述三种方式所得的Class对象是同一个Class对象
  • Class对象对应的是在内存代码区的.class文件占用的内存空间
  • Class引用数据类型变量保存的就是当前空间首地址
  • Java程序中,.class字节码文件有且之加载一次
  • .class文件占用的空间独一份,不管通过哪一种方式获取对应的Class类对象都是同一个。

3.2 Constructor(构造方法类)涉及到的方法

(1) public Constructor[] getConstructors();
		获取当前Class类对象对应Java文件中,所有【public】修饰的【构造方法】的类对象数组
(2) public Constructor[] getDeclaredConstructors();
【暴力反射】
		获取当前Class类对象对应Java文件中,所有【构造方法】的类对象数组,包括【private】修饰的构造方法。
(3) public Constructor getConstructor(Class... initArgumentTypes);
		(a) Class :【约束数据类型】,当前方法所需的参数类型
			如:需要int类型,int.class
				需要String类型, String.class
		(b) ... :【不定长参数】。构造方法需要的参数类型有很多,有的无参数,有的有参数但参数个数不一致。因此用“...”概括所有,增强代码的普适性。
		(c) initArgumentTypes : 【参数名】,初始化参数类型复数
		
		(d)根据指定的数据类型,来选择对应的构造方法,这里可能会抛出异常。
		(e)这里有且只能获取类内的【public】修饰的【指定数据类型】的构造方法类对象。
(4) public Constructor getDeclaredConstructor(Class... initArgumentTypes);
【暴力反射】
		(a)根据指定的数据类型,选择对应的构造方法,可能会抛出异常。
		(b)这里可以获取指定参数类型的所有构造方法,包括【private】修饰的构造方法。
(5) Object newInstance(Object... initArguments);
		(a)通过Constructor对象来调用,传入当前构造方法所需创建对象的初始化参数,创建对象。
		(b) Object类是Java中所有类的基类,这里可以传入任意类型的参数
		(c) ... :不定长参数,因为Constructor类对象在获取的过程中,约束的参数个数都不确定。

以上方法的代码演示

【注意】以上方法所需抛出的异常较多:
public static void main(String[] args) 
			throws ClassNotFoundException, 
			NoSuchMethodException, SecurityException, 
			InstantiationException, IllegalAccessException, 
			IllegalArgumentException, InvocationTargetException{}
			
	获取Class对象,方便下列方法使用
	//根据指定的包名.类名,获取对应的Class对象
	Class<?> cls = Class.forName("com.a_reflect.Person");1//获取当前Person类内所有非【private】构造方法
	Constructor<?>[] constructors = cls.getConstructors();
			for (Constructor<?> constructor : constructors) {
				System.out.println(constructor);
			}2//暴力反射,获取Person类内所有的构造方法,包括【private】构造方法
	Constructor<?>[] declaredConstructors = cls.getDeclaredConstructors();
			for (Constructor<?> constructor : declaredConstructors) {
				System.out.println(constructor);
			}3//根据指定参数类型获取【public】构造方法对象
	//如果没有指定参数的构造方法,运行异常java.lang.NoSuchMethodException
	Constructor<?> constructor1 = cls.getConstructor();
	Constructor<?> constructor2 = cls.getConstructor(int.class);
	Constructor<?> constructor3 = cls.getConstructor(int.class, String.class);
	System.out.println(constructor1);
	System.out.println(constructor2);
	System.out.println(constructor3);4//通过暴力反射可以获取任意权限修饰符,符合参数要求的构造方法对象
	Constructor<?> declaredConstructor1 = cls.getDeclaredConstructor();
	Constructor<?> declaredConstructor2 = cls.getDeclaredConstructor(String.class);
	System.out.println(declaredConstructor1);
	System.out.println(declaredConstructor2);5)a.
		//通过无参数Constructor对象执行newInstance方法
		//这里明确是一个Person类型,可以使用强制类型转换
		//这里使用的是public修饰的构造方法
		Person p1 = (Person) constructor1.newInstance();
		System.out.println(p1);
		System.out.println(new Person());
		System.out.println(constructor3.newInstance(1, "骚磊"));
	b.
		// 给予通过暴力反射获取到的非公开权限成员变量,成员方法,构造方法,操作权限
		// 暴力反射的为所欲为操作
		declaredConstructor2.setAccessible(true);
		Person p2 = (Person) declaredConstructor2.newInstance("骚磊");
		System.out.println(p2);

时间有限,以下内容请看 下一篇博客

Method成员方法涉及到的方法
Field成员变量涉及到的方法
给予暴力反射私有化内容的权限操作
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值