1、通过反射创建对象
1.1、基本说明
1.2、案例演示
测试 1:通过反射创建某类的对象,要求该类中必须有 public 的无参构造
测试 2:通过调用某个特定构造器的方式,实现创建某类的对象
package reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/** * 通过反射机制创建实例 */
public class ReflecCreateInstance {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
// 1. 先获取到 User 类的 Class 对象
Class<?> userClass = Class.forName("reflection.User");
// 2. 通过 public 的无参构造器创建实例
Object o = userClass.newInstance();
System.out.println(o); // User [age=10, name=张三]
// 3. 通过 public 的有参构造器创建实例
/* constructor 对象就是 public User(String name) { // public 的有参构造器 this.name = name; } */
// 3.1 先得到对应构造器
Constructor<?> constructor = userClass.getConstructor(String.class);
// 3.2 创建实例, 并传入实参
Object jack = constructor.newInstance("jack");
System.out.println("jack=" + jack); // jack=User [age=10, name=jack]
// 4. 通过非 public 的有参构造器创建实例
// 4.1 得到 private 的构造器对象
Constructor<?> declaredConstructor = userClass.getDeclaredConstructor(int.class, String.class);
// 4.2 创建实例
// 暴破[暴力破解], 使用反射可以访问 private 构造器/方法/属性, 反射面前, 都是纸老虎
declaredConstructor.setAccessible(true);
Object lucy = declaredConstructor.newInstance(100, "lucy");
System.out.println("lucy=" + lucy); // lucy=User [age=100, name=lucy]
}
}
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 + "]";
}
}
2、通过反射访问类中的成员
2.1、访问属性
package reflection;
import java.lang.reflect.Field;
/** * 反射操作属性 */
public class ReflecAccessProperty {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
// 1. 得到 Student 类对应的 Class 对象
Class<?> stuClass = Class.forName("reflection.Student");
// 2. 创建对象
Object o = stuClass.newInstance();
System.out.println(o.getClass()); // o 的运行类型就是 class reflection.Student
// 3. 使用反射得到 age 属性对象
Field age = stuClass.getField("age");
age.set(o, 80); // 通过反射来操作属性
System.out.println(o); // Student [age=80, name=null]
System.out.println(age.get(o)); // 返回 age 属性的值 80
// 4. 使用反射操作 name 属性
Field name = stuClass.getDeclaredField("name");
// 对 name 进行暴破, 可以操作 private 属性
name.setAccessible(true);
name.set(o, "tom");
System.out.println(o); // Student [age=80, name=tom]
name.set(null, "lily"); // 因为 name 是 static 属性, 因此 o 也可以写成 null
System.out.println(o); // Student [age=80, name=lily]
System.out.println(name.get(o)); // 获取属性值 lily
System.out.println(name.get(null)); // 获取属性值, 要求 name 是 static lily
}
}
class Student {
// 类
public int age;
private static String name;
public Student() {
// 构造器
}
public String toString() {
return "Student [age=" + age + ", name=" + name + "]";
}
}
2.2、访问方法
package reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/** * 通过反射调用方法 */
@SuppressWarnings({
"all"})
public class ReflecAccessMethod {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
// 1. 得到 Boss 类对应的 Class 对象
Class<?> bossClass = Class.forName("reflection.Boss");
// 2. 创建对象
Object o = bossClass.newInstance();
// 3. 调用 public 的 hi 方法
// Method hi = bossClass.getMethod("hi", String.class);
// 3.1 利用getDeclaredMethod 得到 hi 方法对象 (公开方法和非公开方法都能用)
Method hi = bossClass.getDeclaredMethod("hi", String.class);
// 3.2 调用
hi.invoke(o, "jack"); // hi jack
// 4. 调用 private static 方法
// 4.1 得到 say 方法对象
Method say = bossClass.getDeclaredMethod("say", int.class, String.class, char.class);
// 4.2 因为 say 方法是 private, 所以需要暴破,原理和前面构造器和属性一样
say.setAccessible(true);
System.out.println(say.invoke(o, 100, "lucy", '男')); // 100 lucy 男
// 4.3 因为 say 方法是 static 的, 还可以这样调用, 可以传入 null
System.out.println(say.invoke(o, 30, "lily", '女')); // 30 lily 女
// 5. 在反射中, 如果方法有返回值, 统一返回 Object, 但是他运行类型和方法定义的返回类型一致
Object reVal = say.invoke(null, 300, "allen", '男');
System.out.println("reVal 的运行类型=" + reVal.getClass()); // reVal 的运行类型=class java.lang.String
// 一个返回的案例
Method m1 = bossClass.getDeclaredMethod("m1");
Object reVal2 = m1.invoke(o);
System.out.println("reVal2 的运行类型=" + reVal2.getClass()); // reVal2 的运行类型=class reflection.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);
}
}
3、案例练习
package reflection;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Homework01 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
/** * 定义PrivateTest类, 有私有name属性,并且属性值为hellokitty * 提供getName的公有方法 * 创建PrivateTest的类, 利用Class类得到私有的name属性, 修改私有的name属性值, 并调用getName()的方法打印name属性值 */
// 1. 得到 PrivateTest类对应的Class对象
Class<PrivateTest> privateTestClass = PrivateTest.class;
// 2. 创建对象实例
PrivateTest privateTest = privateTestClass.newInstance();
// 3. 得到name属性对象
Field name = privateTestClass.getDeclaredField("name");
// 4. 暴破name
name.setAccessible(true);
name.set(privateTest, "helloworld");
System.out.println(name.get(privateTest)); // helloworld
// 5. 得到getName方法对象
Method method = privateTestClass.getMethod("getName");
// 6. 因为getName() 是public, 所有直接调用
Object invoke = method.invoke(privateTest);
System.out.println("name属性值=" + invoke); // name属性值=helloworld
}
}
class PrivateTest {
private String name = "hellokitty";
// 默认无参构造器
public String getName() {
return name;
}
}
package reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Homework02 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
/** * 利用Class类的forName方法得到File类的class 对象 * 在控制台打印File类的所有构造器 * 通过newInstance的方法创建File对象,并创建E:\mynew.txt文件 */
// 1. Class类的forName方法得到File类的class 对象
Class<?> fileClass = Class.forName("java.io.File");
// 2. 得到所有的构造器
Constructor<?>[] declaredConstructors = fileClass.getDeclaredConstructors();
// 3. 遍历输出
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
/* public java.io.File(java.lang.String,java.lang.String) public java.io.File(java.lang.String) private java.io.File(java.lang.String,java.io.File) public java.io.File(java.io.File,java.lang.String) public java.io.File(java.net.URI) private java.io.File(java.lang.String,int) */
}
// 4. 指定的得到 public java.io.File(java.lang.String)
Constructor<?> declaredConstructor = fileClass.getDeclaredConstructor(String.class);
String fileAllPath = "e:\\mynew.txt";
Object file = declaredConstructor.newInstance(fileAllPath); // 创建File对象
// 5. 得到createNewFile 的方法对象
Method createNewFile = fileClass.getMethod("createNewFile");
createNewFile.invoke(file); // 创建文件, 调用的是 createNewFile
// file的运行类型就是File
System.out.println(file.getClass()); // class java.io.File
System.out.println("创建文件成功: " + fileAllPath); // 创建文件成功: e:\mynew.txt
}
}
文章评论