V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
OldCarMan
V2EX  ›  Java

请问一下,在实现 spring 的 FactoryBean 时,如何得到类成员方法里某个局部变量的真实类型?

  •  
  •   OldCarMan · 2023-05-21 09:39:14 +08:00 · 1523 次点击
    这是一个创建于 546 天前的主题,其中的信息可能已经有所发展或是发生改变。

    rt,代码逻辑大概是这样:

    public class MyFactoryBean implements FactoryBean<MyBean> {
    
        private String myProperty;
    
        public void setMyProperty(String myProperty) {
            this.myProperty = myProperty;
        }
    
        @Override
        public MyBean getObject() throws Exception {
            return createBean(); 
        }
    
    
        public MyBean createBean(){
        	MyBean myBean = new MyBean();
        	myBean.setProperty(myProperty);
            
            //下面 UserListener 调试时,UserListener 对象的类型是“MyFactoryBean$$Lambda$400/0x0000000800e9b558@4225”
            
    	UserListener<User1> userListener=new UserListener<User1>(){
    		@Override
    		public void active(){
    			//doSomething
    		}
    	};
        	Cache.addUserListener(userListener);
    	return myBean;
        }
    
        @Override
        public Class<?> getObjectType() {
            return MyBean.class;
        }
    
        @Override
       public boolean isSingleton() {
            return true;
        }
    }
    
    • 在传递UserListener时,发现传递的不是 UserListener 实例的具体类型(UserListener 是一个泛型接口),而是一个
    MyFactoryBean$$Lambda$400/0x0000000800e9b558@4225
    

    代理对象,请问有什么方式能直接得到该类具体的类型吗?除了把对象类型一并传过去

     Cache.addUserListener(userListener,User1.class);
    
    • ps: 😅哈哈,框架还不是很熟,大家尽管吐槽指正,谢谢大家回复!
    第 1 条附言  ·  2023-05-23 02:29:10 +08:00

    哈哈😂,问了下chatgpt,它说runtime时没法直接得到这个泛型,提供的思路跟我说的基本一样,就是在添加时,把类型传过去。

    I understand. In Java, due to type erasure, it is not possible to directly obtain the type parameter T at runtime. However, you can work around this limitation by passing a Class<T> object as a parameter to the addUserListener method. Here's an example of how you can modify the Cache class to achieve this:
    
    
    public class Cache {
        public static <T extends User> void addUserListener(UserListener<T> userListener, Class<T> userType) {
            // implementation of the method goes here
            System.out.println("User type is: " + userType.getSimpleName());
        }
    }
    
    4 条回复    2023-05-23 01:25:17 +08:00
    letsky
        1
    letsky  
       2023-05-21 10:33:12 +08:00
    试试 Spring 的这个类,https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/ResolvableType.html

    ```java
    private HashMap<Integer, List<String>> myMap;

    public void example() {
    ResolvableType t = ResolvableType.forField(getClass().getDeclaredField("myMap"));
    t.getSuperType(); // AbstractMap<Integer, List<String>>
    t.asMap(); // Map<Integer, List<String>>
    t.getGeneric(0).resolve(); // Integer
    t.getGeneric(1).resolve(); // List
    t.getGeneric(1); // List<String>
    t.resolveGeneric(1, 0); // String
    }
    ```
    luckykev1n
        2
    luckykev1n  
       2023-05-21 11:27:18 +08:00
    不考虑 spring 的话,可以用反射
    public class Main {
    public static void main(String[] args) {
    UserListener<String> userListener = new UserListener<String>() {};
    // 获取实际类型
    Class<? extends UserListener> listenerClass = userListener.getClass();

    // 获取实际范型
    Type[] interfaces = listenerClass.getGenericInterfaces();
    Type listenerType = interfaces[0];
    ParameterizedType paraType = (ParameterizedType) listenerType;
    Type[] actualTypes = paraType.getActualTypeArguments();
    Class<?> actualType = (Class<?>) actualTypes[0];

    // 打印实际范型
    System.out.println(actualType);

    }
    }
    luckykev1n
        3
    luckykev1n  
       2023-05-21 11:30:56 +08:00
    1 楼的这个 ResolvableType ,其实也是 Spring 基于 java 的反射实现的,
    ```
    public ResolvableType[] getGenerics() {
    if (this == NONE) {
    return EMPTY_TYPES_ARRAY;
    }
    if (this.generics == null) {
    if (this.type instanceof Class) {
    Class<?> typeClass = (Class<?>) this.type;
    this.generics = forTypes(SerializableTypeWrapper.forTypeParameters(typeClass), this.variableResolver);
    }
    else if (this.type instanceof ParameterizedType) {
    Type[] actualTypeArguments = ((ParameterizedType) this.type).getActualTypeArguments();
    ResolvableType[] generics = new ResolvableType[actualTypeArguments.length];
    for (int i = 0; i < actualTypeArguments.length; i++) {
    generics[i] = forType(actualTypeArguments[i], this.variableResolver);
    }
    this.generics = generics;
    }
    else {
    this.generics = resolveType().getGenerics();
    }
    }
    return this.generics;
    }
    OldCarMan
        4
    OldCarMan  
    OP
       2023-05-23 01:25:17 +08:00
    @letsky 谢谢回复
    @luckykev1n 谢谢回复,你 2 楼回复的:
    ParameterizedType paraType = (ParameterizedType) listenerType;
    类型无法转换( java.lang.ClassCastException: class java.lang.Class cannot be cast to class java.lang.reflect.ParameterizedType )。

    1.

    2.

    3.


    可能我没描述好,我说的是,我在另外一个类 Cache.java 里面接收 UserListener 时,无法获取到泛型接口 UserListener<T extends User>相应的泛型 T 类型:
    public class Cache{
    -----

    public static void addUserListener(UserListener<T extends User> userListener){

    在这里无法直接获取得到 userListener 的相应的泛型 T 类型

    }

    -----

    }
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2704 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 11:03 · PVG 19:03 · LAX 03:03 · JFK 06:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.