如何创建给定超类的每个子类的实例?
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);
}
}
我想避免您在 Base
和 Phone
的构造函数中看到的情况。与其每次都创建一个新实例然后添加它 "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 中,我经常引用 类 来实例化游戏或其他任何东西中的随机怪物,并且可以看到在某些情况下创建所有类型的怪物有何用处。
我有几个抽象类,每个都有几个子类。我想创建每个子类的实例,而不必 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);
}
}
我想避免您在 Base
和 Phone
的构造函数中看到的情况。与其每次都创建一个新实例然后添加它 "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 中,我经常引用 类 来实例化游戏或其他任何东西中的随机怪物,并且可以看到在某些情况下创建所有类型的怪物有何用处。