我是一名C ++程序员,在C ++中,我可以这样做:
class SuperSuper
{
virtual void newItem()=0;
}
class SubSuperA:public SuperSuper
{
virtual void newItem()
{
//do something
}
}
class SubSuperB:public SuperSuper
{
virtual void newItem()
{
//do something different (disappear! :)
}
}
template <class T>
class SubSub:public T
{
virtual void newItem()
{
T::newItem();
//do a third thing
}
}
我想用Java做到这一点,但我感觉它(至少直接)是不可能的
我在Java中轻松设置了前三个类,如下所示:
public abstract class SuperSuper
{
abstract void newItem(Item item);
}
public class SubSuperA extends SuperSuper
{
@Override void newItem(Item item)
{
//stuff
}
}
public class SubSuperB extends SuperSuper
{
@Override void newItem(Item item)
{
//other stuff
}
}
//SubSuperC,D,etc
目前我正在实施第四个:
SubSuperA sa=new SubSuperA() {
@Override public void newItem(Item item)
{
super.newItem(item);
//A lot of stuff that will be changing constantly throughout development
}
};
SubSuperB sb=new SubSuperB() {
@Override public void newItem(Item item)
{
super.newItem(item);
//A lot of stuff that will be changing constantly throughout development
}
};
请注意,两个覆盖都具有相同的功能。无论它基于什么SubSuper *,替换newItem()都是相同的。显然这将是一个维持的噩梦。我希望我能像这样宣布一个SubSub类
public class SubSub<T> extends T {
@Override public void newItem(Item item)
{
super.newItem(item);
//A lot of stuff that will be changing constantly throughout development
}
}
我可以像这样实例化
SubSub ss=new SubSub<SubSuperA>
等...但是java中的这个错误:
"Cannot refer to the type parameter T as a supertype."
我根据该错误环顾四周,发现Extend from Generic Supertype?声称使用该方法无法实现我想做的事。
我真正需要做的是:我有一个平台无关的Twitter客户端,只处理接收推文,存储它们等。它有一个抽象的Column类(SuperSuper),我可以扩展为各种不同类型的列(SubSuper)(家庭时间表,提及等),每个过滤掉他们想要在newItem()中显示的推文。我希望能够为不同的平台插入各种GUI,我需要客户端调用GUI特定的功能(SubSub)来处理将每个推文添加到GUI库。具有可以扩展任何Column派生类的GUI特定类将是理想的解决方案
由于显然这种直接实现在Java中是不可能的,我想知道是否有一些语法技巧可以实现类似的东西,或者我是否应该创建一个将由SuperSuper存储和调用的接口, SuperSub *由我的GUI处理程序而不是SubSub实现。
答案 0 :(得分:2)
使用Java的泛型可以使用模板。但是,在Java中,接口比继承更受欢迎。这是因为Java不支持多重继承。
在C ++中,您可以扩展多个类。
class X : public A, public B, private C { }
因为C ++没有区分虚拟和非虚拟类,只有虚拟和非虚拟成员,所以类之间没有正式的区别。可能没有虚拟方法。
另一方面,Java有三种不同的类类型:在Java中,虚方法被称为抽象方法,因此我将在此处称之为。
Java也有泛型。泛型在语法上与模板类似,但在实现方面完全不同。我将把实施研究留给您(在您的搜索中使用的关键字是“擦除”)。
在课堂上宣布泛型。例如,Java等同于C ++ vector
是ArrayList
类。它的用途非常相似:
List<String> strs = new ArrayList<String>();
此处,List
是一种ArrayList
的超类型。 List
是一个接口,ArrayList
实现了它。 List
本身在其声明中声明了一个泛型类型:
public interface List<E> ... {
// ...
E get(int index);
// ...
}
注意get
如何返回E
。这里,E
没有具体定义。这是一种通用类型,在这种情况下,可以使用任何内容,String
,Object
,Boolean
,您自己的类等。
ArrayList
实现List
,并且还声明了泛型类型:
public ArrayList<E> implements List<E>, ... {
// ...
public E get(int index) {
// bounds check
return elements[i];
}
// ...
}
您还可以使用类型边界限制泛型的类型。这有点超出了这个范围,因为你想要的并不是真正的泛型。你想要接口。
在您的示例中,您首先要使用newItem
声明一个接口。
public interface A {
void newItem();
}
每个方法都必须来自具体的实现或接口,因此需要这个接口。具体来说,此界面等同于SuperSuper
。它是一个完全虚拟的类(接口)。现在为您的课程:
public class B implements A {
@Override
public void newItem() {
// Do something
}
}
public class C implements A {
@Override
public void newItem() {
// Do something else
}
}
对于像我这样没有太多C ++经验的人来说,你的最后一点有点令人困惑,但我假设你所说的是你想用newItem
方法创建一个模板类型。在Java中,这将是A
接口的另一个实现,或者您可以扩展B或C并覆盖它们的方法。
public class D extends B {
@Override
public void newItem() {
// And yet another something else
}
}
然后使用newItem
方法的东西就像这样简单:
A a = new B(); // or "new C()" or "new D()"
a.newItem();
就像你怎么说
SuperSuper* a = new SubSuperA();
在Java中,您可以使用接口,抽象类和具体类来执行相同的操作,就像我上面所做的那样。
所以我认为接口是解决问题的方法。我强烈建议您阅读Java中如何使用接口。它们提供强大的类型,没有多重继承。我会很快找到几个链接。
希望那些帮助。如果您需要任何澄清,请与我们联系。
答案 1 :(得分:1)
你不能。
C ++模板实际上是源代码“模板”。当您有模板类或函数时,对于用作类型参数的每个类型,编译器有效地生成(“实例化”)源代码的单独副本,并将type参数替换为实际类型参数。例如,vector<int>
和vector<string>
是完全独立的类型,其功能的编译代码也可能是分开的(就像它们是不同的类型一样)。
这就是为什么可以做类似参数继承的事情。对于编译器,它只是在它看到的任何地方替换T
的任何类型参数。生成的代码有效,因此可以正常工作。
Java中的泛型非常不同。通用类或方法只有一个编译代码的副本。编译代码的一个版本必须同时适用于任何可能的类型参数(现有的或未来的)在其范围内。
所以想想如果你能按照你的意思做什么意味着什么。类SubSub
的编译代码只有一个副本,它继承了T
,无论它是什么。因此它必须同时继承每个类型。怎么可能?一个类只能有一个明确的父类。
答案 2 :(得分:0)
根据您的Java代码,我认为您真的需要装饰器模式:
public class SubSub<T extends SuperSuper> extends SuperSuper {
private final Class<T> clazz;
public SubSub(Class<T> clazz){
this.clazz = clazz;
}
@Override
public void newItem(Item item){
T sup = clazz.newInstance();
sup.newItem(item);
// other stuff
}
}
使用如下调用:
SubSub<SubSuperA> foo = new SubSub<SubSuperA>(SubSuperA.class);
如果您想将类的名称作为参数传递,则可以完全删除泛型:
public class SubSub extends SuperSuper {
private final SuperSuper _super;
public <T extends SuperSuper> SubSub(Class<T> clazz){
_super = clazz.newInstance();
}
@Override
public void newItem(Item item){
_super.newItem(item);
sup.newItem(item);
// other stuff
}
}
使用表单的实例化:
SubSub foo = new SubSub(SubSuperA.class);
或:
SubSub foo = new SubSub((Class<SuperSuper>) Class.forName("SubSuperA"));