【问题标题】:Return a class, not an instance, of a concrete class that extends an abstract base class?返回扩展抽象基类的具体类的类而不是实例?
【发布时间】:2018-05-28 19:17:47
【问题描述】:

如果我有这样的类层次结构

AbstractSuperClass
    ConcreteClassA
    ConcreteClassB

是否有可能在AbstractSuperClass 中有一个静态方法,它返回两个具体类之一的类而不是实例?

我尝试返回 Class<AbstractSuperClass>,但 IDE (Android Studio) 说

Incompatible types.
Required: Class <com.example.AbstractSuperClass>
Found:    Class <com.example.ConcreteClassA>

这是我在想的一个例子,但它不起作用:

public abstract class AbstractSuperClass{

    public abstract void someAbstractMethod();


    public static String getSomeText(){ 
        return "This is AbstractSuperClass"; 
    };

    public static Class<AbstractSuperClass> getConcreteClass(int x){
        switch( x ){
            case 0: return ConcreteClassA.class;
            case 1: return ConcreteClassB.class;
        }
    }
}


public class ConcreteClassA extends AbstractSuperClass{
    public abstract void someAbstractMethod(){
        // Do something
    }

    public static String getSomeText(){ 
        return "This is ConcreteClassA"; 
    };
}



public class ConcreteClassB extends AbstractSuperClass{
    public abstract void someAbstractMethod(){
        // Do something
    }

    public static String getSomeText(){ 
        return "This is ConcreteClassB"; 
    };
}



AbstractSuperClass.getConcreteClass(1).getSomeText(); // Should return "This is ConcreteClassB"

这在 Java 中是不可能的,还是我做错了?

【问题讨论】:

  • 改成Class&lt;? extends AbstractSuperClass&gt;

标签: java class reflection


【解决方案1】:

您不能像您尝试做的那样直接从Class 调用static 方法,您需要反射来调用您的getSomeText() 方法。喜欢,

try {
    Method m = AbstractSuperClass.getConcreteClass(1).getMethod("getSomeText", 
            new Class[0]);
    System.out.println(m.invoke(null, new Object[0]));
} catch (Exception e) {
    e.printStackTrace();
}

然后您可以使用 capture-of extends AbstractSuperClass (生产者扩展,消费者超级)修复您的 getConcreteClass 方法。对于没有匹配项的情况,您必须有一个默认返回。喜欢,

public static Class<? extends AbstractSuperClass> getConcreteClass(int x) {
    switch (x) {
    case 0: return ConcreteClassA.class;
    case 1: return ConcreteClassB.class;
    }
    return null;
}

我跑了(并得到了)

This is ConcreteClassB

【讨论】:

    【解决方案2】:

    对于这个方法,

    public Class<AbstractSuperClass> getConcreteClass(int x){
        switch( x ){
            case 0: return ConcreteClassA.class;
            case 1: return ConcreteClassB.class;
        }
    }
    

    签名应该是

    public Class<? extends AbstractSuperClass> getConcreteClass(int x)
    

    这意味着返回值可以是AbstractSuperClass.class或其任何子类型。

    【讨论】:

      【解决方案3】:

      我不确定它需要什么,但您的代码中有几个问题。

      1. 您不能返回 Class,因为您正在返回一个扩展 AbstractSuperClass 的类。所以你必须通知编译器并将返回类型更改为 Class
      2. 您不能直接从类中调用 any(不管是静态方法还是非静态方法)。您需要使用反射 API,因此您的方法调用将如下所示:

        final Class clazz = AbstractSuperClass.getConcreteClass(1); 对象结果 = clazz.getMethod("getSomeText").invoke(clazz);

      这就是你类的完整代码。

      package com.mycompany.sandbox;
      
      import java.lang.reflect.InvocationTargetException;
      import java.util.Objects;
      import java.util.logging.Level;
      import java.util.logging.Logger;
      
      
      abstract class AbstractSuperClass{
      
          public abstract void someAbstractMethod();
      
      
          public static String getSomeText(){ 
              return "This is AbstractSuperClass"; 
          };
      
          public static Class<? extends AbstractSuperClass> getConcreteClass(int x){
              switch( x ){
                  case 0: return ConcreteClassA.class;
                  case 1: return ConcreteClassB.class;
              }
            return null;
          }
      }
      
      
      class ConcreteClassA extends AbstractSuperClass{
          public void someAbstractMethod(){
              // Do something
          }
      
          public static String getSomeText(){ 
              return "This is ConcreteClassA"; 
          };
      }
      
      
      
      class ConcreteClassB extends AbstractSuperClass{
          public void someAbstractMethod(){
              // Do something
          }
      
          public static String getSomeText(){ 
              return "This is ConcreteClassB"; 
          };
      }
      
      
      
      
      // one class needs to have a main() method
      public class HelloWorld
      {
        // arguments are passed using the text field below this editor
        public static void main(String args[])
        {
            try {
                final Class<? extends AbstractSuperClass> clazz = AbstractSuperClass.getConcreteClass(1);
                Object result = clazz.getMethod("getSomeText").invoke(clazz);
                System.out.println(Objects.toString(result, "<NULL>"));
            } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
                Logger.getLogger(HelloWorld.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
      }
      

      【讨论】:

        【解决方案4】:

        试试这个:

        public abstract class AbstractSuperClass {
        
            public abstract void someAbstractMethod();
        
            public static String getSomeText() { 
                return "This is AbstractSuperClass"; 
            };
        
            public Class<? extends AbstractSuperClass> getConcreteClass() {
                return this.getClass();
            }
        }
        

        事实上,您不需要int 参数,因为子类的实例无需提示即可知道其类型。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-11-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-20
          • 2012-05-03
          相关资源
          最近更新 更多