(视频:尚硅谷:)
(视频:韩顺平:https://www.bilibili.com/video/BV1fh411y7R8?p=711)
目录
二.理解 Class 类,并获取 Class 实例:(java.lang.Class)
一.java 反射机制概述:
1)反射:(Reflection)(关于反射的理解)
a:被视为动态语言的关键,反射机制允许程序在执行期,借助于 Reflection API,取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
b:加载完类之后,在堆内存的方法区中,就产生了一个 Class 类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。
c:我们可以通过这个 Class 对象,看到类的结构,称之为反射。
1)反射简介:
在运行状态中,对于任意一个类都能够知道这个类所有的 属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息 以及动态调用对象方法的功能成为 Java 语言的反射机制。
2)反射机制提供的功能:
3)面试题:
a:通过直接 new 的方式 或 反射的方式,都可以调用公共的结构,开发中用哪一个?
* 建议:使用直接 new 方式。
b:什么时候会用反射:反射的作用,反射的方式?
c:反射机制 与 面向对象中的封装性是不是矛盾的,如何看待两个技术?
* 不矛盾。
二.理解 Class 类,并获取 Class 实例:(java.lang.Class)
1)类加载过程:
a:javac AB.java --> 生成一个或多个字节码文件(.class 结尾)。
b:java AB --> 对某个字节码文件进行解释运行。相当于字节码文件加载到内存中。
c:加载到内存中的类,就称为 运行时类,就作为 Class 类的实例。
2)面试题:谈谈你对 Class 类的理解 ?
a:Class 实例,每一个Class 实例,对应着加载到内存中的一个运行时类。
3)Class 实例的获取:(4 种方法)(都是 方法区中的,同一个运行时类,都 ==)
public static void main(String[] args) throws Exception {
//方式 一:调用运行时类的属性:.class
Class<AA> clazz1 = AA.class;
//方式 二:通过 运行时类的对象,调用 getClass() 对象。
AA aa = new AA();
Class<? extends AA> clazz2 = aa.getClass();
//方式 三:Class 类的静态方法:forName(String classPath)
Class<?> clazz3 = Class.forName("com.string.test.AA");
//方式 四:类加载器
ClassLoader classLoader = Test_01.class.getClassLoader();
Class<?> clazz4 = classLoader.loadClass("com.string.test.AA");
}
4)哪些类型 可以有 Class 对象?
a:只要数组的 元素类型和维度一样,就是同一个Class实例。
* 元素类型:int,String,Byte。
* 维度:一维数组,二维数组。
三:类的加载 与 ClassLoader 的理解
1)类加载器:
a:将类的 Class字节码文件 加载到 内存中,并为之创建一个java.lang.Class对象
2)类的加载过程:
a:类的加载(Load):
* java 命令,将 class 文件,加载到内存,并将这些静态数据,
* 转换成方法区的,运行时数据结构。并为之创建一个 Class 实例。
* 此过程由类加载器完成。
a:类的链接(Link):
* 将 Java 类的二进制代码,合并到 JVM 的运行状态之中的过程。
* 验证:确保加载类信息符合 JVM 规范
* 准备:为 类变量(static),分配内存,并设置类变量默认初始值,在方法去中分配。
* 解析:虚拟机常量池内 的符号引用(常量名),替换为直接引用(地址)的过程。
a:类的初始化(Intialize):
3)类加载顺序:
a:先为 父类 类变量(static变量),分配空间,赋默认值,然后赋值。
b:再为 子类 类变量(static变量),分配空间,赋默认值,然后赋值。
b:走静态方法,从上往下走。
c:开始创建对象,子类构造方法,为 子类 和 父类 本地变量分配内存地址,
d:父类本地变量先赋值,在执行父类构造方法。
e:子类本地变量先赋值,在执行子类构造方法。
f:创建子类对象完毕。
g:虚拟机会保证,类的初始化,在多线程环境下,被正确 加锁 和 同步
2)类的加载与 ClassLoader 理解:
public static void main(String[] args) {
//1:获取 系统类加载器()
ClassLoader classLoader = AB.class.getClassLoader();
System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2
//通过系统类加载器,获取配置文件
InputStream resourceAsStream = classLoader.getResourceAsStream("jdbc.properties");
//2:获取 扩展类加载器
ClassLoader parent = classLoader.getParent();
System.out.println(parent);//sun.misc.Launcher$AppClassLoader@18b4aac2
//3:获取 引导类加载器(无法获取)
// 主要负责加载java 核心类库,无法加载自定义类。
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);//null ,获取不到。
}
四.创建运行时类的对象
1)通过反射 创建对应的 运行时类的对象:
public static void main(String[] args) throws Exception {
Class<AB> clazz = AB.class;
//newInstance() :创建对应的运行时类的对象,
// 内部调用了运行时类的无参构造器(权限够才可以调用)
AB ab = clazz.newInstance();
System.out.println(ab);
}
1)本质:
a:本质还是调用 Person 类的无参构造 方法。
a:如需要创建成功:
* 对象有无参构造方法
* 无参构造方法,权限够。
五.获取运行时类的完整结构
1)获取类内部所有属性:(权限修饰符、数据类型、变量名)
public static void main(String[] args) throws Exception {
Class<AB> clazz = AB.class;
//有权限的
Field[] fields = clazz.getFields();
System.out.println(Arrays.toString(fields));
//任何权限(不包含夫类中的)
Field[] declaredFields = clazz.getDeclaredFields();
System.out.println(Arrays.toString(declaredFields));
//获取属性的细节信息
for (Field ff : declaredFields) {
int modifiers = ff.getModifiers();
System.out.println(Modifier.toString(modifiers));
Class<?> type = ff.getType();
System.out.println(type.getName());
}
}
2) 获取类内部所有方法:
a:和方法中的(注解,权限修饰符,返回值类型,方法名(参数)throws Exception )
public static void main(String[] args) throws Exception {
Class<AB> clazz = AB.class;
//获取 当前类和夫类有权限的所有方法(public)
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
//获取 当前类 所有方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
}
3) 获取构造器结构:
public static void main(String[] args) throws Exception {
Class<AB> clazz = AB.class;
//获取当前运行时类中,声明为 public 构造器
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor cc : constructors) {
System.out.println(cc);
}
//获取 全部构造器
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor cc : declaredConstructors) {
System.out.println(cc);
}
}
4) 获取运行时类的父类
public static void main(String[] args) throws Exception {
Class<AB> clazz = AB.class;
Class<? super AB> superclass = clazz.getSuperclass();
}
5) 获取运行时类实现的接口:
public static void main(String[] args) throws Exception {
Class<AB> clazz = AB.class;
// 获取运行时类实现的接口
Type[] genericInterfaces = clazz.getGenericInterfaces();
// 获取所在包
Package aPackage = clazz.getPackage();
String name = aPackage.getName();
System.out.println(name);
}
六.调用运行时类的指定结构
1) 调用运行时类的 指定的属性,并为之赋值。
public static void main(String[] args) throws Exception {
Class<BBB> clazz = BBB.class;
BBB bbb = clazz.newInstance();
//获取属性 private String name;
Field name = clazz.getDeclaredField("name");
//设为可访问的
name.setAccessible(true);
//为属性赋值
name.set(bbb, "张三");
System.out.println(bbb);
}
2) 调用运行时类的 指定的方法:
a:普通方法
public static void main(String[] args) throws Exception {
Class<BBB> clazz = BBB.class;
BBB bbb = clazz.newInstance();
//1:获取 send() 方法。
Method clazzDeclaredMethod = clazz.getDeclaredMethod("send", String.class);
System.out.println(clazzDeclaredMethod);
//2:调用 获取到的方法
clazzDeclaredMethod.setAccessible(true);
// 相当于 bbb.send("张三");
clazzDeclaredMethod.invoke(bbb, "张三");
}
class BBB {
private void send(String str) {
System.out.println("调用了方法,参数为:" + str);
}
}
a:静态方法:
public class AB {
public static void main(String[] args) throws Exception {
Class<BBB> clazz = BBB.class;
BBB bbb = clazz.newInstance();
Method method = clazz.getDeclaredMethod("staticSend", String.class);
method.setAccessible(true);
System.out.println(method);
// 是用当前 类的class文件调用方法
Object o = method.invoke(clazz, "李四");
System.out.println(o);
}
}
class BBB {
private static String staticSend(String str) {
System.out.println("调用了方法,参数为:" + str);
return "静态方法 返回了";
}
}
2) 调用运行时类的 指定的构造器:
public class AB {
public static void main(String[] args) throws Exception {
Class<BBB> clazz = BBB.class;
Constructor<BBB> declaredConstructor = clazz.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
BBB bbb = declaredConstructor.newInstance();
System.out.println(bbb);
//但是 ,一般情况下,都使用
BBB bbb = clazz.newInstance();
}
}
class BBB {
private BBB() {
}
}
七.反射的应用:动态代理
见:https://blog.csdn.net/qq_43056248/article/details/116379582