Java 反射相关的知识
学前问题:
- 什么是反射?
- 反射出现的背景?
- 反射的具体实现原理?
- 反射的应用场景?
基本就是 What --- Why --- How
+ 场景
1. 什么是反射
反射的两层理解:
- 1、反转创建对象的角色
- 2、将
类结构
映射为对应的 Java 对象。
反射
Reflection
:将 Java 类中的各种结构(方法、属性。构造器、类名)映射为对应的Java 对象
,利用反射技术可以对一个类进行解剖,反射是框架技术的灵魂。
Oracle 官网对 Java Reflection 反射技术的一个定义:
①:
Reflection
is a feature in the Java programming language. It allows an executing Java program to examine or "introspect" upon itself, and manipulate internal properties of the program. For example, it's possible for a Java class to obtain the names of all its members and display them.②:One tangible use of reflection is in JavaBeans, where software components can be manipulated visually via a builder tool. The tool uses reflection to obtain the properties of Java components (classes) as they are dynamically loaded.
①:
反射技术允许 Java 程序在运行期间对自身进行自省(introspect up it self),并操作程序内部的属性。例如 Java 类可以获取其所有的成员名称并显示他们。【反射是可以获取类的所有信息:包括
字段
,方法
,构造函数
等。】②:反射的实际用途是在
JavaBean
中,使用反射功能动态加载类的属性。
小结:反射技术在运行期间可以获取到类的所有信息,与方法,并且支持动态地创建类的对象。
1.1 Class 对象
其实要介绍什么是反射,首先要介绍一下 Java 的核心思想 —— 面向对象编程 。
Java 的核心是对象,对象通过类创建,而 Class 类代表了对象的模板,也就是每个类都有一个对应的 Class 对象,通过这个 Class 来生成具体的实例。
那么对象是怎样来的?
这里的 对象
,狭义的来说就是类的实例
,而 Java
是由许多个类组成的。
类的定义很简单,一个 .java
源文件被编译成字节码文件后, JVM
经过一系列过程例如验证,链接 之后 加载 Class
文件,生成 Class
模板对象,然后当我们使用 new
关键字时,生成类的实例对象。
对象创建的方式:
1、虚拟机 JVM 加载类 Class
文件,代码中使用 new
关键字创建对象
2、使用反射创建对象:在代码运行期由对象的使用者准备对象的创建模板 --- Class
类,角色反转。
这里可以将 Class
对象看作是 Java
对象的模板,并且这些 Class 对象是由 JVM 进行加载的,保证了安全性,Java 编写了对应的 Class
类。
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {
...
}
1.2 Class 对象的获取方法
使用反射时,创建类或调用类中方法的前提是获取该类对应的 Class
对象 , Java 中有三种获取方法:
- 第一种:使用
Class.forName
方法 获得传入参数的类,并对其进行初始化。
// 可以看到这个方法的入参是类名,这里是包括包名的完整类路径 例如 study01.server.basic.Iphone
// 这个方法与调用 Class.forName(className,true,currentLoader) 等效,CurrentLoader 指的是当前类的类加载器,通过这个类加载器对类进行装载
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
- 第二种: 使用
字面量
方式.class
获取Class
类- 例如:
Class clz = String.class
,clz
获取了String
对应的Class
对象
- 例如:
这种方式只适用于编译器就知道的类。
- 第三种:使用类对象的实例的
getClass()
方法
那么这个前提也很明显了,就是已经创建了类对象的实例,反过来获取创建实例的模板。
2. 使用反射创建对象
反射可以获取类的属性,与方法,也包括了构造方法,那么自然也可以创建对象,而不是使用 new
关键字来创建对象。
2.1 newInstance 方法(已在 jdk9 之后被标记为过期)
获取 Class
对象之后,调用 Class.newInstance()
就可以获取对应类的实例,具体演示如下:
首先定义一个类:
class Iphone {
public Iphone() {
}
private String name = "爱疯12 create by Class.newInstance";
public Iphone(String name) {
this.name = name;
}
@Override
public String toString() {
return new StringJoiner(", ", Iphone.class.getSimpleName() + "[", "]")
.add("name='" + name + "'")
.toString();
}
}
使用 Class.newInstance() 创建 Iphone 对象
public static void main(String[] args)
throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
// 1、使用 newInstance 的方式创建对象
Iphone ip = new Iphone();
Class iPClazz = ip.getClass();
Iphone ip1 = (Iphone) iPClazz.newInstance();
System.out.println(ip.toString());
}
}
我的项目 JDK 设置的是 11
,可以看到 newInstance
已经被标记为 Deprecated
过期了
从 JDK9 这个版本开始,不推荐使用这个方法了。
使用 Class.getConstructor().newInstance 创建 Iphone 对象(JDK11 之后推荐的方法)
public static void main(String[] args)
throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
// 1、对象.getClass()
// 3. Class.forName("包名.类名") 完整类路径,不需要类存在,耦合度最低,动态性最高,配合多态使用,更加灵活
Class iPClazz = Class.forName("study01.server.basic.Iphone");
Iphone o1 = (Iphone) iPClazz.getConstructor().newInstance();
System.out.println(o1);
// 这里如果需要通过传入 name 调用带参构造创建对象可以向下面这样
}
}
调用无参构造函数通过反射创建对象:
调用带参构造函数通过反射创建对象:
到这一部分为止,为了学习自己写一个 Java HTTP 服务器的反射相关知识已经够了,所以就先不继续深入了。
学习之前的问题基本上回答了什么是反射和反射的应用场景,至于具体反射实现类的源码与底层技术留到之后深入学习。
Q.E.D.
Comments | 0 条评论