携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情
反射_概念
我们之前正常使用一个类:这种情况叫:正向加载。缺点:与Student类产生了紧耦合,它改我的类就得改。
Student stu = new Student();
stu.show();
反射:也叫反向加载,是指程序有能力在运行时,动态的加载一个"类",并创建对象,并调用成员属性和成员方法。
在编译时,可以不知道这个类的存在。
反射_意义及示例
示例:
//使用反射,优点:解开两个类的紧耦合
Class c = Class.forName("全类名");
//创建对象
Object o = c.newInstance();
//获取方法
Method m = c.getMethod("show3");
//执行方法
m.invoke(o);
意义: 解开类与类之间的耦合关系。
反射_类的加载
-
当我们第一次创建一个类的对象时,JVM会去找这个类的class文件。 但之后创建对象时,JVM就不会再去找class文件,而是直接创建对象。
-
当第一次创建对象时,JVM似乎将这个类的信息全部都"记录下来",当再次创建对象时,不需要找class文件,而是找之前记录的那些信息,就可以创建对象了。
-
当我们第一次使用(第一次创建对象,第一次访问它的静态成员)某个类时,JVM会在"方法区"中创建一个Class对象,并将这个类信息写入到这个Class对象中。后期通过这个Class对象就可以获取这个类的内部信息。
-
JVM会为每个类都会创建"一个Class对象"。
-
反射是基于这个Class对象的:
- 我们让JVM去创建某个类的Class对象;
- 我们之后可以让JVM将这个Class对象返回到"程序中",之后我们程序员就可以操作这个Class对象,获取那个类的内部的信息。可以创建对象,访问属性、方法。
反射_Class对象的初始化时机
1. 第一次创建类的实例
Student stu = new Student();//1.创建它的Class对象;2.创建Student对象
...
Student stu2 = new Student();//1.创建Student对象
2. 第一次类的静态变量,或者为静态变量赋值
System.out.println(Student.PI);//第一次访问静态属性,会创建它的Class对象
...
Student stu = new Student();//不会创建Class对象,会直接创建对象
3. 第一次调用类的静态方法:
Student.show();//第一次调用静态的show()方法;会创建它的Class对象;
..
4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
Class.forName(String 全名限定的类名)
5. 初始化某个类的子类
class Fu{}
class Zi extends Fu{}
main(){
new Zi();//1.创建Fu的Class对象,2.创建Zi的Class对象,3.创建Fu对象,4.创建Zi对象
}
6. 直接使用java.exe命令来运行某个主类
class Demo{
public static void main(String[] args){
}
}
---------------
命令行:
C:>java Demo
反射_名词说明
| 英文 | 中文 |
|---|---|
| Class | 类 |
| Constructor | 构造 |
| Method | 方法 |
| Field | 字段(成员属性) |
| instance | 示例(对象) |
| invoke | 执行 |
反射_实现_获取Class对象的三种方式
1.Object-->getClass()--被所有引用类型继承
Student stu = new Student();
Class c1 = stu.getClass();
2.任何数据类型(包含基本类型)都有一个"静态属性--class",只能通过"类型名"获取,不能通过对象获取
Class c2 = Student.class;
3.通过反射
Class c3 = Class.forName("全类名");
System.out.println(c1 == c2);//true
System.out.println(c2 == c3);//true
反射_实现_获取构造方法并创建对象
获取构造方法并调用:
-
批量获取【了解】:
-
public Constructor[] getConstructors():获取所有的公有构造方法。
-
public Constructor[] getDeclaredContructors():获取所有的构造方法,包括公有、受保护的、默认的、私有的
-
-
获取单个【掌握】:
-
public Constructor getConstructor(Class ... parameterTypes):获取某个公有的构造方法
-
public Constructor getDeclaredConstructor(Class ... parameterTypes):获取某个构造方法,可以是:公有、受保护、默认、私有的
-
调用构造方法,创建对象【重点掌握】:
Constructor newInstance(Object ... 实参列表)
注意:要调用私有构造方法,要先设置暴力访问:
Constructor --> setAccessible(true)
Class --> newInstance():调用这个类的公有、无参构造方法,前提是,这个类必须有这个构造方法
反射_实现_获取成员属性并赋值和取值
-
获取成员属性:
-
批量获取:
-
public Field[] getFields():获取所有公有成员属性;
-
public Field[] getDeclaredFields():获取所有的成员属性。包括公有、受保护、默认、私有
-
-
单个获取:
-
public Field getField(String fieldName):获取某个公有的成员属性
-
public Field getDeclaredField(String fieldName):获取某个成员属性,可以是公有、受保护、默认、私有。
-
-
为属性赋值:注意:一定要先创建对象
Field --> set(Object targetObj,Object value):为targetObj对象中的Field属性赋值为value
Field --> get(Object targetObj):获取targetObj中的Field属性的值。
注意:如果是私有属性,要先设置暴力访问:Field --> setAccessible(true)
反射_实现_获取成员方法并调用
-
批量获取:
-
public Method[] getMethods():获取所有公有成员方法;包括继承的方法
-
public Method[] getDeclaredMethods():获取所有成员方法,包括公有、受保护、默认、私有
-
-
单个获取:
-
public Method getMethod(String methodName,Class ... parameterTypes):获取某个公有的成员方法
-
public Method getDeclaredMethod(String methodName,Class ... ps):获取某个成员方法,包括公有、受保护、默认、私有
-
-
调用方法:
Method --> Object invoke(Object targetObj,Class ... parameterTypes):
调用这个Method的invoke()方法,就是去调用Method所封装的那个方法。
调用invoke()的返回值,就是调用Method所封装方法的返回值;
注意:访问私有方法,要设置暴力访问:Method --> setAccessible(true)