如何创建给定超类的每个子类的实例?

How can I create instances of every subclass of a given superclass?

我有几个抽象类,每个都有几个子类。我想创建每个子类的实例,而不必 copy/paste 本质上可能是数百行的相同代码,因为随着程序变得越来越复杂,子 类 的数量也在增加。

对于每个给定的抽象超类,子类实例将包含在 Map(特别是 HashMap)中。 类(super 和 sub)都有不带参数的构造函数。

我在十年前看到这个问题的答案说这是不可能的(或者,至少,不可取)。我希望情况有所改变,但我一直无法找到更新的答案。

编辑:由于显然我的问题不够清楚,这里有一个 example 代码(强调 example;这两者都不是MWE 也不是我实际拥有的代码):

public abstract class A {
    public abstract void setName(String s);
    public abstract String getName();
}

public class B extends A {
    private String name = "B";

    public String getName() {
        return name;
    }

    public void setName(String s) {
        name = s;
    }
}

public class C extends A {
    private int count = 0;
    private String name = "C";

    public void increaseCount() {
        count++;
    }

    public String getName() {
        return name;
    }

    public void setName(String s) {
        name = s;
    }
}

public class Base {
    private Map<String, A> list;

    public Base() {
        list = new HashMap<>();
        A b = new B();
        list.put(b.getName(), b);
        A c = new C();
        list.put(c.getName(), c);
    }
}

public class Phone {
    private Map<String, A> list;

    public Phone() {
        list = new HashMap<>();
        A b = new B();
        list.put(b.getName(), b);
        A c = new C();
        list.put(c.getName(), c);
    }
}

我想避免您在 BasePhone 的构造函数中看到的情况。与其每次都创建一个新实例然后添加它 "by hand",这将花费大量的时间和精力,我宁愿使用一种自动化的方式来做到这一点,如果存在的话。

直接的,你不能,但间接的,你可以。

也许是 "several lines of code, you mention".

的更短版本

您已经用 Map 回答了自己,您需要明确、存储或注册每个非抽象后代。

这通常称为 "data dictionary" 或 "metadata dictionary",您需要一个集合来保存一些数据才能执行此操作。

有一个叫做 "type reflection" 的东西,它提供了特殊的 classes 和对象方法,比如 getSimpleName( )getClass( )getSuperClass( )

您可以开始声明一个非抽象的 class 来分配 map 变量,更像是 class:

这样的程序
import java.utils.map;

public class SubclassesList
{

  public static Main (...)
  {
     Map<string, Pair<object, string>> AMap =
       new Map<string, Pair<object, string>( );

     // ...

     Map = null;
   } // main

} // public class

稍后,定义一个非抽象 class,它将作为所有其他子classes 的基础。

public /* nonabstract */ class Monster
{
    public JustDoSomething( )
    {
      System.out.println(this.getClass(  ).getSimpleName( ));
    }
} // Monster

要列出的所有 classes 都需要能够从此 class.

派生

接下来,作为示例,让我们从这个 Monster 中获得非抽象子class,我们不会添加任何与列表相关的额外代码,而是添加特定代码。

public /* nonabstract */ class DireWolf 
  inherits Monster
{

  public void EatGrannies ( ) {  }

} // class

public /* nonabstract */ class Dragon
  inherits Monster
{

  public void SpitFire ( ) {  }

} // class

public /* nonabstract */ class Kraken
  inherits Monster
{

  public void CrashSeaShips( ) {  }

} // class

public /* nonabstract */ class Kitty
  inherits Monster
{

  public void Mischief ( ) {  }

} // class

稍后,我们需要将这些 class 添加到 "Data Dictionary" 映射中。

import java.utils.map;

public class SubclassesList
{

  public void RegisterMonster
     (Map AMap, Monster Item)
  {
      Map.put(Item.getClass( ).getSimpleName(),
         new Pair(Item, Item.getClass( ).getSuperClass( ).getSimpleName( )));

  } //

  public static Main (...)
  {
     Map<string, Pair<Monster, string>> AMap =
       new Map<string, Pair<Monster, string>>( );

     this.RegisterMonster(new DireWolf( ));
     this.RegisterMonster(new Dragon( ));
     this.RegisterMonster(new Kraken( ));
     this.RegisterMonster(new Kitty( ));

     AMap = null;
   } // main

} // public class

稍后,拆分注册部分,从列表中。

import java.utils.map;

public class SubclassesList
{

  public void RegisterMonster
     (Map<string, Pair<Monster, string>> AMap, Monster Item)
  {
      AMap.put(Item.getClass( ).getSimpleName( ),
         new Pair(Item, Item.getClass( ).getSuperClass( ).getSimpleName( )));

  } //

 public void Registration
   (Map<string, Pair<Monster, string>> AMap)
 {
     this.RegisterMonster(new DireWolf( ));
     this.RegisterMonster(new Dragon( ));
     this.RegisterMonster(new Kraken( ));
     this.RegisterMonster(new Kitty( ));
} //

 public void ListSubclasses
   (Map<string, Pair<Monster, string>> AMap, string AParent)
 {
    for ( Pair<string, Monster> EachMonster : AMap)
    {
       if (AParent.equals(EachMonster.getkey( )))
       {
         System.out.println(EachMonster.getClass( ).getSimpleName());
       } // if
    } // for
 } //

 public void ListClasses( )
 {
   ListSubclasses
     (Monster.getClass( ).getSimpleName());
 } //

  public static void Main (...)
  {
     Map<string, Pair<Monster string>> AMap =
       new Map<string, Pair<Monster, string>( );

     this.Registration(AMap);
     this.ListClasses(AMap);

     AMap = null;
   } // main

} // public class

现在,这可以通过替换存储在地图中的 getSimpleName 来优化,通过实施 gethashcode 方法,但会使它更复杂。

完成。

我不太明白你的问题,但据我了解,你想加载任何给定父 class 的所有子class。为此,您可以使用反射。但是,您可能想先检查您的设计,也许您甚至不需要那个。

Java Reflection 允许在运行时操作 java classes(创建实例、调用方法、访问字段...)。

这是一个例子,有人试图找到如何加载给定 class 的子 classes:

How do you find all subclasses of a given class in Java?

对于您自己的包,此代码来自对使用反射库扫描 Java 包以获取 类 的答案,似乎应该这样做。感谢评论者指出这一点。

Reflections reflections = new Reflections("my.project.prefix");

Set<Class<? extends Object>> allClasses = 
     reflections.getSubTypesOf(Object.class);

发件人:

我想你在你的软件中有一些地方可以做一些初始化的事情,或者发生什么实例化,所以也许你可以在那里做。

我同意评论和其他答案中的人们的观点,即您可能想要重新考虑设计。但要知道这种东西也很有用。在 Python 中,我经常引用 类 来实例化游戏或其他任何东西中的随机怪物,并且可以看到在某些情况下创建所有类型的怪物有何用处。