我有一个超类,我想将一个名为getInstance()
的静态方法转发给所有子类。
在创建子类的实例时,我然后在超类中注册实例(可能使用哈希表,其中键基于getClass()
)。然后,我希望使用前面提到的静态方法(getInstance
),其中超类方法将返回正确类型的实例。
例如,我有一个超类A,一个子类B扩展A.
我想写一个静态方法A.getInstance()
;当从B(B.getInstance()
)调用时,我希望它返回我之前存储的B实例。
有点难以解释,但我将会使用这个超类,我宁愿不在每个子类中编写getInstance
方法。
我将如何做这样的事情?
编辑:我刚刚意识到我的问题可能被误解为创建对象的新实例。我已经创建了实例,我希望得到类的现有实例
答案 0 :(得分:3)
正如许多其他人在评论中指出的那样,静态方法无法实现您的目标。此外,您应尽可能避免使用静态方法,因为它们可能会导致测试和维护噩梦(*)。
您将方法命名为“getInstance”,因此我猜测您想要做的是混合使用Factory和Singleton模式。以下是一些有关这些模式的信息:
Singleton:http://en.wikipedia.org/wiki/Singleton_pattern
工厂方法:http://en.wikipedia.org/wiki/Factory_method_pattern
抽象工厂:http://en.wikipedia.org/wiki/Abstract_factory
这两天都不应该手工编码(*) - 看一下像Google Guice或Spring这样的好的“依赖注入”(DI)容器。我不是100%确定你想要实现什么,但看起来像DI容器会为你做。
修改:这是对问题编辑的回复。您希望接收子类的缓存实例。在这种情况下,我仍然建议不要使用静态方法。您可以创建“BCache”类的单例实例(使用DI容器或手动编程),然后使用此缓存对象来查找已注册的对象。使用Guice作为DI容器,它看起来像这样(警告,未经测试):
@Singleton
public class BCache {
private Map<Class<? extends B>, B> cache = ...;
public <T> T getInstance(Class<? extends T> type) {
return (T) cache.get(type);
}
}
我仍然认为可以完全使用DI容器来删除缓存类。同样,这是使用Guice的未经测试的代码,但它看起来像这样:
@Singleton
public class A extends B {
public A() {
//I am not sure if you need to register in this case, because your
//DI container keeps track of the singleton instances.
super.register(this);
}
}
public class SomeClassUsingA {
@Inject private A a;
}
(*)请注意“所有概括都是错误的”,也就是说,在某些项目中它可能有意义,但在大多数情况下它不会。
答案 1 :(得分:1)
使用静态方法无法以良好的OOP方式完成您想要的操作。您可以使用if .. else if
的反射或一堆来做某事。
但是,您应该使用一些定义明确的设计模式,例如Abstract fectory或Factory method。这就是你应该去的方式,就像有人说“不要发明温水”。
答案 2 :(得分:1)
您始终可以将子类实例分配给superClass引用。因此,你的superClass的静态方法可以设置或获取一个subClass实例。但请确保在使用之前强制转换返回的实例。
public class A {
private static A a;
/**
* @param a the a to set
*/
public static void setA(A a) {
A.a = a;
}
/**
* @return the a
*/
public static A getA() {
return a;
}
public class B extends A {
private int index = 0;
/**
* @param index the index to set
*/
public void setIndex(int index) {
this.index = index;
}
/**
* @return the index
*/
public int getIndex() {
return index;
}
用法:
public static void main(String[] args) throws Exception {
B b = new B();
A.setA(b);
B c = (B) A.getA();
System.out.println(c.getIndex());
}
答案 3 :(得分:0)
将表单getInstance()
更改为getInstance(String class)
在超类中:
public static A getInstance(String class){
if(class.equals("A")){
RegisterObject(...);//User defined method
return new A(...);
}
else if(class.equals("B")){
RegisterObject(...);//User defined method
return new B(...);
}
else if(class.equals("C")){
RegisterObject(...);//User defined method
return new C(...);
}
//... and so on
}
答案 4 :(得分:0)
静态方法无法知道使用哪个类来调用它们。例如,如果您使用static getInstance()
扩展了A和A
的A类和B类,那么使用getInstance()
或A
调用B
是没有区别的。此外,尝试调用B.getIntance()
将产生编译警告(至少在Eclipse中)。
但是,您可以将该类作为getInstance()
:
public class A {
public static <T extends A> T getInstance(Class<T> clazz) {
return clazz.newInstance(); // I do not catch exceptions here: do it yourself
}
}
public class B extends A {
}
...............
B b = A.getInstance(B.class);
答案 5 :(得分:0)
你可以这样做,
class A{
public static A getInstance(){
return new A();
}
@Override
public String toString() {
return "inside A";
}
}
class B extends A{
public static A getInstance(){
return new B();
}
@Override
public String toString() {
return "inside B";
}
}
在主要内部:
public static void main(String[] args) {
A a1 = A.getInstance();
A a2 = B.getInstance();
System.out.println(a1.toString());
System.out.println(a2.toString());
}