Java 泛型(generics)详解及代码示例、Java 类型通配符详解及代码示例
- 概念
- Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
- java中使用泛型举例:
-
- List接口也使用了泛型:
- List接口也使用了泛型:
-
- ArrayList 是泛型类。
- ArrayList 是泛型类。
- 泛型标记符:
- Java中的泛型标记符有:
1、E - Element (在集合中使用,因为集合中存放的是元素)
2、T - Type(Java 类)
3、K - Key(键)
4、V - Value(值)
5、N - Number(数值类型)
6、? - 表示不确定的 java 类型
- 泛型分类
- 泛型方法
- 泛型类
- 泛型方法:
-
泛型方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。定义泛型方法的规则如下:
1、所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的 )。
2、每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
3、类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
4、泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像 int、double、char 等)。 -
泛型方法代码示例:
//collectionReverse.java
import java.util.Arrays;
import java.util.Collections;
public class GenericMethodDemo {
public static <E> void collectionReverse(E[] colArray){
Collections.reverse(Arrays.asList(colArray));
System.out.println("逆序后的集合的排列顺序为:"+Arrays.toString(colArray));
}
public static void main(String[] args) {
Integer[] i = {
1, 2, 3, 4, 5};
Character[] c = {
'G', 'e', 'n', 'e', 'r', 'i', 'c'};
String[] s = {
"first", "second", "third", "fourth", "fifth"};
System.out.println("原序集合顺序为:"+Arrays.toString(i));
collectionReverse(i);
System.out.println("--------------------------------------");
System.out.println("原序集合顺序为:"+Arrays.toString(c));
collectionReverse(c);
System.out.println("--------------------------------------");
System.out.println("原序集合顺序为:"+Arrays.toString(s));
collectionReverse(s);
}
}
//执行结果如下:
//原序集合顺序为:[1, 2, 3, 4, 5]
//逆序后的集合的排列顺序为:[5, 4, 3, 2, 1]
//--------------------------------------
//原序集合顺序为:[G, e, n, e, r, i, c]
//逆序后的集合的排列顺序为:[c, i, r, e, n, e, G]
//--------------------------------------
//原序集合顺序为:[first, second, third, fourth, fifth]
//逆序后的集合的排列顺序为:[fifth, fourth, third, second, first]
//Process finished with exit code 0
- 有界的类型参数:
可能有时候,你会想限制那些被允许传递到一个类型参数的类型种类范围。例如,一个操作数字的方法可能只希望接受Number或者Number子类的实例。这就是有界类型参数的目的。要声明一个有界的类型参数,首先列出类型参数的名称,后跟extends关键字,最后紧跟它的上界。 - 有界的类型参数代码示例:
//BoundedGenericMethodDemo.java
import java.util.Arrays;
import java.util.Collections;
public class BoundedGenericMethodDemo {
public static <E extends Number> void collectionReverse(E[] colArray){
Collections.reverse(Arrays.asList(colArray));
System.out.println("逆序后的集合的排列顺序为:"+Arrays.toString(colArray));
}
public static void main(String[] args) {
Integer[] i = {
1, 2, 3, 4, 5};
Character[] c = {
'G', 'e', 'n', 'e', 'r', 'i', 'c'};
String[] s = {
"first", "second", "third", "fourth", "fifth"};
System.out.println("原序集合顺序为:"+Arrays.toString(i));
collectionReverse(i);
System.out.println("--------------------------------------");
System.out.println("原序集合顺序为:"+Arrays.toString(c));
collectionReverse(c);
System.out.println("--------------------------------------");
System.out.println("原序集合顺序为:"+Arrays.toString(s));
collectionReverse(s);
}
}
//执行结果如下,由于定义了类型上限,即调用泛型方法传递的参数必须是Number 类的子类,所以传递Character[] 和 String[] 都会报错。将collectionReverse(c) 和 collectionReverse(s) 两行代码注释掉即可:
//java: 无法将类 com.example.utils.generic.BoundedGenericMethodDemo中的方法 collectionReverse应用到给定类型;
// 需要: E[]
// 找到: java.lang.Character[]
// 原因: 推断类型不符合上限
// 推断: java.lang.Character
// 上限: java.lang.Number
- 泛型类
- 泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。
- 泛型类代码示例:
//GenericClassDemo.java
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
public class GenericClassDemo<K, V> {
private K k;
private V v;
public void put(K k, V v){
this.k = k;
this.v = v;
}
public V get(K k){
return v;
}
public static void main(String[] args) {
GenericClassDemo<String, Character[]> gcd = new GenericClassDemo<>();
gcd.put("java_say", new Character[]{
'h','e','l','l','o','泛','型','类'});
Character[] java_says = gcd.get("java_say");
System.out.println("打印出来的值为:"+Arrays.toString(java_says));
}
}
//执行结果如下:
//打印出来的值为:[h, e, l, l, o, 泛, 型, 类]
//Process finished with exit code 0
- 类型通配符
- 类型通配符一般是使用 ? 代替具体的类型参数。例如 List<?> 在逻辑上是 List<String>, List<Integer> 等所有 List<具体类型实参> 的父类。
- 只有泛型类的类型参数可以使用 ? 类型通配符来替换。代码示例如下:
//GenericClassBox.java
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class GenericClassBox<K, V> {
private K k;
private V v;
public void put(K k, V v){
this.k = k;
this.v = v;
}
public V get(K k){
return v;
}
public static void main(String[] args) {
GenericClassBox<String, String> gcd1 = new GenericClassBox<>();
gcd1.put("java_say","hello, 类型通配符");
GenericClassBox<Integer, Integer> gcd2 = new GenericClassBox<>();
gcd2.put(2,2);
GenericClassBox<Character, String> gcd3 = new GenericClassBox<>();
gcd3.put(new Character('a'), "bc");
getValue(gcd1);
System.out.println("--------------------------");
getValue(gcd2);
System.out.println("--------------------------");
getValue(gcd3);
}
public static void getValue(GenericClassBox<?,?> data){
System.out.println("使用通配符获取到的值为:"+data.v);
}
}
//执行结果如下:
//使用通配符获取到的值为:hello, 类型通配符
//--------------------------
//使用通配符获取到的值为:2
//--------------------------
//使用通配符获取到的值为:bc
//Process finished with exit code 0
-
有界的类型通配符:
1、<? extends T>表示该通配符所代表的类型是T类型的子类。
2、<? super T>表示该通配符所代表的类型是T类型的父类。 -
有界的类型通配符代码示例:
//BoundedGenericClassBox.java
public class BoundedGenericClassBox<K, V> {
private K k;
private V v;
public void put(K k, V v){
this.k = k;
this.v = v;
}
public V get(K k){
return v;
}
public static void main(String[] args) {
BoundedGenericClassBox<Integer, String> gcd1 = new BoundedGenericClassBox<>();
gcd1.put(1,"hello, 有界的类型通配符");
getValue(gcd1);
}
public static void getValue(BoundedGenericClassBox<? extends Number,? super String> data){
//第一个类型通配符 ? 代表的类型必须是Number的子类
//第二个类型通配符 ? 代表的类型必须是String的父类
System.out.println("使用有界的通配符获取到的值为:"+data.v);
}
}
//执行结果如下:
//使用有界的通配符获取到的值为:hello, 有界的类型通配符
//Process finished with exit code 0