使用继承时使用 class 的实际类型
Use actual type of the class when using inheritance
假设我们有一个 class,方法如下:
public class Entry {
private String name;
public static Entry getOrCreate(String name) {
// ...
return new Entry(name);
}
}
这个class可以被subclassed(例如SubEntry
),"getOrCreate"背后的逻辑没有改变。但是 subclasses 不应该 return 类型 Entry
的新对象,而是相应 subclass 类型的新对象(例如 return SubEntry(name)
)
如何在不为 Entry
的每个子 class 重新实现方法 getOrCreate
的情况下实现这一点?这种技术有专门的术语吗?
Subclassing Entry
不会影响 getOrCreate
方法,因为静态方法不是 class 实例的一部分;他们在逻辑上不属于任何 class.
如果您改为将 getOrCreate
移动到非静态工厂 class,您可以使用一些泛型魔术来确定返回的类型:
public class Entry {
private String name;
}
abstract class AbstractEntryFactory<T extends Entry>
public abstract T getOrCreate(String name);
}
public class EntryFactory extends AbstractEntryFactory<Entry>
@Override
public Entry getOrCreate(String name) {
// ...
return new Entry(name);
}
}
public class SubEntryFactory extends AbstractEntryFactory<SubEntry>
@Override
public SubEntry getOrCreate(String name) {
// ...
return new SubEntry(name);
}
}
实际调用 getOrCreate
看起来与您的代码看起来不同。而不是这个:
Entry myEntry = Entry.getOrCreate("my name");
它看起来像这样:
Entry myEntry = new EntryFactory().getOrCreate("my name");
或者这样:
SubEntry myEntry = new SubEntryFactory().getOrCreate("my name");
假设您希望能够调用 Entry.getOrCreate()
来创建一种 SubEntry,您将必须传递一些额外的信息。原因是 getOrCreate()
方法没有被 SubEntry
继承,因为它是 static
方法。因此,如果您想按照我提到的方式调用它,则必须传递要创建的 class 名称。在下面的代码中,没有检查来验证 Class clazz
是 Entry
还是子类型,但这给了你一个开始。
import java.lang.reflect.Constructor;
public class TestClass {
public static void main(String[] args) {
Entry entry = (Entry)Entry.getOrCreate("entry", Entry.class);
SubEntry subEntry = (SubEntry)SubEntry.getOrCreate("subEntry", SubEntry.class);
System.out.println("entry class: " + entry.getClass().getName());
System.out.println("subEntry class: " + subEntry.getClass().getName());
}
}
class Entry {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static Object getOrCreate(String name, Class clazz) {
// If a constructor is created that takes a String, such as "public Entry(String name)",
// then each sub class will need to implement that method. Instead I used a getter and
// setter for the name attribute.
try {
Entry entry = (Entry)clazz.newInstance();
entry.setName(name);
return entry;
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
class SubEntry extends Entry {
}
最终结果是这样的输出:
entry class: Entry
subEntry class: SubEntry
您有两个问题要问:
- 我该怎么做?
- 这种技术叫什么?
第二个比第一个重要得多。
在我看来,您想要实现的目标类似于克隆 (link) 或虚拟构造函数。但是您希望这是一个静态方法,这就提出了一个问题,为什么?由于静态方法绑定到某个 class,而不是实例,因此您应该通过 class 调用它,在这种情况下您也可以显式调用 new
。但是搜索 "retrive class in static context" 我会说不可能完全按照你在问题中写的那样做。
如果将静态方法转换为普通方法,可以使用反射来完成:
class Entry {
private String name;
public Entry(String name) {
this.name = name;
}
public Entry() {
this.name = null;
}
public Entry getOrCreate(String name) {
try {
return getClass().getConstructor(String.class).newInstance(name);
} catch (Exception e) {
return new Entry(name);
}
}
}
class BetterEntry extends Entry {
public BetterEntry(String name) {
super(name);
}
public BetterEntry() {
super();
}
}
然后您将从一个实例调用该函数,如下所示:
Entry a = new Entry().getOrCreate("First");
Entry b = new BetterEntry().getOrCreate("Second");
Entry c = b.getOrCreate("Third");
a、b、c的动态类型分别为Entry、BetterEntry和BetterEntry。您可以省略默认构造函数,但我添加了它们以使调用 getOrCreate
感觉更像是一个静态方法。
如果您真的希望该方法是静态的,最简单的方法就是在每个子class.
中重新实现该函数
假设我们有一个 class,方法如下:
public class Entry {
private String name;
public static Entry getOrCreate(String name) {
// ...
return new Entry(name);
}
}
这个class可以被subclassed(例如SubEntry
),"getOrCreate"背后的逻辑没有改变。但是 subclasses 不应该 return 类型 Entry
的新对象,而是相应 subclass 类型的新对象(例如 return SubEntry(name)
)
如何在不为 Entry
的每个子 class 重新实现方法 getOrCreate
的情况下实现这一点?这种技术有专门的术语吗?
Subclassing Entry
不会影响 getOrCreate
方法,因为静态方法不是 class 实例的一部分;他们在逻辑上不属于任何 class.
如果您改为将 getOrCreate
移动到非静态工厂 class,您可以使用一些泛型魔术来确定返回的类型:
public class Entry {
private String name;
}
abstract class AbstractEntryFactory<T extends Entry>
public abstract T getOrCreate(String name);
}
public class EntryFactory extends AbstractEntryFactory<Entry>
@Override
public Entry getOrCreate(String name) {
// ...
return new Entry(name);
}
}
public class SubEntryFactory extends AbstractEntryFactory<SubEntry>
@Override
public SubEntry getOrCreate(String name) {
// ...
return new SubEntry(name);
}
}
实际调用 getOrCreate
看起来与您的代码看起来不同。而不是这个:
Entry myEntry = Entry.getOrCreate("my name");
它看起来像这样:
Entry myEntry = new EntryFactory().getOrCreate("my name");
或者这样:
SubEntry myEntry = new SubEntryFactory().getOrCreate("my name");
假设您希望能够调用 Entry.getOrCreate()
来创建一种 SubEntry,您将必须传递一些额外的信息。原因是 getOrCreate()
方法没有被 SubEntry
继承,因为它是 static
方法。因此,如果您想按照我提到的方式调用它,则必须传递要创建的 class 名称。在下面的代码中,没有检查来验证 Class clazz
是 Entry
还是子类型,但这给了你一个开始。
import java.lang.reflect.Constructor;
public class TestClass {
public static void main(String[] args) {
Entry entry = (Entry)Entry.getOrCreate("entry", Entry.class);
SubEntry subEntry = (SubEntry)SubEntry.getOrCreate("subEntry", SubEntry.class);
System.out.println("entry class: " + entry.getClass().getName());
System.out.println("subEntry class: " + subEntry.getClass().getName());
}
}
class Entry {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static Object getOrCreate(String name, Class clazz) {
// If a constructor is created that takes a String, such as "public Entry(String name)",
// then each sub class will need to implement that method. Instead I used a getter and
// setter for the name attribute.
try {
Entry entry = (Entry)clazz.newInstance();
entry.setName(name);
return entry;
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
class SubEntry extends Entry {
}
最终结果是这样的输出:
entry class: Entry
subEntry class: SubEntry
您有两个问题要问:
- 我该怎么做?
- 这种技术叫什么?
第二个比第一个重要得多。
在我看来,您想要实现的目标类似于克隆 (link) 或虚拟构造函数。但是您希望这是一个静态方法,这就提出了一个问题,为什么?由于静态方法绑定到某个 class,而不是实例,因此您应该通过 class 调用它,在这种情况下您也可以显式调用 new
。但是搜索 "retrive class in static context" 我会说不可能完全按照你在问题中写的那样做。
如果将静态方法转换为普通方法,可以使用反射来完成:
class Entry {
private String name;
public Entry(String name) {
this.name = name;
}
public Entry() {
this.name = null;
}
public Entry getOrCreate(String name) {
try {
return getClass().getConstructor(String.class).newInstance(name);
} catch (Exception e) {
return new Entry(name);
}
}
}
class BetterEntry extends Entry {
public BetterEntry(String name) {
super(name);
}
public BetterEntry() {
super();
}
}
然后您将从一个实例调用该函数,如下所示:
Entry a = new Entry().getOrCreate("First");
Entry b = new BetterEntry().getOrCreate("Second");
Entry c = b.getOrCreate("Third");
a、b、c的动态类型分别为Entry、BetterEntry和BetterEntry。您可以省略默认构造函数,但我添加了它们以使调用 getOrCreate
感觉更像是一个静态方法。
如果您真的希望该方法是静态的,最简单的方法就是在每个子class.
中重新实现该函数