1. 为什么需要泛型
2. 泛型类型
2.1. 泛型类
2.2. 泛型接口
3. 泛型方法
4. 类型擦除
5. 泛型和继承
6. 类型边界
7. 类型通配符
7.1. 上界通配符
7.2. 下界通配符
7.3. 无界通配符
7.4. 通配符和向上转型
8. 泛型的约束
9. 泛型**实践
9.1. 泛型命名
9.2. 使用泛型的建议
10. 小结
11. 参考资料
#1. 为什么需要泛型
public class NoGenericsDemo {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add("abc");
list.add(18);
list.add(new double[] {1.0, 2.0});
Object obj1 = list.get(0);
Object obj2 = list.get(1);
Object obj3 = list.get(2);
System.out.println("obj1 = [" + obj1 + "]");
System.out.println("obj2 = [" + obj2 + "]");
int num1 = (int)list.get(0);
int num2 = (int)list.get(1);
int num3 = (int)list.get(2);
System.out.println("num1 = [" + num1 + "]");
System.out.println("num2 = [" + num2 + "]");
System.out.println("num3 = [" + num3 + "]");
}
}
// Output:
// obj1 = [abc]
// obj2 = [18]
// obj3 = [[D@47089e5f]
// Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
// at io.github.dunwu.javacore.generics.NoGenericsDemo.main(NoGenericsDemo.java:23)
编译时的强类型检查
避免了类型转换
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);
List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0); // no cast
泛型编程可以实现通用算法
#2. 泛型类型
#2.1. 泛型类
class name<T1, T2, ..., Tn> { /* ... */ }
未应用泛型的类
public class Info {
public Object getValue() {
return value;
public void setValue(Object value) {
this.value = value;
}
}
单类型参数的泛型类
public class Info<T> {
public Info(T value) {
this.value = value;
public T getValue() {
return value;
public void setValue(T value) {
this.value = value;
@Override
public String toString() {
return "Info{" + "value=" + value + '}';
}
public class GenericsClassDemo01 {
public static void main(String[] args) {
Info<Integer> info = new Info<>();
info.setValue(10);
Info<String> info2 = new Info<>();
info2.setValue("xyz");
System.out.println(info2.getValue());
}
}
// Output:
// 10
// xyz
public static void main(String[] args) {
Info info = new Info();
info.setValue(10);
System.out.println(info.getValue());
info.setValue("abc");
System.out.println(info.getValue());
}
多个类型参数的泛型类
public class MyMap<K,V> {
private K key;
public MyMap(K key, V value) {
this.key = key;
this.value = value;
@Override
public String toString() {
return "MyMap{" + "key=" + key + ", value=" + value + '}';
}
public class GenericsClassDemo02 {
public static void main(String[] args) {
MyMap<Integer, String> map = new MyMap<>(1, "one");
System.out.println(map);
}
}
// Output:
// MyMap{key=1, value=one}
泛型类的类型嵌套
public class GenericsClassDemo03 {
public static void main(String[] args) {
Info<String> info = new Info("Hello");
MyMap<Integer, Info<String>> map = new MyMap<>(1, info);
System.out.println(map);
}
}
// Output:
// MyMap{key=1, value=Info{value=Hello}}
#2.2. 泛型接口
public interface Content<T> {
T text();
}
public class GenericsInterfaceDemo01 implements Content<Integer> {
public GenericsInterfaceDemo01(int text) {
this.text = text;
@Override
public static void main(String[] args) {
GenericsInterfaceDemo01 demo = new GenericsInterfaceDemo01(10);
System.out.print(demo.text());
}
}
// Output:
// 10
实现接口的子类不明确声明泛型类型
public class GenericsInterfaceDemo02<T> implements Content<T> {
public GenericsInterfaceDemo02(T text) {
this.text = text;
@Override
public static void main(String[] args) {
GenericsInterfaceDemo02<String> gen = new GenericsInterfaceDemo02<>("ABC");
System.out.print(gen.text());
}
}
// Output:
// ABC
#3. 泛型方法
public <T> T func(T obj) {}
public class GenericsMethodDemo01 {
public static <T> void printClass(T obj) {
System.out.println(obj.getClass().toString());
public static void main(String[] args) {
printClass("abc");
printClass(10);
}
}
// Output:
// class java.lang.String
// class java.lang.Integer
public class GenericVarargsMethodDemo {
public static <T> List<T> makeList(T... args) {
List<T> result = new ArrayList<T>();
Collections.addAll(result, args);
return result;
public static void main(String[] args) {

List<String> ls = makeList("A");
System.out.println(ls);
ls = makeList("A", "B", "C");
System.out.println(ls);
}
}
// Output:
// [A]
// [A, B, C]
#4. 类型擦除
把泛型中的所有类型参数替换为 Object,如果指定类型边界,则使用类型边界来替换。因此,生成的字节码仅包含普通的类,接口和方法。
擦除出现的类型声明,即去掉 <> 的内容。比如 T get() 方法声明就变成了 Object get() ;List<String> 就变成了 List。如有必要,插入类型转换以保持类型安全。
生成桥接方法以保留扩展泛型类型中的多态性。类型擦除确保不为参数化类型创建新类;因此,泛型不会产生运行时开销。
public class GenericsErasureTypeDemo {
public static void main(String[] args) {
List<Object> list1 = new ArrayList<Object>();
List<String> list2 = new ArrayList<String>();
System.out.println(list1.getClass());
System.out.println(list2.getClass());
}
}
// Output:
// class java.util.ArrayList
// class java.util.ArrayList
#5. 泛型和继承
List<Integer> list = new ArrayList<>();
List<Object> list2 = list; // Erorr
#6. 类型边界
<T extends XXX>
public class GenericsExtendsDemo01 {
static <T extends Comparable<T>> T max(T x, T y, T z) {
T max = x; // 假设x是初始最大值
if (y.compareTo(max) > 0) {
max = y; //y 更大
}
if (z.compareTo(max) > 0) {
max = z; // 现在 z 更大
}
return max; // 返回最大对象
public static void main(String[] args) {
System.out.println(max(3, 4, 5));
System.out.println(max(6.6, 8.8, 7.7));
System.out.println(max("pear", "apple", "orange"));
}
}
// Output:
// 5
// 8.8
// pear
<T extends B1 & B2 & B3>
public class GenericsExtendsDemo02 {
static class A { /* ... */ }
interface B { /* ... */ }
interface C { /* ... java泛型使用基础*/ }
static class D1 <T extends A & B & C> { /* ... */ }
static class D2 <T extends B & A & C> { /* ... */ } // 编译报错
public static void main(String[] args) {
D1<E> demo1 = new D1<>();
System.out.println(demo1.getClass().toString());
D1<String> demo2 = new D1<>(); // 编译报错
}
}
#7. 类型通配符
#7.1. 上界通配符
public class GenericsUpperBoundedWildcardDemo {
public static double sumOfList(List<? extends Number> list) {
double s = 0.0;
for (Number n : list) {
s += n.doubleValue();
}
return s;
public static void main(String[] args) {
List<Integer> li = Arrays.asList(1, 2, 3);
System.out.println("sum = " + sumOfList(li));
}
}
// Output:
// sum = 6.0
#7.2. 下界通配符
public class GenericsLowerBoundedWildcardDemo {
public static void addNumbers(List<? super Integer> list) {
for (int i = 1; i <= 5; i++) {
list.add(i);
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
addNumbers(list);
System.out.println(Arrays.deepToString(list.toArray()));
}
}
// Output:
// [1, 2, 3, 4, 5]
#7.3. 无界通配符
可以使用 Object 类中提供的功能来实现的方法。
使用不依赖于类型参数的泛型类中的方法。
public class GenericsUnboundedWildcardDemo {
public static void printList(List<?> list) {
for (Object elem : list) {
System.out.print(elem + " ");
}
System.out.println();
public static void main(String[] args) {
List<Integer> li = Arrays.asList(1, 2, 3);
List<String> ls = Arrays.asList("one", "two", "three");
printList(li);
printList(ls);
}
}
// Output:
// 1 2 3
// one two three
#7.4. 通配符和向上转型
public class GenericsWildcardDemo {
public static void main(String[] args) {
List<Integer> intList = new ArrayList<>();
List<? extends Integer> intList2 = new ArrayList<>();
List<? extends Number> numList2 = intList2; // OK
}
}
#8. 泛型的约束
泛型类型的类型参数不能是值类型(opens new window)
Pair<int, char> p = new Pair<>(8, 'a'); // 编译错误
不能创建类型参数的实例(opens new window)
public static <E> void append(List<E> list) {
E elem = new E(); // 编译错误
list.add(elem);
}
不能声明类型为类型参数的静态成员(opens new window)
public class MobileDevice<T> {
// ...
}
类型参数不能使用类型转换或 instanceof(opens new window)
public static <E> void rtti(List<E> list) {
if (list instanceof ArrayList<Integer>) { // 编译错误
// ...
}
}
List<Integer> li = new ArrayList<>();
List<Number> ln = (List<Number>) li; // 编译错误
不能创建类型参数的数组(opens new window)
List<Integer>[] arrayOfLists = new List<Integer>[2]; // 编译错误
不能创建、catch 或 throw 参数化类型对象(opens new window)
// Extends Throwable indirectly
// Extends Throwable directly
class QueueFullException<T> extends Throwable { /* ... */ // 编译错误
public static <T extends Exception, J> void execute(List<J> jobs) {
try {
for (J job : jobs)
// ...
} catch (T e) { // compile-time error
// ...
}
}
仅仅是泛型类相同,而类型参数不同的方法不能重载(opens new window)
public class Example {
public void print(Set<String> strSet) { }
public void print(Set<Integer> intSet) { } // 编译错误
}
#9. 泛型**实践
#9.1. 泛型命名
E - Element
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types
#9.2. 使用泛型的建议
消除类型检查告警
List 优先于数组
优先考虑使用泛型来提高代码通用性
优先考虑泛型方法来限定泛型的范围
利用有限制通配符来提升 API 的灵活性
优先考虑类型安全的异构容器
#10. 小结
#11. 参考资料
Java 编程思想(opens new window)
Java 核心技术(卷 1)(opens new window)
Effective java(opens new window)
Oracle 泛型文档(opens new window)
Java 泛型详解(opens new window)
帮助我们改善此页面! (opens new window)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/4905.html