1. 一个需求引出反射

@SuppressWarnings({"all"})public class ReflectionQuestion {public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {//根据配置文件 re.properties 指定信息, 创建Cat对象并调用方法hi//老韩回忆//传统的方式 new 对象 -》 调用方法// Cat cat = new Cat();// cat.hi(); ===> cat.cry() 修改源码.//我们尝试做一做 -> 明白反射//1. 使用Properties 类, 可以读写配置文件Properties properties = new Properties();properties.load(new FileInputStream("src\\re.properties"));String classfullpath = properties.get("classfullpath").toString();//"com.hspedu.Cat"String methodName = properties.get("method").toString();//"hi"System.out.println("classfullpath=" + classfullpath);System.out.println("method=" + methodName);//2. 创建对象 , 传统的方法,行不通 =》 反射机制//new classfullpath();//3. 使用反射机制解决//(1) 加载类, 返回Class类型的对象clsClass cls = Class.forName(classfullpath);//(2) 通过 cls 得到你加载的类 com.hspedu.Cat 的对象实例Object o = cls.newInstance();System.out.println("o的运行类型=" + o.getClass()); //运行类型//(3) 通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName"hi" 的方法对象// 即:在反射中,可以把方法视为对象(万物皆对象)Method method1 = cls.getMethod(methodName);//(4) 通过method1 调用方法: 即通过方法对象来实现调用方法System.out.println("=============================");method1.invoke(o); //传统方法 对象.方法() , 反射机制 方法.invoke(对象)}}
2. java反射机制
Java Reflection

Java 反射机制原理示意图!!!

Java 反射机制可以完成

反射相关的主要类

public class Reflection01 {public static void main(String[] args) throws Exception {//1. 使用Properties 类, 可以读写配置文件Properties properties = new Properties();properties.load(new FileInputStream("src\\re.properties"));String classfullpath = properties.get("classfullpath").toString();//"com.hspedu.Cat"String methodName = properties.get("method").toString();//"hi"//2. 使用反射机制解决//(1) 加载类, 返回Class类型的对象clsClass cls = Class.forName(classfullpath);//(2) 通过 cls 得到你加载的类 com.hspedu.Cat 的对象实例Object o = cls.newInstance();System.out.println("o的运行类型=" + o.getClass()); //运行类型//(3) 通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName"hi" 的方法对象// 即:在反射中,可以把方法视为对象(万物皆对象)Method method1 = cls.getMethod(methodName);//(4) 通过method1 调用方法: 即通过方法对象来实现调用方法System.out.println("=============================");method1.invoke(o); //传统方法 对象.方法() , 反射机制 方法.invoke(对象)//java.lang.reflect.Field: 代表类的成员变量, Field对象表示某个类的成员变量//得到name字段//getField不能得到私有的属性Field nameField = cls.getField("age"); //System.out.println(nameField.get(o)); // 传统写法 对象.成员变量 , 反射 : 成员变量对象.get(对象)//java.lang.reflect.Constructor: 代表类的构造方法, Constructor对象表示构造器Constructor constructor = cls.getConstructor(); //()中可以指定构造器参数类型, 返回无参构造器System.out.println(constructor);//Cat()Constructor constructor2 = cls.getConstructor(String.class); //这里老师传入的 String.class 就是String类的Class对象System.out.println(constructor2);//Cat(String name)}}
反射优点和缺点

public class Reflection02 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//Field//Method//Constructorm1();m2();m3();}//传统方法来调用hipublic static void m1() {Cat cat = new Cat();long start = System.currentTimeMillis();for (int i = 0; i < 90; i++) {cat.hi();}long end = System.currentTimeMillis();System.out.println("m1() 耗时=" + (end - start));}//反射机制调用方法hipublic static void m2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {Class cls = Class.forName("com.hspedu.Cat");Object o = cls.newInstance();Method hi = cls.getMethod("hi");long start = System.currentTimeMillis();for (int i = 0; i < 900000000; i++) {hi.invoke(o);//反射调用方法}long end = System.currentTimeMillis();System.out.println("m2() 耗时=" + (end - start));}//反射调用优化 + 关闭访问检查public static void m3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {Class cls = Class.forName("com.hspedu.Cat");Object o = cls.newInstance();Method hi = cls.getMethod("hi");hi.setAccessible(true);//在反射调用方法时,取消访问检查long start = System.currentTimeMillis();for (int i = 0; i < 900000000; i++) {hi.invoke(o);//反射调用方法}long end = System.currentTimeMillis();System.out.println("m3() 耗时=" + (end - start));}}
反射调用优化-关闭访问检查


3. Class类
基本介绍


public class Class01 {public static void main(String[] args) throws ClassNotFoundException {//看看Class类图//1. Class也是类,因此也继承Object类//Class//2. Class类对象不是new出来的,而是系统创建的//(1) 传统new对象/* ClassLoader类public Class<?> loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);}*///Cat cat = new Cat();//(2) 反射方式, 刚才老师没有debug到 ClassLoader类的 loadClass, 原因是,我没有注销Cat cat = new Cat();/*ClassLoader类, 仍然是通过 ClassLoader类加载Cat类的 Class对象public Class<?> loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);}*/Class cls1 = Class.forName("com.hspedu.Cat");//3. 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次Class cls2 = Class.forName("com.hspedu.Cat");System.out.println(cls1.hashCode());System.out.println(cls2.hashCode());Class cls3 = Class.forName("com.hspedu.Dog");System.out.println(cls3.hashCode());}}
Class 类的常用方法

public class Class01 {public static void main(String[] args) throws ClassNotFoundException {//看看Class类图//1. Class也是类,因此也继承Object类//Class//2. Class类对象不是new出来的,而是系统创建的//(1) 传统new对象/* ClassLoader类public Class<?> loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);}*///Cat cat = new Cat();//(2) 反射方式, 刚才老师没有debug到 ClassLoader类的 loadClass, 原因是,我没有注销Cat cat = new Cat();/*ClassLoader类, 仍然是通过 ClassLoader类加载Cat类的 Class对象public Class<?> loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);}*/Class cls1 = Class.forName("com.hspedu.Cat");//3. 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次Class cls2 = Class.forName("com.hspedu.Cat");System.out.println(cls1.hashCode());System.out.println(cls2.hashCode());Class cls3 = Class.forName("com.hspedu.Dog");System.out.println(cls3.hashCode());}}
应用实例: Class02.java
public class Class002 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {//找到car类String classAllPath = "com.hspedu.Car";//获取Class对象Class<?> cls = Class.forName(classAllPath);//输出clsSystem.out.println(cls); //显示是哪个类的Class对象System.out.println(cls.getName()); //返回全类名System.out.println(cls.getClass()); //返回运行类型System.out.println(cls.getPackage().getName());//获取包名Object o = cls.getDeclaredConstructor().newInstance();//java9以后 创建对象实例//Car car = (Car) cls.getDeclaredConstructor().newInstance();//java9以后 创建对象实例//System.out.println(car);//通过反射获取属性brandField brand = cls.getField("brand");System.out.println(brand.get(o));//赋值brand.set(o,"奔驰");System.out.println(brand.get(o));//获取所有字段Field[] fields = cls.getFields();for (Field o1 :fields) {System.out.println(o1.getName() + "-" + o1.get(o));}}}
4. 获取Class类对象



不同阶段理解

public class GetClass_ {public static void main(String[] args) throws ClassNotFoundException {//1. Class.forNameString classAllPath = "com.hspedu.Car"; //通过读取配置文件获取Class<?> cls1 = Class.forName(classAllPath);System.out.println(cls1);//2. 类名.class , 应用场景: 用于参数传递Class cls2 = Car.class;System.out.println(cls2);//3. 对象.getClass(), 应用场景,有对象实例Car car = new Car();Class cls3 = car.getClass();System.out.println(cls3);//4. 通过类加载器【4种】来获取到类的Class对象//(1)先得到类加载器 carClassLoader classLoader = car.getClass().getClassLoader();//(2)通过类加载器得到Class对象Class cls4 = classLoader.loadClass(classAllPath);System.out.println(cls4);//cls1 , cls2 , cls3 , cls4 其实是同一个对象System.out.println(cls1.hashCode());System.out.println(cls2.hashCode());System.out.println(cls3.hashCode());System.out.println(cls4.hashCode());//5. 基本数据(int, char,boolean,float,double,byte,long,short) 按如下方式得到Class类对象Class<Integer> integerClass = int.class;Class<Character> characterClass = char.class;Class<Boolean> booleanClass = boolean.class;System.out.println(integerClass);//int//6. 基本数据类型对应的包装类,可以通过 .TYPE 得到Class类对象Class<Integer> type1 = Integer.TYPE;Class<Character> type2 = Character.TYPE; //其它包装类BOOLEAN, DOUBLE, LONG,BYTE等待System.out.println(type1);System.out.println(integerClass.hashCode());//?System.out.println(type1.hashCode());//?}}
5. 哪些类型有Class对象
如下类型有 Class 对象

应用实例
public class AllTypeClass {public static void main(String[] args) {Class<String> cls1 = String.class;//外部类Class<Serializable> cls2 = Serializable.class;//接口Class<Integer[]> cls3 = Integer[].class;//数组Class<float[][]> cls4 = float[][].class;//二维数组Class<Deprecated> cls5 = Deprecated.class;//注解//枚举Class<Thread.State> cls6 = Thread.State.class;Class<Long> cls7 = long.class;//基本数据类型Class<Void> cls8 = void.class;//void数据类型Class<Class> cls9 = Class.class;//System.out.println(cls1);System.out.println(cls2);System.out.println(cls3);System.out.println(cls4);System.out.println(cls5);System.out.println(cls6);System.out.println(cls7);System.out.println(cls8);System.out.println(cls9);}}
6. 类加载
基本说明

类加载时机

类加载过程图

验证: 安全校验准备: 静态变量 分配内存 默认初始化解析: 虚拟机把常量池中的符号引用替换为直接引用
类加载各阶段完成任务

加载阶段

连接阶段-验证

连接阶段-准备

public class ClassLoad02 {public static void main(String[] args) {}}class A {//属性-成员变量-字段//老韩分析类加载的链接阶段-准备 属性是如何处理//1. n1 是实例属性, 不是静态变量,因此在准备阶段,是不会分配内存//2. n2 是静态变量,分配内存 n2 是默认初始化 0 ,而不是20//3. n3 是static final 是常量, 他和静态变量不一样, 因为一旦赋值就不变 n3 = 30public int n1 = 10;public static int n2 = 20;public static final int n3 = 30;}
连接阶段-解析

符号引用: 相当于相对引用直接引用: 相当于绝对引用(在内存中被分配地址) --- JVM机操作
Initialization(初始化)

public class ClassLoad03 {public static void main(String[] args) throws ClassNotFoundException {//老韩分析//1. 加载B类,并生成 B的class对象//2. 链接 num = 0//3. 初始化阶段// 依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并合并/*clinit() {System.out.println("B 静态代码块被执行");//num = 300;num = 100;}合并: num = 100*///new B();//类加载 4.会输出构造器//System.out.println(B.num);//100, 如果直接使用类的静态属性,也会导致类的加载,但是不会调用构造器//看看加载类的时候,是有同步机制控制/*protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{//正因为有这个机制,才能保证某个类在内存中, 只有一份Class对象synchronized (getClassLoadingLock(name)) {//....}}*/B b = new B();}}class B {static {System.out.println("B 静态代码块被执行");num = 300;}static int num = 100;public B() {//构造器System.out.println("B() 构造器被执行");}}
7. 通过反射获取类的结构信息
第一组: java.lang.Class 类

第二组: java.lang.reflect.Field 类

第三组: java.lang.reflect.Method 类

第四组: java.lang.reflect.Constructor 类

public class ReflectionUtils {public static void main(String[] args) {}@Testpublic void api_02() throws ClassNotFoundException, NoSuchMethodException {//得到Class对象Class<?> personCls = Class.forName("com.hspedu.reflection.Person");//getDeclaredFields:获取本类中所有属性//规定 说明: 默认修饰符 是0 , public 是1 ,private 是 2 ,protected 是 4 , static 是 8 ,final 是 16Field[] declaredFields = personCls.getDeclaredFields();for (Field declaredField : declaredFields) {System.out.println("本类中所有属性=" + declaredField.getName()+ " 该属性的修饰符值=" + declaredField.getModifiers()+ " 该属性的类型=" + declaredField.getType());}//getDeclaredMethods:获取本类中所有方法Method[] declaredMethods = personCls.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);}}//getDeclaredConstructors:获取本类中所有构造器Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();for (Constructor<?> declaredConstructor : declaredConstructors) {System.out.println("====================");System.out.println("本类中所有构造器=" + declaredConstructor.getName());//这里老师只是输出名Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();for (Class<?> parameterType : parameterTypes) {System.out.println("该构造器的形参类型=" + parameterType);}}}//第一组方法API@Testpublic void api_01() throws ClassNotFoundException, NoSuchMethodException {//得到Class对象Class<?> personCls = Class.forName("com.hspedu.reflection.Person");//getName:获取全类名System.out.println(personCls.getName());//com.hspedu.reflection.Person//getSimpleName:获取简单类名System.out.println(personCls.getSimpleName());//Person//getFields:获取所有public修饰的属性,包含本类以及父类的Field[] fields = personCls.getFields();for (Field field : fields) {//增强forSystem.out.println("本类以及父类的属性=" + field.getName());}//getDeclaredFields:获取本类中所有属性Field[] declaredFields = personCls.getDeclaredFields();for (Field declaredField : declaredFields) {System.out.println("本类中所有属性=" + declaredField.getName());}//getMethods:获取所有public修饰的方法,包含本类以及父类的Method[] methods = personCls.getMethods();for (Method method : methods) {System.out.println("本类以及父类的方法=" + method.getName());}//getDeclaredMethods:获取本类中所有方法Method[] declaredMethods = personCls.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {System.out.println("本类中所有方法=" + declaredMethod.getName());}//getConstructors: 获取所有public修饰的构造器,包含本类Constructor<?>[] constructors = personCls.getConstructors();for (Constructor<?> constructor : constructors) {System.out.println("本类的构造器=" + constructor.getName());}//getDeclaredConstructors:获取本类中所有构造器Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();for (Constructor<?> declaredConstructor : declaredConstructors) {System.out.println("本类中所有构造器=" + declaredConstructor.getName());//这里老师只是输出名}//getPackage:以Package形式返回 包信息System.out.println(personCls.getPackage());//com.hspedu.reflection//getSuperClass:以Class形式返回父类信息Class<?> superclass = personCls.getSuperclass();System.out.println("父类的class对象=" + superclass);////getInterfaces:以Class[]形式返回接口信息Class<?>[] interfaces = personCls.getInterfaces();for (Class<?> anInterface : interfaces) {System.out.println("接口信息=" + anInterface);}//getAnnotations:以Annotation[] 形式返回注解信息Annotation[] annotations = personCls.getAnnotations();for (Annotation annotation : annotations) {System.out.println("注解信息=" + annotation);//注解}}}class A {public String hobby;public void hi() {}public A() {}public A(String name) {}}interface IA {}interface IB {}@Deprecatedclass Person extends A implements IA, IB {//属性public String name;protected static int age; // 4 + 8 = 12String job;private double sal;//构造器public Person() {}public Person(String name) {}//私有的private Person(String name, int age) {}//方法public void m1(String name, int age, double sal) {}protected String m2() {return null;}void m3() {}private void m4() {}}
8. 通过反射创建对象

实例
案例演示 com.hspedu.reflection ReflecCreateInstance.java
测试 1:通过反射创建某类的对象,要求该类中必须有 public 的无参构造
测试 2:通过调用某个特定构造器的方式,实现创建某类的对象
public class ReflecCreateInstance {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {//1. 先获取到User类的Class对象Class<?> userClass = Class.forName("com.hspedu.reflection.User");//2. 通过public的无参构造器创建实例Object o = userClass.newInstance();System.out.println(o);//3. 通过public的有参构造器创建实例/*constructor 对象就是public User(String name) {//public的有参构造器this.name = name;}*///3.1 先得到对应构造器Constructor<?> constructor = userClass.getConstructor(String.class);//3.2 创建实例,并传入实参Object hsp = constructor.newInstance("hsp");System.out.println("hsp=" + hsp);//4. 通过非public的有参构造器创建实例//4.1 得到private的构造器对象Constructor<?> constructor1 = userClass.getDeclaredConstructor(int.class, String.class);//4.2 创建实例//暴破【暴力破解】 , 使用反射可以访问private构造器/方法/属性, 反射面前,都是纸老虎constructor1.setAccessible(true);Object user2 = constructor1.newInstance(100, "张三丰");System.out.println("user2=" + user2);}}class User { //User类private int age = 10;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;}public String toString() {return "User [age=" + age + ", name=" + name + "]";}}
9. 通过反射访问类中的成员
访问属性

public class ReflecAccessProperty {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {//1. 得到Student类对应的 Class对象Class<?> stuClass = Class.forName("com.hspedu.reflection.Student");//2. 创建对象Object o = stuClass.newInstance();//o 的运行类型就是StudentSystem.out.println(o.getClass());//Student//3. 使用反射得到age 属性对象Field age = stuClass.getField("age");age.set(o, 88);//通过反射来操作属性System.out.println(o);//System.out.println(age.get(o));//返回age属性的值//4. 使用反射操作name 属性Field name = stuClass.getDeclaredField("name");//对name 进行暴破, 可以操作private 属性name.setAccessible(true);//name.set(o, "老韩");name.set(null, "老韩~");//因为name是static属性,因此 o 也可以写出nullSystem.out.println(o);System.out.println(name.get(o)); //获取属性值System.out.println(name.get(null));//获取属性值, 要求name是static}}class Student {//类public int age;private static String name;public Student() {//构造器}public String toString() {return "Student [age=" + age + ", name=" + name + "]";}}
访问方法
public class ReflecAccessMethod {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//1. 得到Boss类对应的Class对象
Class<?> bossCls = Class.forName("com.hspedu.reflection.Boss");
//2. 创建对象
Object o = bossCls.newInstance();
//3. 调用public的hi方法
//Method hi = bossCls.getMethod("hi", String.class);//OK
//3.1 得到hi方法对象
Method hi = bossCls.getDeclaredMethod("hi", String.class);//OK
//3.2 调用
hi.invoke(o, "韩顺平教育~");
//4. 调用private static 方法
//4.1 得到 say 方法对象
Method say = bossCls.getDeclaredMethod("say", int.class, String.class, char.class);
//4.2 因为say方法是private, 所以需要暴破,原理和前面讲的构造器和属性一样
say.setAccessible(true);
System.out.println(say.invoke(o, 100, "张三", '男'));
//4.3 因为say方法是static的,还可以这样调用 ,可以传入null
System.out.println(say.invoke(null, 200, "李四", '女'));
//5. 在反射中,如果方法有返回值,统一返回Object , 但是他运行类型和方法定义的返回类型一致
Object reVal = say.invoke(null, 300, "王五", '男');
System.out.println("reVal 的运行类型=" + reVal.getClass());//String
//在演示一个返回的案例
Method m1 = bossCls.getDeclaredMethod("m1");
Object reVal2 = m1.invoke(o);
System.out.println("reVal2的运行类型=" + reVal2.getClass());//Monster
}
}
class Monster {}
class Boss {//类
public int age;
private static String name;
public Boss() {//构造器
}
public Monster m1() {
return new Monster();
}
private static String say(int n, String s, char c) {//静态方法
return n + " " + s + " " + c;
}
public void hi(String s) {//普通public方法
System.out.println("hi " + s);
}
}
10. 练习

public class Homework01 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
/**
* 定义PrivateTest类,有私有name属性,并且属性值为hellokitty
* 提供getName的公有方法
* 创建PrivateTest的类,利用Class类得到私有的name属性,修改私有的name属性值,并调用getName()的方法打印name属性值
*/
//1. 得到 PrivateTest类对应的Class对象
Class<PrivateTest> privateTestClass = PrivateTest.class;
//2. 创建对象实例
PrivateTest privateTestObj = privateTestClass.newInstance();
//3. 得到name属性对象
Field name = privateTestClass.getDeclaredField("name");//name属性是private
//4. 暴破name
name.setAccessible(true);
name.set(privateTestObj, "天龙八部");
//5. 得到getName方法对象
Method getName = privateTestClass.getMethod("getName");
//6. 因为getName() 是public,所有直接调用
Object invoke = getName.invoke(privateTestObj);
System.out.println("name属性值=" + invoke);//天龙八部
}
}
class PrivateTest {
private String name = "hellokitty";
//默认无参构造器
public String getName() {
return name;
}
}

public class Homework02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
/**
* 利用Class类的forName方法得到File类的class 对象
* 在控制台打印File类的所有构造器
* 通过newInstance的方法创建File对象,并创建E:\mynew.txt文件
*/
//1. Class类的forName方法得到File类的class 对象
Class<?> fileCls = Class.forName("java.io.File");
//2. 得到所有的构造器
Constructor<?>[] declaredConstructors = fileCls.getDeclaredConstructors();
//遍历输出
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("File构造器=" + declaredConstructor);
}
//3. 指定的得到 public java.io.File(java.lang.String)
Constructor<?> declaredConstructor = fileCls.getDeclaredConstructor(String.class);
String fileAllPath = "e:\\mynew.txt";
Object file = declaredConstructor.newInstance(fileAllPath);//创建File对象
//4. 得到createNewFile 的方法对象
Method createNewFile = fileCls.getMethod("createNewFile");
createNewFile.invoke(file);//创建文件,调用的是 createNewFile
//file的运行类型就是File
System.out.println(file.getClass());
System.out.println("创建文件成功" + fileAllPath);
}
}
