Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java中的反射(通过反射获取类的结构、invoke方法、获取注解)

Java中的反射(通过反射获取类的结构、invoke方法、获取注解)

作者头像
鱼找水需要时间
发布于 2023-05-09 08:41:05
发布于 2023-05-09 08:41:05
4.8K01
代码可运行
举报
文章被收录于专栏:SpringBoot教程SpringBoot教程
运行总次数:1
代码可运行

1. 创建运行时类的对象

创建运行时类的对象是反射机制应用最多的地方。创建运行时类的对象有两种方式:

方式1:直接调用Class对象的newInstance()方法

要求: 1)类必须有一个无参数的构造器。 2)类的构造器的访问权限需要足够。

方式一的步骤

1)获取该类型的Class对象 2)调用Class对象的newInstance()方法创建对象

方式2:通过获取构造器对象来进行实例化

方式二的步骤

1)通过Class类的getDeclaredConstructor(Class ... parameterTypes)取得本类的指定形参类型的构造器 2)向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。 3)通过Constructor实例化对象。

如果构造器的权限修饰符修饰的范围不可见,可以调用setAccessible(true)

示例代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import org.junit.Test;

import java.lang.reflect.Constructor;

public class TestCreateObject {
    @Test
    public void test1() throws Exception{
//        Person obj = new Person();//编译期间无法创建

        Class<?> clazz = Class.forName("com.example.ext.demo.Person");
        //clazz代表com.example.ext.demo.Person类型
        //clazz.newInstance()创建的就是Person的对象
        Object obj = clazz.newInstance();
        System.out.println(obj);
    }

    @Test
    public void test2()throws Exception{
        Class<?> clazz = Class.forName("com.example.ext.demo.Person");
        //java.lang.InstantiationException: com.example.ext.demo.Person
        //Caused by: java.lang.NoSuchMethodException: com.example.ext.demo.Person.<init>()
        //即说明Person没有无参构造,就没有无参实例初始化方法<init>
        Object stu = clazz.newInstance();
        System.out.println(stu);
    }

    @Test
    public void test3()throws Exception{
        //(1)获取Class对象
        Class<?> clazz = Class.forName("com.example.ext.demo.Person");
        /*
         * 获取Person类型中的有参构造
         * 如果构造器有多个,我们通常是根据形参【类型】列表来获取指定的一个构造器的
         * 例如:public Person(String title, int num)
         */
        //(2)获取构造器对象
        Constructor<?> constructor = clazz.getDeclaredConstructor(String.class,int.class);

        //(3)创建实例对象
        // T newInstance(Object... initargs)  这个Object...是在创建对象时,给有参构造的实参列表
        Object obj = constructor.newInstance("张三", 18);
        System.out.println(obj);
    }
}

2. 获取运行时类的完整结构

可以获取:包、修饰符、类型名、父类(包括泛型父类)、父接口(包括泛型父接口)、成员(属性、构造器、方法)、注解(类上的、方法上的、属性上的)。

2.1 相关API

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//1.实现的全部接口
public Class<?>[] getInterfaces()   
//确定此对象所表示的类或接口实现的接口。 

//2.所继承的父类
public Class<? Super T> getSuperclass()
//返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class。

//3.全部的构造器
public Constructor<T>[] getConstructors()
//返回此 Class 对象所表示的类的所有public构造方法。
public Constructor<T>[] getDeclaredConstructors()
//返回此 Class 对象表示的类声明的所有构造方法。

//Constructor类中:
//取得修饰符: 
public int getModifiers();
//取得方法名称: 
public String getName();
//取得参数的类型:
public Class<?>[] getParameterTypes();

//4.全部的方法
public Method[] getDeclaredMethods()
//返回此Class对象所表示的类或接口的全部方法
public Method[] getMethods()  
//返回此Class对象所表示的类或接口的public的方法

//Method类中:
public Class<?> getReturnType()
//取得全部的返回值
public Class<?>[] getParameterTypes()
//取得全部的参数
public int getModifiers()
//取得修饰符
public Class<?>[] getExceptionTypes()
//取得异常信息

//5.全部的Field
public Field[] getFields() 
//返回此Class对象所表示的类或接口的public的Field。
public Field[] getDeclaredFields() 
//返回此Class对象所表示的类或接口的全部Field。

//Field方法中:
public int getModifiers()
//以整数形式返回此Field的修饰符
public Class<?> getType()  
//得到Field的属性类型
public String getName()  
//返回Field的名称。

//6. Annotation相关
get Annotation(Class<T> annotationClass) 
getDeclaredAnnotations() 

//7.泛型相关
//获取父类泛型类型:
Type getGenericSuperclass()
//泛型类型:ParameterizedType
//获取实际的泛型类型参数数组:
getActualTypeArguments()

//8.类所在的包
Package getPackage() 

2.2 获取所有的属性及相关细节

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

import org.junit.Test;

import com.example.java1.Person;

public class FieldTest {
	
    @Test
    public void test1(){
        
        Class clazz = Person.class;
        //getFields():获取到运行时类本身及其所有的父类中声明为public权限的属性
    //		Field[] fields = clazz.getFields();
    //
    //		for(Field f : fields){
    //			System.out.println(f);
    //		}
        
        //getDeclaredFields():获取当前运行时类中声明的所有属性,包括 private的属性
        Field[] declaredFields = clazz.getDeclaredFields();
        for(Field f : declaredFields){
            System.out.println(f);
        }
    }
	
	//权限修饰符  变量类型  变量名
    @Test
    public void test2(){
        Class clazz = Person.class;
        Field[] declaredFields = clazz.getDeclaredFields();
        for(Field f : declaredFields){
            //1.权限修饰符
            /*
            * 0x是十六进制
            * PUBLIC           = 0x00000001;  1    1
            * PRIVATE          = 0x00000002;  2	10
            * PROTECTED        = 0x00000004;  4	100
            * STATIC           = 0x00000008;  8	1000
            * FINAL            = 0x00000010;  16	10000
            * ...
            *
            * 设计的理念,就是用二进制的某一位是1,来代表一种修饰符,整个二进制中只有一位是1,其余都是0
            *
            * mod = 17          0x00000011
            * if ((mod & PUBLIC) != 0)  说明修饰符中有public
            * if ((mod & FINAL) != 0)   说明修饰符中有final
            */
            int modifier = f.getModifiers();
            System.out.print(Modifier.toString(modifier) + "\t");

//            //2.数据类型
            Class type = f.getType();
            System.out.print(type.getName() + "\t");
//
//            //3.变量名
            String fName = f.getName();
            System.out.print(fName);
//
            System.out.println();
        }
    }
}

2.3 获取所有的方法及相关细节

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import org.junit.Test;

import com.example.java1.Person;

public class MethodTest {

    @Test
    public void test1() {

        Class clazz = Person.class;
        // getMethods():获取到运行时类本身及其所有的父类中声明为public权限的方法
        // Method[] methods = clazz.getMethods();
        //
        // for(Method m : methods){
        // System.out.println(m);
        // }

        // getDeclaredMethods():获取当前运行时类中声明的所有方法
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m : declaredMethods) {
            System.out.println(m);
        }
    }

    // 注解信息
    // 权限修饰符 返回值类型 方法名(形参类型1 参数1,形参类型2 参数2,...) throws 异常类型1,...{}
    @Test
    public void test2() {
        Class clazz = Person.class;
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m : declaredMethods) {
            // 1.获取方法声明的注解
            Annotation[] annos = m.getAnnotations();
            for (Annotation a : annos) {
                System.out.println(a);
            }

            // 2.权限修饰符
            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();
        }
    }
}

2.4 获取其他结构(构造器、父类、接口、包、注解等)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.java2;

import com.example.java1.Person;
import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class OtherTest {

    /*
    	获取当前类中的所有的构造器(包括私有构造器)
     */
    @Test
    public void test1(){
        Class clazz = Person.class;
        Constructor[] cons = clazz.getDeclaredConstructors();
        for(Constructor c :cons){
            System.out.println(c);
        }
    }
    /*
    	获取运行时类的父类
     */
    @Test
    public void test2(){
        Class clazz = Person.class;
        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);//class com.example.java1.Creature
    }
    /*
    	获取运行时类的所在的包
     */
    @Test
    public void test3(){
        Class clazz = Person.class;
        Package pack = clazz.getPackage();
        System.out.println(pack);

    }
    /*
    	获取运行时类的注解
     */
    @Test
    public void test4(){
        Class clazz = Person.class;
        Annotation[] annos = clazz.getAnnotations();
        for (Annotation anno : annos) {
            System.out.println(anno);
        }
    }

    /*
    	获取运行时类所实现的接口
     */
    @Test
    public void test5(){
        Class clazz = Person.class;
        Class[] interfaces = clazz.getInterfaces();
        for (Class anInterface : interfaces) {
            System.out.println(anInterface);
        }
    }
    /*
    	获取运行时类的带泛型的父类
     */
    @Test
    public void test6(){
        Class clazz = Person.class;
        Type genericSuperclass = clazz.getGenericSuperclass();
        System.out.println(genericSuperclass);//com.example.java1.Creature<java.lang.String>
    }
}

2.5 获取泛型父类信息

示例代码获取泛型父类信息:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/* Type:
 * (1)Class
 * (2)ParameterizedType   
 * 		例如:Father<String,Integer>
 * 			ArrayList<String>
 * (3)TypeVariable
 * 		例如:T,U,E,K,V
 * (4)WildcardType
 * 		例如:
 * 		ArrayList<?>
 * 		ArrayList<? super 下限>
 * 		ArrayList<? extends 上限>
 * (5)GenericArrayType
 * 		例如:T[]
 * 	
 */
public class TestGeneric {
    public static void main(String[] args) {
        //需求:在运行时,获取Son类型的泛型父类的泛型实参<String,Integer>
        
        //(1)还是先获取Class对象
        Class clazz = Son.class;//四种形式任意一种都可以
        
        //(2)获取泛型父类
        //  Class sc = clazz.getSuperclass();
        //  System.out.println(sc);
        /*
        * getSuperclass()只能得到父类名,无法得到父类的泛型实参列表
        */
        Type type = clazz.getGenericSuperclass();
        
        // Father<String,Integer>属于ParameterizedType
        ParameterizedType pt = (ParameterizedType) type;
        
        //(3)获取泛型父类的泛型实参列表
        Type[] typeArray = pt.getActualTypeArguments();
        for (Type type2 : typeArray) {
            System.out.println(type2);
        }
    }
}
//泛型形参:<T,U>
class Father<T,U>{
	
}
//泛型实参:<String,Integer>
class Son extends Father<String,Integer>{
	
}

2.6 获取内部类或外部类信息

public Class<?>[] getClasses():返回所有公共内部类和内部接口。包括从超类继承的公共类和接口成员以及该类声明的公共类和接口成员。

public Class<?>[] getDeclaredClasses():返回 Class 对象的一个数组,这些对象反映声明为此 Class 对象所表示的类的成员的所有类和接口。包括该类所声明的公共、保护、默认(包)访问及私有类和接口,但不包括继承的类和接口。

public Class<?> getDeclaringClass():如果此 Class 对象所表示的类或接口是一个内部类或内部接口,则返回它的外部类或外部接口,否则返回null。

Class<?> getEnclosingClass() :返回某个内部类的外部类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void test5(){
    Class<?> clazz = Map.class;
    Class<?>[] inners = clazz.getDeclaredClasses();
    for (Class<?> inner : inners) {
        System.out.println(inner);
    }
    
    Class<?> ec = Map.Entry.class;
    Class<?> outer = ec.getDeclaringClass();
    System.out.println(outer);
}

2.7 总 结

  1. 了解了反射这么多API,其实在实际的操作中,通过反射获取类的信息的操作代码,并不会经常开发,在框架的设计中才会被频繁使用。
  2. 主要要熟悉java.lang.reflect包的作用,反射机制。

3. 调用运行时类的指定结构

3.1 调用指定的属性

在反射机制中,可以直接通过Field类操作类中的属性,通过Field类提供的set()get()方法就可以完成设置和取得属性内容的操作。

(1)获取该类型的Class对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Class clazz = Class.forName("包.类名");

(2)获取属性对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Field field = clazz.getDeclaredField("属性名");

(3)如果属性的权限修饰符不是public,那么需要设置属性可访问

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
field.setAccessible(true);

(4)创建实例对象:如果操作的是非静态属性,需要创建实例对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Object obj = clazz.newInstance(); //有公共的无参构造

Object obj = 构造器对象.newInstance(实参...);//通过特定构造器对象创建实例对象

(4)设置指定对象obj上此Field的属性内容

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
field.set(obj,"属性值");

如果操作静态变量,那么实例对象可以省略,用null表示

(5)取得指定对象obj上此Field的属性内容

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Object value = field.get(obj);

如果操作静态变量,那么实例对象可以省略,用null表示

示例代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.reflect;

public class Student {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.reflect;

import java.lang.reflect.Field;

public class TestField {
    public static void main(String[] args)throws Exception {
        //1、获取Student的Class对象
        Class clazz = Class.forName("com.example.reflect.Student");

        //2、获取属性对象,例如:id属性
        Field idField = clazz.getDeclaredField("id");

        //3、如果id是私有的等在当前类中不可访问access的,我们需要做如下操作
        idField.setAccessible(true);

        //4、创建实例对象,即,创建Student对象
        Object stu = clazz.newInstance();

        //5、获取属性值
        /*
         * 以前:int 变量= 学生对象.getId()
         * 现在:Object id属性对象.get(学生对象)
         */
        Object value = idField.get(stu);
        System.out.println("id = "+ value);

        //6、设置属性值
        /*
         * 以前:学生对象.setId(值)
         * 现在:id属性对象.set(学生对象,值)
         */
        idField.set(stu, 2);

        value = idField.get(stu);
        System.out.println("id = "+ value);
    }
}

3.2 调用指定的方法

(1)获取该类型的Class对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Class clazz = Class.forName("包.类名");

(2)获取方法对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Method method = clazz.getDeclaredMethod("方法名",方法的形参类型列表);

(3)创建实例对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Object obj = clazz.newInstance();

(4)调用方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Object result = method.invoke(obj, 方法的实参值列表);

如果方法的权限修饰符修饰的范围不可见,也可以调用setAccessible(true) 如果方法是静态方法,实例对象也可以省略(写上也没问题),用null代替

示例代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.reflect;

import org.junit.Test;

import java.lang.reflect.Method;

public class TestMethod {
    @Test
    public void test()throws Exception {
        // 1、获取Student的Class对象
        Class<?> clazz = Class.forName("com.example.reflect.Student");

        //2、获取方法对象
        /*
         * 在一个类中,唯一定位到一个方法,需要:(1)方法名(2)形参列表,因为方法可能重载
         *
         * 例如:void setName(String name)
         */
        Method setNameMethod = clazz.getDeclaredMethod("setName", String.class);

        //3、创建实例对象
        Object stu = clazz.newInstance();

        //4、调用方法
        /*
         * 以前:学生对象.setName(值)
         * 现在:方法对象.invoke(学生对象,值)
         */
        Object setNameMethodReturnValue = setNameMethod.invoke(stu, "张三");

        System.out.println("stu = " + stu);
        //setName方法返回值类型void,没有返回值,所以setNameMethodReturnValue为null
        System.out.println("setNameMethodReturnValue = " + setNameMethodReturnValue);

        Method getNameMethod = clazz.getDeclaredMethod("getName");
        Object getNameMethodReturnValue = getNameMethod.invoke(stu);
        //getName方法返回值类型String,有返回值,getNameMethod.invoke的返回值就是getName方法的返回值
        System.out.println("getNameMethodReturnValue = " + getNameMethodReturnValue);//张三
    }

    @Test
    public void test02()throws Exception{
        Class<?> clazz = Class.forName("com.example.ext.demo.Student");
        Method printInfoMethod = clazz.getMethod("printInfo", String.class);
        //printInfo方法是静态方法
        printInfoMethod.invoke(null,"北大");
    }
}

3.3 关于setAccessible方法的使用

  • MethodFieldConstructor对象都有setAccessible()方法。
  • setAccessible启动和禁用访问安全检查的开关。
  • 参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。
    • 提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true
    • 使得原本无法访问的私有成员也可以访问
  • 参数值为false则指示反射的对象应该实施Java语言访问检查。

4. 读取注解信息

一个完整的注解应该包含三个部分: (1):声明 (2):使用 (3):读取

4.1 声明自定义注解

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.annotation;

import java.lang.annotation.*;

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
    String value();
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.annotation;

import java.lang.annotation.*;

@Inherited
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    String columnName();
    String columnType();
}
  • 自定义注解可以通过四个元注解@Retention@Target@Inherited@Documented,分别说明它的声明周期,使用位置,是否被继承,是否被生成到API文档中。
  • Annotation 的成员在 Annotation 定义中以无参数有返回值的抽象方法的形式来声明,我们又称为配置参数。返回值类型只能是八种基本数据类型、String类型Class类型enum类型Annotation类型、以上所有类型的数组
  • 可以使用 default 关键字为抽象方法指定默认返回值
  • 如果定义的注解含有抽象方法,那么使用时必须指定返回值,除非它有默认值。格式是“方法名 = 返回值”,如果只有一个抽象方法需要赋值,且方法名为value,可以省略“value=”,所以如果注解只有一个抽象方法成员,建议使用方法名value。

4.2 使用自定义注解

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.annotation;

@Table("t_stu")
public class Student {
    @Column(columnName = "sid",columnType = "int")
    private int id;
    @Column(columnName = "sname",columnType = "varchar(20)")
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

4.3 读取和处理自定义注解

自定义注解必须配上注解的信息处理流程才有意义。

我们自己定义的注解,只能使用反射的代码读取。所以自定义注解的声明周期必须是RetentionPolicy.RUNTIME

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.annotation;

import java.lang.reflect.Field;

public class TestAnnotation {
    public static void main(String[] args) {
        Class studentClass = Student.class;
        Table tableAnnotation = (Table) studentClass.getAnnotation(Table.class);
        String tableName = "";
        if(tableAnnotation != null){
            tableName = tableAnnotation.value();
        }

        Field[] declaredFields = studentClass.getDeclaredFields();
        String[] columns = new String[declaredFields.length];
        int index = 0;
        for (Field declaredField : declaredFields) {
            Column column = declaredField.getAnnotation(Column.class);
            if(column!= null) {
                columns[index++] = column.columnName();
            }
        }
        
        String sql = "select ";
        for (int i=0; i<index; i++) {
            sql += columns[i];
            if(i<index-1){
                sql += ",";
            }
        }
        sql += " from " + tableName;
        System.out.println("sql = " + sql);
    }
}

5. 体会反射的动态性

体会1:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ReflectionTest {

    //体会反射的动态性:动态的创建给定字符串对应的类的对象
    public <T> T getInstance(String className) throws Exception {

        Class clazz = Class.forName(className);

        Constructor constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        return (T) constructor.newInstance();

    }

    @Test
    public void test1() throws Exception {
        String className = "com.example.java1.Person";
        Person p1 = getInstance(className);
        System.out.println(p1);
    }
}

体会2:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ReflectionTest {
    //体会反射的动态性:动态的创建指定字符串对应类的对象,并调用指定的方法
    public Object  invoke(String className,String methodName) throws Exception {
        Class clazz = Class.forName(className);
        Constructor constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        //动态的创建指定字符串对应类的对象
        Object obj = constructor.newInstance();

        Method method = clazz.getDeclaredMethod(methodName);
        method.setAccessible(true);
        return method.invoke(obj);
    }

    @Test
    public void test2() throws Exception {
        String info = (String) invoke("com.example.java1.Person", "show");

        System.out.println("返回值为:" + info);

    }
}

体会3:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ReflectionTest {
	@Test
    public void test1() throws Exception {
        //1.加载配置文件,并获取指定的fruitName值
        Properties pros = new Properties();
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("config.properties");
        pros.load(is);
        String fruitStr = pros.getProperty("fruitName");
        //2.创建指定全类名对应类的实例
        Class clazz = Class.forName(fruitStr);
        Constructor constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        Fruit fruit = (Fruit) constructor.newInstance();
        //3. 调用相关方法,进行测试
        Juicer juicer = new Juicer();
        juicer.run(fruit);

    }

}

interface Fruit {
	public void squeeze();
}

class Apple implements Fruit {
	public void squeeze() {
		System.out.println("榨出一杯苹果汁儿");
	}
}

class Orange implements Fruit {
	public void squeeze() {
		System.out.println("榨出一杯桔子汁儿");
	}
}

class Juicer {
	public void run(Fruit f) {
		f.squeeze();
	}
}

其中,配置文件【config.properties】存放在当前Module的src下

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-05-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Java 反射机制深度剖析:原理、用法与实战
Java 是一种强类型语言,一般在编译期确定类型。但在某些场景中,我们希望在运行时动态获取类的信息,甚至动态创建对象、调用方法或访问字段。
用户11690571
2025/06/06
1360
Java注解的介绍和反射使用
java注解==(Annotation)==,又称为java标注,是jdk5.0引入的一种机制。
半月无霜
2023/03/03
3780
Java之反射
Reflection(反射) 是被视为动态语言的关键,反射的机制允许程序在执行期间借助 Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性方法。
OY
2022/03/12
2470
Java之反射
Java基础(二十三):反射机制
(1)class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类 (2)interface:接口 (3)[]:数组 (4)enum:枚举在这里插入代码片 (5)annotation:注解@interface (6)primitive type:基本数据类型 (7)void
Java微观世界
2025/01/21
1250
Java基础(二十三):反射机制
利用反射技术提升Java应用的灵活性和可扩展性
结论:**同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个**。
杨不易呀
2023/09/26
2300
利用反射技术提升Java应用的灵活性和可扩展性
Java 反射深入浅出
Java Reflection(反射) 被视为动态语言的关键,Java并不是动态语言,但因为反射Java可以被称为准动态语言
Java_慈祥
2024/08/06
1570
Java 反射深入浅出
Java程序设计(高级及专题)- 类的加载和反射[通俗易懂]
大家好,又见面了,我是你们的朋友全栈君。 加载器 类加载器就是可以从其作用来理解,其功能就是将classpath目录下.class文件,加载到内存中来进行一些处理,处理完的结果就是一些字节码
全栈程序员站长
2022/08/04
4010
Java程序设计(高级及专题)- 类的加载和反射[通俗易懂]
java反射原理
  简单来说,反射可以帮助我们在动态运行的时候,对于任意一个类,可以获取其所有的方法(包括public、protected、private和默认状态的),所有的变量(包括public、protected、private和默认状态的)。
Java阿呆
2020/11/04
6010
java反射原理
java的反射(reflection)机制_腹部反射区图解
在运行时,判断任意一个类的完整结构,比如属性,方法,内部类,实现接口等
全栈程序员站长
2022/11/18
2850
java的反射(reflection)机制_腹部反射区图解
java之反射机制
假设现在我们有一张动漫的图片,我们通过这张图片,在大脑中搜索有关记忆,就清楚这张图片是什么动漫里的谁;假设我们现在有一个名字,在大脑中搜索有关记忆,就自然而然地想到了该名字人物的具体形象,这种思维过程就是反射。
西西嘛呦
2020/08/26
3220
Java反射真正的详解,学以致用,实战案例,近万字长文,不读后悔
全文共 7500 字左右,案例均可运行,阅读时间大约需要20分钟左右,如有问题,请留言或发送邮件(nzc_wyh@163.com)。
宁在春
2022/10/31
7190
Java反射真正的详解,学以致用,实战案例,近万字长文,不读后悔
Java反射详解
这样的需求在学习框架时特别多,即通过外部文件配置,在不修改源码情况下。来控制程序,也符合设计模式的ocp原则(开闭原则:不修改源码,扩容功能)。
timerring
2023/05/24
3430
Java反射详解
Java 中的反射与注解
Class 元类是对普通类的抽象,是类的类。Class 包含了一个类的所有属性,包括类名、包名、父类、实现的接口、所有方法、属性等。拿到一个类的 Class 元类,就拿到了这个类所有信息,就可以通过这些信息动态做一些处理。
菜皮日记
2023/12/18
1820
Java 反射详解
反射(Reflection)能够让运行于 JVM 中的程序检测和修改运行时的行为。
Yano_nankai
2018/10/08
3550
大数据必学Java基础(九十):通过反射获取运行时类的完整结构
问题1:创建Person的对象,以后用new Person()创建,还是用反射创建?
Lansonli
2022/12/13
5210
大数据必学Java基础(九十):通过反射获取运行时类的完整结构
深入分析Java反射(一)-核心类库和方法
Java反射的API在JavaSE1.7的时候已经基本完善,但是本文编写的时候使用的是Oracle JDK11,因为JDK11对于sun包下的源码也上传了,可以直接通过IDE查看对应的源码和进行Debug。
Throwable
2020/06/23
9740
反射入门_入门教程
类(外部类,内部类,匿名内部类等等),接口,数组,enum,注解,基本数据类型 ,void都算Class对象
全栈程序员站长
2022/09/21
2610
一起学JAVA 反射学习(超详细)
Reflection(反射) 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,也有称作“自省”。 反射非常强大,它甚至能直接操作程序的私有属性。我们前面学习都有一个概念,被private封装的资源只能类内部访问,外部是不行的,但这个规定被反射赤裸裸的打破了。 反射就像一面镜子,它可以在运行时获取一个类的所有信息,可以获取到任何定义的信息(包括成员变量,成员方法,构造器等),并且可以操纵类的字段、方法、构造器等部分。
全栈程序员站长
2022/07/01
3510
一起学JAVA 反射学习(超详细)
关于Java中泛型、反射和注解的扫盲篇
  泛型是在JDK1.5之后引入的,旨在让我们写出更加通用化,更加灵活的代码。通用化的手段在于让数据类型变得参数化,定义泛型时,对应的数据类型是不确定的,泛型方法被调用时,会指定具体类型,其核心目标是为了解决容器类型在编译时安全检查的问题。   泛型:一般用在类、方法、接口中,叫做泛型类、泛型接口、泛型方法
程序员波特
2024/01/19
2730
java中的反射
  –对象照镜子后可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。
全栈程序员站长
2022/09/06
1.8K0
java中的反射
相关推荐
Java 反射机制深度剖析:原理、用法与实战
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验