摘要: 从字节码看Java的泛型编程与多态,重载的同于不同。
泛型编程
泛型编程在某些语言中也称之为模板编程,比如C ++,所以在泛型编程中见到的那个Ť也就是模板的首字母。
来看一个泛型编程的简单样例。
public static void main(String [] args){ StringBuilder sb = new StringBuilder(“Test template”); 的System.out.println(FOO(SB)的ToString()); } public static T foo(T t){// bla bla bla return t; }
泛型编程与多态
在面向对象的编程中还有一个概念叫多态,利用这种概念,我们可以将泛型编程中的Ť替换成所有对象的基类对象,这在某种程度上同样能够达到泛型编程所达到的效果,如下方代码所示。
public static void main(String [] args){ StringBuilder sb = new StringBuilder(“Test template”); 的System.out.println(FOO(SB)的ToString()); 的System.out.println(foo2的(SB)的ToString()); } public static T foo(T t){// bla bla bla return t; } public static Object foo2(Object o){// bla bla bla return o; }
那么这两种方法有什么区别吗?
我们来看看字节码。
public class template.Template { public template.Template(); 代码:0:aload_0 1:invokespecial#1 //方法java / lang / Object。“”:()V 4:return public static void main(java.lang.String []); 代码:0:new#2 // class java / lang / StringBuilder 3:dup 4:ldc#3 // String测试模板 6:invokespecial#4 //方法java / lang / StringBuilder“”:( Ljava / lang / String;)V 9:astore_1 10:getstatic#5 // Field java / lang / System.out:Ljava / io / PrintStream; 13:aload_1 14:invokestatic#6 //方法foo :( Ljava / lang / Object;)Ljava / lang / Object; 17:checkcast#2 // class java / lang / StringBuilder 20:invokevirtual#7 //方法java / lang / StringBuilder.toString :()Ljava / lang / String; 23:invokevirtual#8 //方法java / io / PrintStream.println :( Ljava / lang / String;)V 26:getstatic#5 // Field java / lang / System.out:Ljava / io / PrintStream; 29:aload_1 30:invokestatic#9 //方法foo2:(Ljava / lang / Object;)Ljava / lang / Object; 33:invokevirtual#10 //方法java / lang / Object.toString :()Ljava / lang / String; 36:invokevirtual#8 //方法java / io / PrintStream.println:(Ljava / lang / String;)V 39:返回 public static T foo(T); 代码:0:aload_0 1:areturn public static java.lang.Object foo2(java.lang.Object); 代码:0:aload_0 1:areturn }
FOO方法调用时的字节码
14:invokestatic#6 //方法foo :( Ljava / lang / Object;)Ljava / lang / Object; 17:checkcast#2 // class java / lang / StringBuilder20:invokevirtual#7 //方法java / lang / StringBuilder。的toString :()Ljava /郎/字符串;
foo2的方法调用时的字节码
30:invokestatic#9 //方法foo2 :( Ljava / lang / Object;)Ljava / lang / Object; 33:invokevirtual#10 //方法java / lang / Object.toString :()Ljava / lang / String;
不难发现,主函数调用使用了泛型编程的FOO方法时,其字节码已不再是T,而是替换为实际的StringBuilder的类;反观foo2的方法使用的还是对象,那它将是在运行时作类型转换。
结论:泛型编程是编译期替换;多态则是运行期作类型转换。
泛型编程与重载
什么是重载
不废话,形如下方代码即重载。
public static int add(int a,int b) public static double add(double a,double b)
重载的特点:两个及以上方法名相同;参数个数不同,参数顺序不同,类型不同,以上任一种及以上都可以构成重载仅返回值不同不可构成重载。
测试的完整代码如下:
public static void main(String [] args){ StringBuilder sb = new StringBuilder(“Test template”); 的System.out.println(FOO(SB)的ToString()); 的System.out.println(foo2的(SB)的ToString()); int a = 1; int b = 2; System.out.println(add(a,b)); double x = 1.1; 双y = 1.2; System.out.println(add(x,y)); } public static T foo(T t){// bla bla bla return t; } public static Object foo2(Object o){// bla bla bla return o; } public static int add(int a,int b) public static double add(double a,double b)
接下来看看重载部分的字节码:
48:invokestatic#11 //方法添加:(II)I71:invokestatic#17 //方法add :((DD)D)
总结:看来字节码已经做了相应的转换,重载和泛型编程相似,都是在编译期就做了替换,而不是在运行时,但是重载需要为每一种不同的参数类型重新编写代码,代码复用度不高。
总结
泛型编程和重载是在编译期作了类型替换,多态则是在运行期作类型转换。
泛型编程和多态代码复用度高,重载代码复用度低。
当然,泛型,重载,多态更有其它设计模式的意义,在此不作讨论。
领取专属 10元无门槛券
私享最新 技术干货