Вернуть класс, а не экземпляр конкретного класса, который расширяет абстрактный базовый класс? - PullRequest
0 голосов
/ 28 мая 2018

Если у меня есть иерархия классов, подобная этой

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 или я просто делаю это неправильно?

Ответы [ 4 ]

0 голосов
/ 28 мая 2018

Я не уверен, для чего это нужно, но в вашем коде есть несколько проблем.

  1. Вы не можете вернуть Class, потому что вы возвращаете класс, который расширяет AbstractSuperClass.Поэтому вы должны сообщить об этом компилятору и изменить тип возвращаемого значения на Class
  2. . Вы не можете вызывать any (не имеет значения статический или не статический метод) напрямую из класса.Вам нужно использовать API отражений, поэтому вызов метода будет выглядеть следующим образом:

    final Class clazz = AbstractSuperClass.getConcreteClass (1);Object result = 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);
      }
  }
}
0 голосов
/ 28 мая 2018

Для этого метода

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 или любым его подтипом.

0 голосов
/ 28 мая 2018

Вы не можете вызвать метод static напрямую из Class, как вы пытаетесь это сделать, вам понадобится рефлексия для вызова вашего 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();
}

Затем вы можете исправить свой метод getConcreteClass, используя метод capture-of extends AbstractSuperClass (производитель extends, потребитель super).И вы должны иметь возврат по умолчанию для случая, когда ничего не совпадает.Мол,

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
0 голосов
/ 28 мая 2018

Попробуйте это:

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, поскольку экземпляр подкласса будет знать его тип без подсказки.

...