public class Person {
// 属性
private String name;
public int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private Person(String name) {
this.name = name;
}
public Person() {
System.out.println("Person()");
}
public void show(){
System.out.println("你好,我是一个人");
}
private String showNation(String nation){
System.out.println("我的国籍是:" + nation);
return nation;
}
}
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectionTest {
@Test
public void test() throws Exception {
// 1. 通过反射获取Person类对应的Class类型的实例对象
// 获取的Class类型对象可以认为就是Person类
Class personClass = Person.class;
// 2. 通过反射(通过Person类对应的Class类型的实例对象)获取Person类的构造器
// 获取参数为String类型和int类型的构造器
Constructor personPublicConstructor = personClass.getConstructor(String.class, int.class);
// 3. 通过反射(通过获取的Person类的构造器)实例化person对象
// 实例化的对象 name = “ZS”; age = 18
Object personObj = personPublicConstructor.newInstance("ZS", 18);
System.out.println(personObj);
// 4. 通过反射获取类的属性和方法
// 获取Person类的属性
Field personAgeField = personClass.getField("age");
// 通过获取的Person类的属性修改person对象personObj的age属性
personAgeField.set(personObj, 10);
System.out.println(personObj);
// 获取Person类的方法
Method personShowMethod = personClass.getMethod("show");
// 通过反射调用person对象personObj的show方法
personShowMethod.invoke(personObj);
System.out.println("===========================================");
// 5. 通过反射获取Person类的私有结构,私有方法、私有属性等
// 通过反射获取Person类的私有构造器
Constructor personPrivateConstructor = personClass.getDeclaredConstructor(String.class);
personPrivateConstructor.setAccessible(true); // 允许调用私有构造器
// 使用Person类的私有构造器实例化对象
Person personObj2 = (Person) personPrivateConstructor.newInstance("LS");
System.out.println(personObj2);
// 6. 通过反射获取私有属性和方法
// 获取私有属性
Field name = personClass.getDeclaredField("name");
name.setAccessible(true); // 允许调用私有属性
name.set(personObj2, "WW");
System.out.println(personObj2);
// 获取私有方法
Method showNation = personClass.getDeclaredMethod("showNation", String.class);
showNation.setAccessible(true); // 允许调用私有方法
String nation = (String) showNation.invoke(personObj2, "China");
System.out.println(nation);
}
}
疑问:通过直接new的方式或反射的方式都可以调用公共的结构,开发中到底用那个?
Java代码运行时,加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。
反射,即有一个对象,但这个对象的类型为Class类型,一个Class类型的对象对应一个Java类,我们可以通过这个对象获取对应的Java类的结构信息,即可以获取这个Class类型对象对应Java类的方法和属性信息及其他信息。
@Test
public void test01() throws ClassNotFoundException {
// 方式一:
// 通过调用运行时类的class属性获取Class实例
// Class Class带泛型
// 获取的Class实例对象就是User类本身
Class userClass1 = User.class;
System.out.println(userClass1);
// 方式二:
// 通过运行时类的对象的getClass()方法获取Class实例
// 不管哪个对象都可以获取到该对象是由哪个类实例化的
User user = new User();
Class userClass2 = user.getClass();
System.out.println(userClass2);
// 方式三:
// 调用Class的静态方法,forName(String classPath)获取Class实例
// classPath为类的全类名,全类名包含包名在内的类的完整路径
String className = "study01.User";
Class userClass3 = Class.forName(className); // 在内存中加载User类
System.out.println(userClass3);
// 方式四:
// 使用当前类的加载器Classloader调用加载器中的loadClass(String classPath)方法获取Class实例
// classPath为类的全类名
// 获取系统类加载器调用加载器中的loadClass(String classPath)方法获取Class实例
Class userClass4 = ClassLoader.getSystemClassLoader().loadClass(className); // 在内存中加载User类
System.out.println(userClass4);
// 不同的方法获取都是同一个Class实例对象,即都是同一个运行时类
System.out.println(userClass1 == userClass1);
System.out.println(userClass1 == userClass2);
System.out.println(userClass1 == userClass3);
System.out.println(userClass1 == userClass4);
}
()
方法的过程。
()
方法是由编译器自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。()
方法在多线程环境中被正确加锁和同步。@Test
public void test01() {
// 获取系统类加载器
// 该方法默认获取的类加载器为系统类加载器
// SystemClassLoader就是ApplicationClassLoader
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
// 获取系统类加载器的父加载器 ExtensionClassLoader
ClassLoader extensionClassLoader = systemClassLoader.getParent();
System.out.println(extensionClassLoader);
// 获取引导类记载器
ClassLoader bootstrapClassLoader = extensionClassLoader.getParent();
System.out.println(bootstrapClassLoader);
}
@Test
public void test02() throws ClassNotFoundException {
// 获取User类的运行时类对象,对应的Class实例对象
Class<User> userClass = User.class;
// 获取加载User类的加载器
ClassLoader classLoader = userClass.getClassLoader();
// jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
// 用户自定义的类是系统类加载器加载的
System.out.println(classLoader);
// 将 String 这个类主动进行加载
Class<?> stringClass = Class.forName("java.lang.String");
// 获取加载String的类加载器
ClassLoader stringClassClassLoader = stringClass.getClassLoader();
// null
// java核心库中的类有引导类加载器加载
System.out.println(stringClassClassLoader);
}
package java.lang;
/**
* ClassName: String
* Package: java.lang
* Description:
*
* @Author tcw
* @Create 2023-05-22 18:32
* @Version 1.0
*/
public class String {
public static void main(String[] args) {
System.out.println("hello world...");
}
}
@Test
public void test5() throws Exception {
// 实例化Properties对象
Properties pros = new Properties();
// 获取文件输入流对象
// 文件默认位于当前模块下(测试方法默认从当前模块下开始读取文件)
FileInputStream fis = new FileInputStream("jdbc.properties");
// Properties对象加载配置文件中的内容
pros.load(fis);
// 读取配置文件中的user password
String user = pros.getProperty("user");
String password = pros.getProperty("password");
System.out.println("user = " + user + ",password = " + password);
}
@Test
public void test6() throws Exception {
Properties pros = new Properties();
// 使用ClassLoader获取系统类加载器
ClassLoader classLoader = ClassLoader.getClassLoader();
// 通过系统类加载器以流的方式获取资源
// 使用该方式读取配置文件,默认的读取位置为:当前模块的src下
InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
// Properties对象加载配置文件中的内容
pros.load(is);
// 读取数据
String user = pros.getProperty("user");
String password = pros.getProperty("password");
System.out.println("user = " + user + ",password = " + password);
}
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value();
}
public interface MyInterface {
void method();
}
public class Creature<T> {
boolean gender;
public int id;
public void breath(){
System.out.println("呼吸");
}
private void info(){
System.out.println("我是一个生物");
}
}
@MyAnnotation("t_persons")
public class Person extends Creature<String> implements Comparable<Person>,MyInterface{
private String name;
public int age = 1;
@MyAnnotation("info")
private static String info;
public Person(){
System.out.println("Person()...");
}
protected Person(int age){
this.age = age;
}
private Person(String name, int age){
this.name = name;
this.age = age;
}
public void show() throws RuntimeException,ClassNotFoundException{
System.out.println("你好,我是一个Person");
}
@MyAnnotation(value="show_nation")
private String showNation(String nation,int age){
System.out.println("showNation...");
return "我的国籍是:" + nation + ",生活了" + age + "年";
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Person o) {
return 0;
}
@Override
public void method() {
}
public static void showInfo(){
System.out.println("我是一个人");
}
}
Class实例对象.getDeclaredConstructor().newInstance()
// InstantiationException 没有空参构造器会抛出该异常
// IllegalAccessException 空参的构造器权限不足会抛出该异常
@org.junit.Test
public void test01() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
// 加载类到内存,获取 Person 类对应的运行时类对象
Class<?> personClass = Class.forName("study02.data.Person");
// 创建 Person 类的实例对象
Person person = (Person) personClass.newInstance();
System.out.println(person);
}
@org.junit.Test
public void test1() {
Class personClass = Person.class;
// 使用getFields()获取运行时类及其父类中声明为public访问权限的属性。
// 返回值为一个Field类型的数组
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
}
@Test
public void test2() {
Class personClass = Person.class;
// getDeclaredField()获取运行时类中声明的所有属性,不包含父类中声明的属性。
// 返回值为一个Field类型的数组
Field[] fields = personClass.getDeclaredFields();
for (Field field: fields) {
System.out.println(field);
}
}
Modifier.toString(modifiers)
将权限修饰符对应数字转换为对应的权限修饰符字符串 @Test
public void test3() {
Class personClass = Person.class;
Field[] fields = personClass.getDeclaredFields();
for (Field field: fields) {
// 1. 获取属性的权限修饰符
// field.getModifiers()得到的为权限修饰符对应的数字
// 默认权限为0
// 可以使用Modifier.toString(modifiers)将权限修饰符对应数字转换为对应的权限修饰符字符串
int modifiers = field.getModifiers();
System.out.println(Modifier.toString(modifiers));
// 2. 获取属性的数据类型
// 返回值类型为Class
Class type = field.getType();
// type.getName()会返回数据类型的全类名
System.out.println(type.getName());
// 3. 获取属性的变量名
String fieldName = field.getName();
System.out.println(fieldName);
System.out.println("---------------");
}
}
// 对于权限修饰符,将其数字转换为对应的字符串的对应关系
// 0x是十六进制
// * PUBLIC = 0x00000001; 1 1
// * PRIVATE = 0x00000002; 2 10
// * PROTECTED = 0x00000004; 4 100
// * STATIC = 0x00000008; 8 1000
// * FINAL = 0x00000010; 16 10000
public static String toString(int mod) {
StringJoiner sj = new StringJoiner(" ");
if ((mod & PUBLIC) != 0) sj.add("public");
if ((mod & PROTECTED) != 0) sj.add("protected");
if ((mod & PRIVATE) != 0) sj.add("private");
/* Canonical order */
if ((mod & ABSTRACT) != 0) sj.add("abstract");
if ((mod & STATIC) != 0) sj.add("static");
if ((mod & FINAL) != 0) sj.add("final");
if ((mod & TRANSIENT) != 0) sj.add("transient");
if ((mod & VOLATILE) != 0) sj.add("volatile");
if ((mod & SYNCHRONIZED) != 0) sj.add("synchronized");
if ((mod & NATIVE) != 0) sj.add("native");
if ((mod & STRICT) != 0) sj.add("strictfp");
if ((mod & INTERFACE) != 0) sj.add("interface");
return sj.toString();
}
@Test
public void test1() {
Class personClass = Person.class;
// getMethods()获取运行时类及其所有父类中声明为public访问权限的方法。
// 返回值为Method类型的数组
Method[] methods = personClass.getMethods();
for (Method method: methods) {
System.out.println(method);
}
}
@Test
public void test2() {
Class personClass = Person.class;
// getDeclaredMethods()获取运行时类中声明的所有方法,不包含父类中声明的方法
// 返回值为Method类型的数组
Method[] methods = personClass.getDeclaredMethods();
for (Method method: methods) {
System.out.println(method);
}
}
@Xxxx
权限修饰符 返回值类型 方法名(参数类型1 参数名1, ...) throws Exception {}
@Test
public void test4() {
Class clazz = Person.class;
Method[] methods = clazz.getDeclaredMethods();
for (Method m : methods) {
//1.获取方法声明的注解
//返回值为Annotation类型的数组,因为一个方法上可以加多个注解
Annotation[] annos = m.getAnnotations();
for (Annotation a : annos) {
System.out.println(a);
}
//2.权限修饰符
//m.getModifiers()得到的为权限修饰符对应的数字
//Modifier.toString()将权限修饰符数字转换为对应的字符串
System.out.print(Modifier.toString(m.getModifiers()) + "\t");
//3.返回值类型
System.out.print(m.getReturnType().getName() + "\t");
//4.方法名
System.out.print(m.getName());
System.out.print("(");
//5.形参列表
Class[] parameterTypes = m.getParameterTypes();
//判断方法是否有形参列表
if (!(parameterTypes == null || parameterTypes.length == 0)) {
// 循环输出参数类型
for (int i = 0; i < parameterTypes.length; i++) {
// 最后一个形参的输出进行特殊处理
if (i == parameterTypes.length - 1) {
System.out.print(parameterTypes[i].getName() + " args_" + i);
break;
}
System.out.print(parameterTypes[i].getName() + " args_" + i + ",");
}
}
System.out.print(")");
//6.抛出的异常
//抛出的异常可能有多个也可能没有异常的抛出
Class[] exceptionTypes = m.getExceptionTypes();
//判断是否有异常的抛出
if (exceptionTypes.length > 0) {
System.out.print("throws ");
for (int i = 0; i < exceptionTypes.length; i++) {
if (i == exceptionTypes.length - 1) {
System.out.print(exceptionTypes[i].getName());
break;
}
System.out.print(exceptionTypes[i].getName() + ",");
}
}
System.out.println("{}");
}
}
@Test
public void test1() {
Class personClass = Person.class;
// getConstructors()获取运行时类中声明为public访问权限的构造器。
// 返回值为Constructor类型的数组,构造器可能有多个
Constructor[] constructors = personClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
}
@Test
public void test2() {
Class personClass = Person.class;
// getDeclaredConstructors()获取运行时类中声明的所有构造器
// 返回值为Constructor类型的数组,构造器可能有多个
Constructor[] constructors = personClass.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
}
@Test
public void test() {
Class personClass = Person.class;
// 获取运行时类的父类
// 运行时类的父类的类型也为Class
Class superClass = personClass.getSuperclass();
System.out.println(superClass);
}
@Test
public void test() {
Class personClass = Person.class;
// 获取运行时类的带泛型的父类
Type genericSuperclass = personClass.getGenericSuperclass();
System.out.println(genericSuperclass);
}
@Test
public void test() {
Class personClass = Person.class;
// 先获取带泛型的父类
// Type 是一个接口,Class 实现了该接口
Type genericSuperclass = personClass.getGenericSuperclass();
System.out.println(genericSuperclass);
// 已经确定genericSuperclass带有泛型,将其强转为带有参数类型ParameterizedType类型
ParameterizedType paramType = (ParameterizedType) genericSuperclass;
//调用getActualTypeArguments()获取泛型
//返回的为数组,是由于有时候泛型有多个,如Map就有两个泛型
Type[] actualTypeArguments = paramType.getActualTypeArguments();
System.out.println(actualTypeArguments[0].getTypeName());
}
@Test
public void test() {
Class clazz = Person.class;
// 获取运行时类实现的接口
// 由于实现的接口可能有多个,所以返回的为数组
Class[] interfaces = clazz.getInterfaces();
for(Class c : interfaces){
System.out.println(c);
}
}
@Test
public void test() {
Class clazz = Person.class;
//获取运行时类的父类实现的接口
//先获取运行时类的父类
//然后获取运行时类的父类实现的接口
Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
for(Class c : interfaces1){
System.out.println(c);
}
}
@Test
public void test() {
Class clazz = Person.class;
Package pack = clazz.getPackage();
System.out.println(pack);
}
@Test
public void test() {
Class clazz = Person.class;
Annotation[] annotations = clazz.getAnnotations();
for(Annotation annos : annotations){
System.out.println(annos);
}
}
@org.junit.Test
public void test03() throws Exception {
// 加载类,获取该类对应的Class实例
Class<?> personClass = Class.forName("study02.data.Person");
// 创建对象
Person person = (Person) personClass.getDeclaredConstructor().newInstance();
/*
* 公共的非静态的属性
*/
// 获取运行时类的指定名的属性
Field age = personClass.getField("age"); // 该属性公共的非静态的
// 获取属性值
// 由于是非静态的,所以要指明获取哪个对象的属性
Object personAge = age.get(person); // 返回的为该对象的属性值
System.out.println("person age 属性的初始值为:" + personAge);
// 设置属性值
age.set(person, 22); // 设置person的age属性的属性值为22
System.out.println("person age 属性的当前值为:" + age.get(person));
/*
* 私有的属性(获取当前运行时类的公共属性或私有属性都可以采用下面的方法)
*/
// getField() 获取运行时类及其父类中声明为 public 访问权限的属性
// 获取私有属性需要使用 getDeclaredField() 获取运行时类中声明的所有属性,不包含父类中声明的属性
Field name = personClass.getDeclaredField("name");
// 私有权限默认不能进行访问
// 要访问私有权限,需要修改其是否可以访问 确保属性可以访问
name.setAccessible(true); // 修改为可以进行访问
name.set(person, "张三"); // 设置person的name为 “张三”
String personName = (String) name.get(person); // 获取person的name
System.out.println("person 的 name 为:" + personName);
/*
* 运行时类的静态属性
*/
Field info = personClass.getDeclaredField("info"); // 获取属性
info.setAccessible(true); // 设置为可以访问
// 对应静态变量,info.set(null, "Person 类的信息..."); 也是可以的
// 因为获取 静态属性 时已经知道该属性是哪个类的了,无向再次指明
info.set(personClass, "Person 类的信息..."); // 由于是静态属性所以调用该方法的对象为类对应的Class实例
// info.get(null)
Object PersonInfo = info.get(personClass); // 获取属性值
System.out.println(PersonInfo);
}
@org.junit.Test
public void test04() throws Exception {
// 获取运行时类Class对象
Class<Person> personClass = Person.class;
// 创建Person对象
Person person = personClass.getDeclaredConstructor().newInstance();
// 获取方法 private String showNation(String nation,int age) {}
// 参数一:方法名
// 参数二:可变形参,方法的形参列表中的各参数的类型(参数类型要对应)
// 类型不能自动装箱,类型的值才可以自动装箱
Method showNation = personClass.getDeclaredMethod("showNation", String.class, int.class);
// 设置方法是否可以访问
showNation.setAccessible(true);
// 参数一:调用哪个对象的该方法
// 参数二:可变形参,方法的形参
// 返回值为方法的返回值
Object invokeBack = showNation.invoke(person, "中国", 23);
System.out.println(invokeBack);
}
@org.junit.Test
public void test05() throws Exception {
// 获取运行时类
Class<Person> personClass = Person.class;
// 获取构造器 private Person(String name, int age) {}
// 参数:可变形参,构造器形参的类型
Constructor<Person> personConstructor = personClass.getDeclaredConstructor(String.class, int.class);
// 设置构造器可以进行访问
personConstructor.setAccessible(true);
// 利用获取的构造器创建对象
Person person = personConstructor.newInstance("张三", 34);
System.out.println(person);
}
/**
* ClassName: Table
* Package: PACKAGE_NAME
* Description:
* 普通Java对象和数据库中哪个表对应
*
* @Author tcw
* @Create 2023-05-25 9:25
* @Version 1.0
*/
@Target(ElementType.TYPE) // 该注解只能使用在类、接口、枚举、记录上
@Retention(RetentionPolicy.RUNTIME) // 在运行时需要可以通过反射获取该注解,所以RUNTIME
public @interface Table {
String value();
}
/**
* ClassName: Column
* Package: PACKAGE_NAME
* Description:
*
* @Author tcw
* @Create 2023-05-25 9:32
* @Version 1.0
*/
@Target(ElementType.FIELD) // 该注解只能在属性上
@Retention(RetentionPolicy.RUNTIME) // 在运行时需要可以通过反射获取该注解,所以RUNTIME
public @interface Column {
String columnName(); // 对应数据库表中字段的字段名
String columnType(); // 对应数据库表中字段的字段类型
}
/**
* ClassName: Customer
* Package: PACKAGE_NAME
* Description:
*
* @Author tcw
* @Create 2023-05-25 9:29
* @Version 1.0
*/
@Table("t_customer") // 该Java类与数据库中的t_customer表对应
public class Customer {
@Column(columnName = "name", columnType = "varchar(10)")
private String name;
@Column(columnName = "age", columnType = "int")
private Integer age;
public Customer() {
}
public Customer(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Customer{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
@Test
public void test() throws Exception {
// 加载类获取类对应的Class实例
Class<?> customer = Class.forName("Customer");
// 获取类上的注解(Table)
Table customerDeclaredAnnotation = customer.getDeclaredAnnotation(Table.class);
// 获取注解的属性
System.out.println("该Java类对应的数据库表为:" + customerDeclaredAnnotation.value());
// 获取属性
Field[] customerDeclaredFields = customer.getDeclaredFields();
// 获取属性上的注解
for (Field customerDeclaredField : customerDeclaredFields) {
Column fieldAnnotation = customerDeclaredField.getAnnotation(Column.class);
System.out.print("对应数据库中的字段:" + fieldAnnotation.columnName());
System.out.println(" 类型为:" + fieldAnnotation.columnType());
}
}
案例:榨汁机榨水果汁,水果分别有苹果(Apple)、香蕉(Banana)、桔子(Orange)等。
提示:
1、声明(Fruit)水果接口,包含榨汁抽象方法:void squeeze(); /skwiːz/
2、声明榨汁机(Juicer),包含运行方法:public void run(Fruit f),方法体中,调用f的榨汁方法squeeze()
3、声明各种水果类,实现水果接口,并重写squeeze();
4、在src下,建立配置文件:config.properties,并在配置文件中配上fruitName=xxx(其中xx为某种水果的全类名)
5、在FruitTest测试类中,
(1)读取配置文件,获取水果类名,并用反射创建水果对象,
(2)创建榨汁机对象,并调用run()方法
/**
* ClassName: Fruit
* Package: PACKAGE_NAME
* Description:
*
* @Author tcw
* @Create 2023-05-25 10:07
* @Version 1.0
*/
public interface Fruit {
/**
* 水果榨汁的方法
*/
void squeeze();
}
/**
* ClassName: Apple
* Package: PACKAGE_NAME
* Description:
*
* @Author tcw
* @Create 2023-05-25 10:09
* @Version 1.0
*/
public class Apple implements Fruit{
@Override
public void squeeze() {
System.out.println("苹果汁...");
}
}
public class Banana implements Fruit{
@Override
public void squeeze() {
System.out.println("香蕉汁....");
}
}
public class Orange implements Fruit{
@Override
public void squeeze() {
System.out.println("橘子汁...");
}
}
public class Juicer {
/**
* 使用需要进行榨汁的水果榨汁
*
* @param fruit 水果
*/
public static void run(Fruit fruit) {
fruit.squeeze(); // 榨汁
}
}
fruitName=Apple
/**
* ClassName: FruitTest
* Package: PACKAGE_NAME
* Description:
*
* @Author tcw
* @Create 2023-05-25 10:14
* @Version 1.0
*/
public class FruitTest {
public static void main(String[] args) throws Exception {
// 利用类加载器加载配置文件
ClassLoader classLoader = FruitTest.class.getClassLoader();
InputStream resource = classLoader.getResourceAsStream("config.properties"); // 默认从src下开始查找文件
// 使用Properties对象加载文件中的内容
Properties properties = new Properties();
properties.load(resource);
// 获取需要进行榨汁的水果(获取全类名)
String fruitName = (String) properties.get("fruitName");
// 利用反射创建相应水果的实例对象
Class<?> fruitClass = Class.forName(fruitName); // 加载类
Fruit fruit = (Fruit) fruitClass.getDeclaredConstructor().newInstance(); // 虽然不知道是什么水果但是一定是水果
// 调用榨汁机榨汁方法进行榨汁
Juicer.run(fruit);
}
}