Java SE在5.0后增加了泛型,而C++一直支持泛型,并有强大的STL。
C++的泛型其实就是一个模板生成器,缺点是代码膨胀,而JAVA的泛型和C++采取的机制完全不同,它利用“擦除”的方式把类型参数替换为限定类型(无限定类型的替换为Object),然后再编译时插入类型安全的类型转换。
【C++ code】
template<typename T>
class Base{
public:
virtual string GetInfo() {return "Base::GetInfo";}
};
template<typename T>
class Derived: public Base<T>
{
public:
string GetInfo() {return "Derived::GetInfo";}
};
int _tmain(int argc, _TCHAR* argv[])
{
Base<int> bi;
cout<<bi.GetInfo()<<endl;
Derived<int> di;
Base<int> &rb = di;
cout<<rb.GetInfo()<<endl;
return 0;
}
C++的机制是先生成一份int版本的代码(把T替换成int),在编译那份非泛型的代码。
【Java code】
class Base<T>{
String getItem(T t) { return "Base" + t; }
}
class Derived extends Base<String>{
String getItem(String s) {return "Derived" + s; }
}
public class MyTest {
public static void main(String[] args) {
Derived d = new Derived();
System.out.println(d.getItem("Derived"));
Base<String> bs = d;
System.out.println(bs.getItem("Base"));
}
}
Java采用擦除机制,其实代码就那么一份:
class Base{
String getItem(Object t) { return "Base" + Object; } //因为为指定限制类型,所以用Object替换
}
对OOP了解的人马上发现,这里出现了问题,显然:
Base: String getItem(Object t); 与
Derived:String getItem(String s); 不是重写的关系,重写要求参数表相同。
那么父类对象调用getItem()就不能产生多态了啊...Java内部采用了“桥方法”的方式来解决这个问题,类似转交函数的方式。
编译器会在子类中生成一个桥方法:
Derived: String getItem(Object t) { return getItem((String)t); } 这样就重写了父类的getItem,体现出了多态机制。
观察Derived.class 字节码可以看到有这样一部分内容:
// Method descriptor #18 ()Ljava/lang/Object;
// Stack: 1, Locals: 1
bridge synthetic java.lang.Object getItem();
0 aload_0 [this]
1 invokevirtual Derived.getItem() : java.lang.String [19]
4 areturn
Line numbers:
[pc: 0, line: 1]
确实生成了桥方法。简单译作:为getItem方法合成了桥方法,调用一个重载的getItem。
Java--色彩斑斓。