不兼容类上的泛型参数
)。以下是一段简单的代码示例,不再赘述。
public class GenericsDemo<T> {
public T g_var_a;
public void set(T data) {
g_var_a = data;
}
public T get() {
return g_var_a;
}
}
public class GenericsUsingDemo {
public static void main(String[] args) {
GenericsDemo<String> g_str = new GenericsDemo<String>();
g_str.set("test");
System.out.println(g_str.get());
GenericsDemo<Integer> g_int = new GenericsDemo<Integer>();
g_int.set(100);
System.out.println(g_int.get());
}
}
反编译上文GenericsUsingDemo类,可以查看调用GenericsDemo类的set方法参数类型和get方法返回类型均为java/lang/Object。使用时,调用checkcast指令自动进行类型转换。
public class GenericsUsingDemo {
public GenericsUsingDemo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2 // class GenericsDemo
3: dup
4: invokespecial #3 // Method GenericsDemo."":()V
7: astore_1
8: aload_1
9: ldc #4 // String test
11: invokevirtual #5 // Method GenericsDemo.set:(Ljava/lang/Object;)V
14: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
17: aload_1
18: invokevirtual #7 // Method GenericsDemo.get:()Ljava/lang/Object;
21: checkcast #8 // class java/lang/String
24: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
27: new #2 // class GenericsDemo
30: dup
31: invokespecial #3 // Method GenericsDemo."":()V
34: astore_2
35: aload_2
36: bipush 100
38: invokestatic #10 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
41: invokevirtual #5 // Method GenericsDemo.set:(Ljava/lang/Object;)V
44: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
47: aload_2
48: invokevirtual #7 // Method GenericsDemo.get:()Ljava/lang/Object;
51: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
54: return
}
如前文所述,Java泛型包括类泛型、接口泛型、方法泛型。其中类泛型、接口泛型不再相赘述,本节重点探讨下方法泛型。
普通泛型方法定义需要在方法返回类型前指定泛型标志
public class GenericsDemo<T> {
public T g_var_a;
public T g_var_b;
public void set(T data) {
g_var_a = data;
}
public T get() {
return g_var_a;
}
public <M> void g_method_set(M m_data, T t_data) {
g_var_a = t_data;
System.out.println(g_var_a);
System.out.println(m_data);
}
}
静态泛型方法不能访问泛型类上的泛型标志。
public class GenericsDemo<T> {
public T g_var_a;
public T g_var_b;
public void set(T data) {
g_var_a = data;
}
public T get() {
return g_var_a;
}
public static <M> void g_method_set(M m_data, T t_data) {
g_var_a = t_data;
System.out.println(g_var_a);
System.out.println(m_data);
}
}
[root@iZbp1fza94gkbdpgoq00xcZ test]# javac GenericsDemo.java
GenericsDemo.java:17: error: non-static type variable T cannot be referenced from a static context
public static <M> void g_method_set(M m_data, T t_data) {
^
GenericsDemo.java:18: error: non-static variable g_var_a cannot be referenced from a static context
g_var_a = t_data;
^
GenericsDemo.java:19: error: non-static variable g_var_a cannot be referenced from a static context
System.out.println(g_var_a);
^
3 errors
如果用泛型标志悠久可变参数,则调用该方法,可传入任意类型参数组合。
public class GenericsDemo<T> {
public T g_var_a;
public T g_var_b;
public void set(T data) {
g_var_a = data;
}
public T get() {
return g_var_a;
}
public <M> void g_method_set(M... m_data) {
for(M m : m_data) {
System.out.println(m);
}
}
}
public class GenericsUsingDemo {
public static void main(String[] args) {
GenericsDemo<String> g_str = new GenericsDemo<String>();
g_str.g_method_set("test", 1);
}
}
public class GenericsUsingDemo {
public static void main(String[] args) {
GenericsDemo<?> g_obj = new GenericsDemo<Object>();
g_obj.g_method_set("test", 1);
}
}
[root@iZbp1fza94gkbdpgoq00xcZ test]# java GenericsUsingDemo
test
1
声明泛型数组须使用通配符标志,不能指定参数类型。具体原因,可以仔细思考下前文反编译中的checkcast指令。
public class GenericsUsingDemo {
public static void main(String[] args) {
GenericsDemo<?>[] g_obj = new GenericsDemo<?>[5];
System.out.println(g_obj.length);
}
}
另外,虽然可以声明通配符类型数组,但不能声明通配符类型变量。
[root@iZbp1fza94gkbdpgoq00xcZ test]# javac GenericsUsingDemo.java
GenericsUsingDemo.java:7: error: unexpected type
GenericsDemo<?> g_obj = new GenericsDemo<?>();
^
required: class or interface without bounds
found: ?
1 error
泛型还可以应用上下边界,语法如下,不再赘述。
Java反射可以影响泛型的执行阶段。如下面一段代码,可以通过编译阶段,但在执行时会提示Integer类型无法转换为String类型异常。如果不使用反射,如前文示例,直接调用set方法,传递Integer类型参数,会在编译阶段报错。
1 import java.lang.reflect.*;
2
3 public class GenericsUsingDemo {
4
5
6 public static void main(String[] args) throws Exception {
7 GenericsDemo<String> g_obj = new GenericsDemo<String>();
8 Class<?> clazz = g_obj.getClass();
9 Method method = clazz.getMethod("set", Object.class);
10 method.invoke(g_obj, 1);
11 System.out.println(g_obj.get());
12
13
14 }
15
16 }
[root@iZbp1fza94gkbdpgoq00xcZ test]# javac GenericsUsingDemo.java
[root@iZbp1fza94gkbdpgoq00xcZ test]# java GenericsUsingDemo
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at GenericsUsingDemo.main(GenericsUsingDemo.java:11)