笔记整理来源 B站UP主韩顺平https://www.bilibili.com/video/BV1g84y1F7df/?spm_id_from=333.999.0.0&vd_source=763902af33f2b5f3d2e194f3923d02ca
反射
引出反射
/**
* @author 小黄
* Date: 2022-07-11
* Time: 17:45
* 反射问题的引入
*/
@SuppressWarnings({"all"})
public class ReflectionQuestionDemo {
public static void main(String[] args) throws ClassNotFoundException, Exception {
// 根据配置文件 re.properties 指定信息,创建Cat对象并调用hi()方法
// 传统方式 new 对象 -》调用方法
// Cat cat = new Cat();
// cat.hi();
// 当想调用 cry()方法时 不得已修改源码 ===>>> cat.cry()
// 在发射中,修改配置文件即可,不需修改源码!!!
// 1、使用Properties 类,读取配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("BasicGrammer\\src\\re.properties"));
String classfullpath = properties.getProperty("classfullpath");
String methodName = properties.getProperty("method");
System.out.println("classfullpath: " + classfullpath);
System.out.println("method: " + methodName);
// 2、创建对象 传统的方法,行不通!!!
// 错误!!! classfullpath 是字符串!!! String类型
//new classfullpath()
// 3、反射机制 解决
// 3.1、加载类,返回一个Class类型的对象!!!
Class cls = Class.forName(classfullpath);
// 3.2、通过 cls 得到你加载的类 com.huang.Cat 的一个对象实例
Object o = cls.newInstance();
System.out.println(o.getClass());// 运行类型:com.huang.Cat
// 3.3、通过 cls.getMethod()方法 得到你加载的类 com.huang.Cat 的 methodName(hi) 的方法对象
// 即:在反射中,可以将方法视为对象【万物皆对象】
Method method = cls.getMethod(methodName);
// 3.4、通过 method 调用方法 【即:通过方法对象来实现调用方法】
// 传统方法 对象.方法()
// 反射机制中 方法.invoke(对象)
System.out.println("=================================================");
// method.invoke(o) 输出
// 修改配置文件前:hi 招财猫
// 修改配置文件后:招财猫 喵喵叫
method.invoke(o);
}
}
反射机制
反射机制原理图
反射相关类
反射调用
反射优点和缺点
/**
* @author 小黄
* Date: 2022-07-11
* Time: 21:07
* 测试反射调用的性能和优化方案
*/
@SuppressWarnings({"all"})
public class ReflectionDemo01 {
public static void main(String[] args) throws Exception {
//
traditionMethod();
reflectionMethod();
}
// 传统方法调用hi()方法
public static void traditionMethod() {
long start = System.currentTimeMillis();
Cat cat = new Cat();
for (int i = 0; i < 900000000; i++) {
cat.hi();
}
long end = System.currentTimeMillis();
System.out.println("传统方法调用hi()方法耗时:" + (end - start));
}
// 反射机制调用hi()方法
public static void reflectionMethod() throws Exception {
long start = System.currentTimeMillis();
Class cls = Class.forName("com.huang.Cat");// 加载类获取Class类实例
Object o = cls.newInstance();// 获取Class对象实例
Method hi = cls.getMethod("hi");// 获取方法实例
for (int i = 0; i < 900000000; i++) {
hi.invoke(o);
}
long end = System.currentTimeMillis();
System.out.println("反射机制调用hi()方法耗时:" + (end - start));
}
}
反射调用优化-关闭访问检查
/**
* @author 小黄
* Date: 2022-07-11
* Time: 21:07
* 测试反射调用的性能和优化方案
*/
@SuppressWarnings({"all"})
public class ReflectionDemo01 {
public static void main(String[] args) throws Exception {
//
traditionMethod();
reflectionMethod();
reflectionImprovedMethod();
}
// 传统方法调用hi()方法
public static void traditionMethod() {
long start = System.currentTimeMillis();
Cat cat = new Cat();
for (int i = 0; i < 900000000; i++) {
cat.hi();
}
long end = System.currentTimeMillis();
System.out.println("传统方法调用hi()方法耗时:" + (end - start));
}
// 反射机制调用hi()方法
public static void reflectionMethod() throws Exception {
long start = System.currentTimeMillis();
Class cls = Class.forName("com.huang.Cat");// 加载类获取Class类实例
Object o = cls.newInstance();// 获取Class对象实例
Method hi = cls.getMethod("hi");// 获取方法实例
for (int i = 0; i < 900000000; i++) {
hi.invoke(o);
}
long end = System.currentTimeMillis();
System.out.println("反射机制调用hi()方法耗时:" + (end - start));
}
// 反射机制调用【优化】hi()方法
public static void reflectionImprovedMethod() throws Exception {
long start = System.currentTimeMillis();
Class cls = Class.forName("com.huang.Cat");// 加载类获取Class类实例
Object o = cls.newInstance();// 获取Class对象实例
Method hi = cls.getMethod("hi");// 获取方法实例
hi.setAccessible(true);// 在反射机制调用方法时,取消访问检查
for (int i = 0; i < 900000000; i++) {
hi.invoke(o);
}
long end = System.currentTimeMillis();
System.out.println("反射机制调用【优化】hi()方法耗时:" + (end - start));
}
}
Class类分析
/**
* @author 小黄
* Date: 2022-07-11
* Time: 21:44
* 对Class类特点的梳理
*/
@SuppressWarnings({"all"})
public class ClassDemo01 {
public static void main(String[] args) throws Exception {
// 1、Class也是类,因此也继承Object类
// 2、Class类对象不是new出来的,而是系统创建的
// 2.1、传统方法 new对象
Cat cat = new Cat();
/*
ClassLoader类
public Class<?> loadClass (String name) throws ClassNotFoundException {
return loadClass(name, false);
}
*/
// 2.2、反射方式
Class<?> cls = Class.forName("com.huang.Cat");
/*
ClassLoader类,仍然是通过ClassLoader类加载Cat类的 Class对象
public Class<?> loadClass (String name) throws ClassNotFoundException {
return loadClass(name, false);
}
*/
// 3、对于某个类的Class对象,在内存中只有一份,因为类只加载一次!!!
// 4、每个类的实例都会记得自己是由哪个Class实例生成的
// 5、通过Class对象可以完整地得到一个类的完整结构,通过一系列API
// 6、Class对象是存放在堆里面的
// 7、类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括 方法代码,变量名,方法名,访问权限等等)
}
}
Class常用方法
/**
* @author 小黄
* Date: 2022-07-11
* Time: 22:44
* 演示Class类的常用方法
*/
@SuppressWarnings({"all"})
public class ClassDemo02 {
public static void main(String[] args) throws Exception {
// 类的全路径
String classFullPath = "com.huang.Car";
// 1、获取到Car类的Class对象
// 返回与给定字符串名称的类或接口相关联的类对象
// <?> 表示不确定的Java数据类型
Class<?> cls = Class.forName(classFullPath);
System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
// 2、输出类对象cls
System.out.println(cls);// 显示cls对象是哪个【类】的Class对象 com.huang.Car
// 输出其运行类型
System.out.println(cls.getClass());// java.lang.Class
System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
// 3、得到包名
System.out.println(cls.getPackage().getName());// 包名 com.huang
System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
// 4、得到类名
System.out.println(cls.getName());// 全类名 com.huang.Car
System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
// 5、通过cls对象创建对象实例
Car car = ((Car) cls.newInstance());
System.out.println(car);// car.toString()
System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
// 6、通过反射获取属性 brand
Field brand = cls.getField("brand");
System.out.println(brand.get(car));// 宝马
System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
// 7、通过反射给字段赋值
brand.set(car, "奔驰");
System.out.println(brand.get(car));// 奔驰
System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
// 8、遍历得到所有属性(字段)
Field[] fields = cls.getFields();
for (Field field : fields) {
System.out.println(field.getName());// 字段名称
}
}
}
获取Class类对象的六种方式
注:根据 Java 程序在计算机中的三个阶段【获取Class类对象方法不同】
/**
* @author 小黄
* Date: 2022-07-11
* Time: 23:13
* 演示得到Class类对象的各种方式【六种】
*/
@SuppressWarnings({"all"})
public class GetClass {
public static void main(String[] args) throws Exception {
// 1、Class.forName()
// 应用场景:多用于配置文件。读取类全路径,加载类
String classFullPath = "com.huang.Car";
Class<?> cls1 = Class.forName(classFullPath);
System.out.println("cls1: " + cls1);
// 2、类名.class
// 应用场景:多用于参数传递。比如通过反射得到对应构造器对象
Class cls2 = Car.class;
System.out.println("cls2: " + cls2);
// 3、对象.getClass()
// 应用场景:已知有对象实例
Car car = new Car();
Class cls3 = car.getClass();
System.out.println("cls3: " + cls3);
// 4、通过类加载器【四种】来获取类的Class对象
// (1)、先得到类加载器 Car car
ClassLoader classLoader = car.getClass().getClassLoader();
// (2)、通过类加载器得到Class对象
Class<?> cls4 = classLoader.loadClass(classFullPath);
System.out.println("cls4: " + cls4);
// cls1 ,cls2 ,cls3 ,cls4 其实是一个对象
System.out.println(cls1.hashCode());// 1554874502
System.out.println(cls2.hashCode());// 1554874502
System.out.println(cls3.hashCode());// 1554874502
System.out.println(cls4.hashCode());// 1554874502
// 5、基本数据类型 按如下方式得到Class类对象
Class<Integer> integerClass = int.class;
Class<Boolean> booleanClass = boolean.class;
Class<Character> characterClass = char.class;
System.out.println(integerClass);// int
// 6、基本数据类型对应的包装类,也可以通过 TYPE 得到Class对象
Class<Integer> type = Integer.TYPE;
System.out.println(type);// int
System.out.println(integerClass.hashCode());// 1846274136
System.out.println(type.hashCode());// 1846274136
}
}
哪些类型有Class类对象
/**
* @author 小黄
* Date: 2022-07-11
* Time: 23:51
* 演示哪些类型有Class类对象
*/
@SuppressWarnings({"all"})
public class AllTypeClass {
public static void main(String[] args) {
// 1、外部类
Class<String> stringClass = String.class;
// 2、接口
Class<Serializable> serializableClass = Serializable.class;
// 3、数组
Class<Integer[]> aClass = Integer[].class;
Class<float[][]> aClass1 = float[][].class;
// 4、注解
Class<SuppressWarnings> suppressWarningsClass = SuppressWarnings.class;
// 5、枚举
Class<Thread.State> stateClass = Thread.State.class;
// 6、基本数据类型/包装类
Class<Integer> integerClass = int.class;
Class<Integer> integerClass1 = Integer.class;
// 7、void
Class<Void> voidClass = void.class;
// 8、Class【本质也是类】
Class<Class> classClass = Class.class;
System.out.println(stringClass);
System.out.println(serializableClass);
System.out.println(aClass);
System.out.println(aClass1);
System.out.println(suppressWarningsClass);
System.out.println(stateClass);
System.out.println(integerClass);
System.out.println(integerClass1);
System.out.println(voidClass);
System.out.println(classClass);
}
}
类加载
动态和静态加载
类加载流程图
类加载的五个阶段
加载 Loading
连接 Linking
验证 Verification
准备 Preparation
public class ClassLoading {
public static void main(String[] args) {
}
}
@SuppressWarnings({"all"})
class A {
// 属性-成员变量-字段
// 分析类加载的 链接-准备阶段 属性是如何处理的
// 1、n1 是实例属性,不是静态属性,因此在准备阶段,是不会分配内存的
// 2、n2 是静态属性,会分配内存 n2 默认初始化为0,而不是20
// 3、n3 是static final 是常量,它和静态变量不一样,因为一旦赋值就不能改变 n3为30
private int n1 = 10;
private static int n2 = 20;
private static final int n3 = 30;
}
解析 Resolution
初始化 Initialization
/**
* @author 小黄
* Date: 2022-07-12
* Time: 9:43
* 演示类加载-初始化阶段之 <clinit>()方法
*/
@SuppressWarnings({"all"})
public class ClassLoadingDemo {
public static void main(String[] args) {
// 1、加载B类,并生成B类的Class对象
// 2、链接 num = 0
// 3、初始化
// 依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句【按顺序收集并合并!!!】
/*
<clinit>(){
System.out.println("B 的静态代码块被执行");
num = 500;
num = 100;
}
合并后:num = 100
*/
System.out.println(B.num);// 100 如果直接使用类的静态属性,也会导致类的加载
}
}
@SuppressWarnings({"all"})
class B {
static {
System.out.println("B 的静态代码块被执行");
num = 500;
}
public static int num = 100;
}
注:在加载类的时候,是有同步机制的!!!
正因为有了这个机制,才能保证某个类在内存中,只有一份Class类对象!!!
获取类结构信息
java.lang.Class类
/**
* @author 小黄
* Date: 2022-07-12
* Time: 10:16
* 演示如何通过反射类获取类的结构信息
*/
@SuppressWarnings({"all"})
public class ReflectionUtils {
public static void main(String[] args) {
}
@Test
public void api01() throws Exception {
// 得到Class类对象
Class<?> personClass = Class.forName("com.huang.reflection.Person");
// 1、getName():得到全类名【返回由类对象表示的实体的名称(类,接口,数组类,原始类型或void),作为String 。】
System.out.println("personClass 全类名:" + personClass.getName());
// 2、getSimpleName():获取简单类名【返回源代码中给出的基础类的简单名称。】
System.out.println("personClass 简单类名:" + personClass.getSimpleName());
// 3、getField():获取所有public修饰的属性,包含本类以及其超类的
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println("本类及其超类public属性名称:" + field.getName());
}
// 4、getDeclaredFields():获取本类中所有属性
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("本类所有属性名称:" + declaredField.getName());
}
// 5、getMethods():获取所有public修饰的方法,包含本类以及其超类的
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println("本类及其超类public方法名称:" + method.getName());
}
// 6、getDeclaredMethods():获取本类中所有方法
Method[] declaredMethods = personClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("本类所有方法名称:" + declaredMethod.getName());
}
// 7、getConstructor():获取本类所有public修饰的构造器【代表这个类的公共构造函数的 Constructor对象的数组】
Constructor<?>[] constructors = personClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("本类public构造器名称:" + constructor.getName());
}
// 8、getDeclaredConstructors():获取本类所有的构造器
Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("本类所有的构造器: " + declaredConstructor.getName());
}
// 9、getPackage():获取该类所在的包名
Package personClassPackage = personClass.getPackage();
System.out.println("该类所在的包名:" + personClassPackage.getName());
// 10、getSuperclass():获取由该对象表示的类的超类
Class<?> superclass = personClass.getSuperclass();
System.out.println("该对象表示的类的超类: " + superclass.getName());
// 11、getInterfaces():获取这个类实现的接口数组
Class<?>[] interfaces = personClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
System.out.println("该类实现的接口: " + anInterface.getName());
}
// 12、getAnnotations():获取此元素上出现的注解
Annotation[] annotations = personClass.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println("此元素上出现的注解: " + annotation);
}
}
}
@SuppressWarnings({"all"})
class C {
public String hobby;
public void hi() {
}
public C() {
}
}
@SuppressWarnings({"all"})
interface IC {
}
@SuppressWarnings({"all"})
@Deprecated
class Person extends C implements Serializable, IC {
// 属性
public String name;
protected int age;
String job;
private double salary;
// 方法
public void m1() {
}
protected void m2() {
}
void m3() {
}
private void m4() {
}
// 构造器
public Person() {
}
public Person(String name) {
this.name = name;
}
private Person(int age) {
this.age = age;
}
java.lang.reflect.Filed类
@Test
public void api02() throws Exception {
// 得到Class类对象
Class<?> personClass = Class.forName("com.huang.reflection.Person");
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("本类所有属性名称:" + declaredField.getName()
+ " 该属性的访问修饰符值:" + declaredField.getModifiers()
+ " 属性类型:" + declaredField.getType());
}
}
java.lang.reflect.Method类
@Test
public void api03() throws Exception {
// 得到Class类对象
Class<?> personClass = Class.forName("com.huang.reflection.Person");
Method[] declaredMethods = personClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("本类所有方法名称:" + declaredMethod.getName()
+ " 该方法的访问修饰符值:" + declaredMethod.getModifiers()
+ " 该方法返回类型:" + declaredMethod.getReturnType());
// 输出当前方法的形参数组情况
Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println("当前方法的形参类型:" + parameterType);
}
}
}
java.lang.reflect.Constructor类
@Test
public void api04() throws Exception {
// 得到Class类对象
Class<?> personClass = Class.forName("com.huang.reflection.Person");
Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("本类所有的构造器: " + declaredConstructor.getName());
Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println("该构造器的形参类型:" + parameterType);
}
}
}
反射暴力破解
创建实例
/**
* @author 小黄
* Date: 2022-07-12
* Time: 14:36
* 演示通过反射机制创建实例
*/
@SuppressWarnings({"all"})
public class ReflectCreateInstance {
public static void main(String[] args) throws Exception {
// 1、先获取到User类的Class类对象
Class<?> userClass = Class.forName("com.huang.reflection.User");
// 2、通过public的无参构造器创建实例 public User() {// 无参 public
Object o = userClass.newInstance();
System.out.println(o);
// 3、通过public的有参构造器创建实例 public User(String name) {// 有参 public
Object o1 = userClass.getConstructor(String.class).newInstance("黄孜洋");
System.out.println(o1);
// 4、通过非public的有参构造器创建实例 private User(int age, String name) {// 有参 private
Constructor<?> declaredConstructor = userClass.getDeclaredConstructor(int.class, String.class);
// 报错 :declaredConstructor构造器私有private!!!
//Object o2 = declaredConstructor.newInstance(20, "黄孜洋");
//System.out.println(o2);
// 解决办法:暴力破解【暴破】
// 使用反射可以访问私有private的属性/方法/构造器
// 反射面前,一切都是纸老虎!!!
declaredConstructor.setAccessible(true);
Object o3 = declaredConstructor.newInstance(20, "黄孜洋");
System.out.println(o3);
}
}
class User {
private int age;
private String name;
public User() {// 无参 public
}
public User(String name) {// 有参 public
this.name = name;
}
private User(int age, String name) {// 有参 private
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
操作属性
/**
* @author 小黄
* Date: 2022-07-12
* Time: 15:09
* 演示反射操作属性/字段
*/
@SuppressWarnings({"all"})
public class ReflectControlField {
public static void main(String[] args) throws Exception {
// 1、得到Student类对应的Class类对象
Class<?> studentClass = Class.forName("com.huang.reflection.Student");
// 2、创建对象实例
Object o = studentClass.newInstance();
// 3、使用反射得到age属性对象
Field age = studentClass.getField("age");
// 通过反射操作属性
age.set(o, 20);
System.out.println(o);
System.out.println(age.get(o));
// 4、使用反射操作name属性【private static】
Field name = studentClass.getDeclaredField("name");
name.setAccessible(true);
//name.set(o, "小黄");
name.set(null, "小黄~");// 因为name是static属性 ,因此 o 也可写为 null
System.out.println(o);
System.out.println(name.get(o));// 获取属性值
System.out.println(name.get(null));// 获取属性值 ,要求name是static属性
}
}
@SuppressWarnings({"all"})
class Student {
public int age;
private static String name;
public Student() {
}
@Override
public String toString() {
return "Student [age= " + age + ",name= " + name + "]";
}
}
操作方法
/**
* @author 小黄
* Date: 2022-07-12
* Time: 15:33
* 演示通过反射调用方法
*/
@SuppressWarnings({"all"})
public class ReflectControlMethod {
public static void main(String[] args) throws Exception {
// 1、得到Boss类对应的Class类对象
Class<?> bossClass = Class.forName("com.huang.reflection.Boss");
// 2、创建对象
Object o = bossClass.newInstance();
// 3、调用 public hi()方法
Method hi = bossClass.getMethod("hi", String.class);
hi.invoke(o, "小黄");
// 4、调用 private static say()方法
Method say = bossClass.getDeclaredMethod("say", int.class, String.class, char.class);
say.setAccessible(true);
Object invoke1 = say.invoke(o, 20, "小黄", '男');
System.out.println(invoke1);
System.out.println(invoke1.getClass());
Object invoke2 = say.invoke(null, 200, "李四", '女');
System.out.println(invoke2);
System.out.println(invoke2.getClass());
}
}
@SuppressWarnings({"all"})
class Boss {
public int age;
private static String name;
public Boss() {
}
private static String say(int n, String s, char c) {
return n + " " + s + " " + c;
}
public void hi(String s) {
System.out.println("hi " + s);
}
}