文章目录
1、反射
1.1、需求引出
package reflection.question;
import reflection.Cat;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* 反射问题的引入
*/
@SuppressWarnings({"all"})
public class ReflectionQuestion {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
// 传统的方式 new 对象 -> 调用方法
Cat cat = new Cat();
cat.cry();
// 根据配置文件 re.properties 指定信息, 创建 Cat 对象并调用方法 hi
// 1. 使用 Properties 类, 可以读写配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("src\\re.properties"));
String classfullpath = properties.get("classfullpath").toString();
String methodName = properties.get("method").toString();
System.out.println("classfullpath=" + classfullpath); // classfullpath=reflection.Cat
System.out.println("method=" + methodName); // method=cry
// 2. 创建对象, 传统的方法, 行不通 => 反射机制
// new classfullpath(); classfullpath 对应的是字符串, 不能 new, 直接报错
// 3. 使用反射机制解决
// (1) 加载类, 返回 Class 类型的对象 cls
Class cls = Class.forName(classfullpath);
// (2) 通过 cls 得到你加载的类 reflection.Cat 的对象实例
Object o = cls.newInstance();
System.out.println("o 的运行类型=" + o.getClass()); // o 的运行类型=class reflection.Cat
// (3) 通过 cls 得到你加载的类 reflection.Cat 的 methodName"cry" 的方法对象
// 即: 在反射中, 可以把方法视为对象 (万物皆对象)
Method method1 = cls.getMethod(methodName);
// (4) 通过 method1 调用方法: 即通过方法对象来实现调用方法
method1.invoke(o); // 猫猫正在哭泣...
// 传统方法 对象.方法(), 反射机制 方法.invoke(对象)
}
}
1.2、反射机制
1.2.1、Java Reflection
1.2.2、Java 反射机制原理示意图
1.2.3、Java 反射机制可以完成
1.2.4、反射相关的主要类
Reflection01.java
package reflection;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
@SuppressWarnings({"all"})
public class Reflection01 {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
// 1. 使用 Properties 类, 可以读写配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("src\\re.properties"));
String classfullpath = properties.get("classfullpath").toString();
String methodName = properties.get("method").toString();
// 2. 使用反射机制解决
// (1) 加载类, 返回 Class 类型的对象 cls
Class cls = Class.forName(classfullpath);
// (2) 通过 cls 得到你加载的类 reflection.Cat 的对象实例
Object o = cls.newInstance();
System.out.println("o 的运行类型=" + o.getClass()); // o 的运行类型=class reflection.Cat
// (3) 通过 cls 得到你加载的类 reflection.Cat 的 method
// 即: 在反射中, 可以把方法视为对象(万物皆对象)
Method method1 = cls.getMethod(methodName);
// (4) 通过 method1 调用方法: 即通过方法对象来实现调用方法
method1.invoke(o); // 传统方法 对象.方法(), 反射机制 方法.invoke(对象) 猫猫正在哭泣...
// java.lang.reflect.Field: 代表类的成员变量, Field 对象表示某个类的成员变量
// 得到 name 字段
// getField 不能得到私有的属性
Field nameField = cls.getField("age");
System.out.println(nameField.get(o)); // 10 传统写法 对象.成员变量, 反射: 成员变量对象.get(对象)
// java.lang.reflect.Constructor: 代表类的构造方法, Constructor 对象表示构造器
Constructor constructor = cls.getConstructor(); // ()中可以指定构造器参数类型, 返回无参构造器
System.out.println(constructor); // public reflection.Cat()
Constructor constructor2 = cls.getConstructor(String.class); // 这里传入的 String.class 就是 String 类的Class 对象
System.out.println(constructor2); // public reflection.Cat(java.lang.String)
}
}
Cat.java
package reflection;
public class Cat {
public String name = "小花猫";
public int age = 10;
public Cat() {
}
public Cat(String name) {
this.name = name;
}
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public void cry() {
System.out.println("猫猫正在哭泣...");
}
}
1.2.5、反射优点和缺点
package reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 测试反射调用的性能和优化方案
*/
@SuppressWarnings({"all"})
public class Reflection02 {
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
// Field
// Method
// Constructor
m1(); // 传统
m2(); // 反射
m3(); // 反射优化
}
// 传统方法来调用 hi
public static void m1() {
Cat cat = new Cat();
long start = System.currentTimeMillis();
for (int i = 0; i < 900000000; i++) {
cat.hi();
}
long end = System.currentTimeMillis();
System.out.println("m1() 耗时=" + (end - start));
}
// 反射机制调用方法 hi
public static void m2() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class cls = Class.forName("reflection.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, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class cls = Class.forName("reflection.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));
}
}
控制台输出
m1() 耗时=16
m2() 耗时=1531
m3() 耗时=1374
1.2.6、反射调用优化 - 关闭访问检查