首先让我承认,我不是一个Java程序员。我从C++的角度看别人的代码,想知道.那到底是怎么回事?
C++确实有类似于C++的泛型方法的模板成员函数,但是C++模板成员函数不能是虚拟的-也就是说,它们不能被覆盖。这个限制对我来说是有意义的,因为虚拟(可覆盖的)函数最终是函数指针,如果虚拟函数可能被模板化,那么类定义就无法知道要为自己生成多少函数指针。
但是Java泛型方法似乎完全可以被派生类覆盖。Java是如何管理它的?
发布于 2018-01-25 08:16:43
据我所知,C++编译器为给定的模板参数实例化(隐式或显式)模板函数,而在运行时,每个模板参数都有不同的函数。
在Java中,没有像泛型实例化或专门化这样的概念。例如,
public class MyClass{
public void <T> method(T t){ }
}我们不能实例化并专门化它,比如在C++中。
public void <Integer> MyClass::method(Integer t){ //not valid in Java
//...
}相反,类型擦除出现了,因此在运行时,我们有一个泛型方法的未泛化版本,可以重写它。
看看这个简单的类:
public class Main{
public static void main(String[] args){
Main m = new Main();
m.method(10);
m.methodNumber(10);
m.methodNumberAnd(10);
m.methodNumberAnd2(10);
m.methodInteger(10);
}
public <T> void method(T t){ }
public <T extends Number> void methodNumber(T t){ }
public <T extends Number & java.io.Serializable> void methodNumberAnd(T t){ }
public <T extends java.io.Serializable & java.lang.Comparable<T>> void methodNumberAnd2(T t){ }
public void methodInteger(Integer t){ }
}还有跑步
javac Main.java
javap -c Main.class它的内容如下:
public class Main {
public Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2 // class Main
3: dup
4: invokespecial #3 // Method "<init>":()V
7: astore_1
8: aload_1
9: bipush 10
11: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
14: invokevirtual #5 // Method method:(Ljava/lang/Object;)V
17: aload_1
18: bipush 10
20: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
23: invokevirtual #6 // Method methodNumber:(Ljava/lang/Number;)V
26: aload_1
27: bipush 10
29: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
32: invokevirtual #7 // Method methodNumberAnd:(Ljava/lang/Number;)V
35: aload_1
36: bipush 10
38: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
41: invokevirtual #8 // Method methodNumberAnd2:(Ljava/io/Serializable;)V
44: aload_1
45: bipush 10
47: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
50: invokevirtual #9 // Method methodInteger:(Ljava/lang/Integer;)V
53: return
public <T> void method(T);
Code:
0: return
public <T extends java.lang.Number> void methodNumber(T);
Code:
0: return
public <T extends java.lang.Number & java.io.Serializable> void methodNumberAnd(T);
Code:
0: return
public <T extends java.io.Serializable & java.lang.Comparable<T>> void methodNumberAnd2(T);
Code:
0: return
public void methodInteger(java.lang.Integer);
Code:
0: return
}请注意已编译方法的签名:
Method method:(Ljava/lang/Object;)V
Method methodNumber:(Ljava/lang/Number;)V
Method methodNumberAnd:(Ljava/lang/Number;)V
Method methodNumberAnd2:(Ljava/io/Serializable;)V
Method methodInteger:(Ljava/lang/Integer;)V正如@Eugene所指出的,泛型类型将在&的情况下擦除到第一个类型绑定。
发布于 2018-01-25 08:36:33
C++模板需要每次使用才能根据实际的参数类型生成实际的类。
Java打算生成一个基于类的单一对象参数。在运行时,只保留对象--这称为类型擦除。
public class A<T> {
public T f(T x) { return x; }
}
public class B extends A<String> {
@Override
public String f(String s) { return s.toLowerCase(); }
}生成的内容类似于:
public class A {
public Object f(Object x) { return x; }
}
public class B extends A {
@Override
public Object f(Object x) { return B.this.f((String)x); }
public String f(String s) { return s.toLowerCase(); }
}C++为它提供了一个虚拟方法表,将方法指针替换为该类的方法指针。
Java有一个.class文件,它更像一个C++ .o或.obj,包含有关方法的“链接”信息:它们的签名:名称和完整的参数类型名称。“链接”发生在类加载中。jvm字节码方法调用操作可以处理继承。
https://stackoverflow.com/questions/48438160
复制相似问题