Java8 Generic泛型详解

    科技2026-02-21  7

    preface

    基于Java 8 的generic的介绍

    1.Generic(Why)

    可以让某些运行期间出现的错误(例如cast),现在通过compile期间的强类型检查,来检出错误可以通过Generic,来编写一个generic type的类或者接口的模板,这样可以创建基于某一特定功能但具有不同数据类型的类,也可以通过generic method来编写针对某些具有相同特性的队形进行操作generic方法可以消除cast的使用

    2.Generic class (What)

    2.1 generic type

    generic type的定义:就是在类型上参数化的泛型类或者接口

    定义generic type 的模板(generic 类和接口都是这么定义的)

    class name<T1, T2, ..., Tn> { /* ... */ }

    例子:

    /** * Generic version of the Box class. * @param <T> the type of the value being boxed */ public class Box<T> { // T stands for "Type" private T t; public void set(T t) { this.t = t; } public T get() { return t; } } public interface Pair<K, V> { public K getKey(); public V getValue(); } //多个 type parameter public class OrderedPair<K, V> implements Pair<K, V> { private K key; private V value; public OrderedPair(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } }

    继承(inheritance),implement

    继承或者实现的原则:

    就是泛型父类或者接口的type parameter 在子类泛型中要保留下来,自己可以新增额外的type parameter对于Parameterized type,只有相同type argument的的Parameterized type 父类和子类之间才存在subtype(父子的关系),如果不是相同的Parameterized type不同,则不存在subtype关系

    例子

    Box<Number> 跟 BOX<Integer>不存在父子关系 interface PayloadList<E,P> extends List<E> { void setPayload(int index, P val); ... }

    type parameter

    命名方式

    E - Element (used extensively by the Java Collections Framework)K - KeyN - NumberT - TypeV - ValueS,U,V etc. - 2nd, 3rd, 4th types

    概念的区别

    public class Box<T> {} Box<String> box; T为type parameter String 为 type argument BOX<T> generic type Box<String> Parameterized type

    2.2 Bouded Type Parameters

    什么是 Bouded Type Parameters

    就是如果是Box的时候,T可以为任何类型,包括 Parameterized Type 类型,但如果我们想要该Box geneirc type 只能 parameterized 为某一指定范围的类型,那么则需要使用Bounded Type Parameter 来完成这个需求

    有什么用

    一:就是规范Parameterized Type的范围,这可以让我们针对这些类型进行某些特定的操作

    二:在实现泛型算法的时候,需要用到该功能

    如何定义

    Class A { /* ... */ } interface B { /* ... */ } interface C { /* ... */ } class D <T extends A & B & C> { /* ... */ }

    例子:

    public class Box<T> { private T t; public void set(T t) { this.t = t; } public T get() { return t; } public <U extends Number> void inspect(U u){ System.out.println("T: " + t.getClass().getName()); System.out.println("U: " + u.getClass().getName()); } public static void main(String[] args) { Box<Integer> integerBox = new Box<Integer>(); integerBox.set(new Integer(10)); integerBox.inspect("some text"); // error: this is still String! } }

    3.Generic Method

    3.1 Generic Method

    如何定义Generic Method

    public class Util { //定义 public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) { return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue()); } } public class Pair<K, V> { private K key; private V value; public Pair(K key, V value) { this.key = key; this.value = value; } public void setKey(K key) { this.key = key; } public void setValue(V value) { this.value = value; } public K getKey() { return key; } public V getValue() { return value; } } //使用 Pair<Integer, String> p1 = new Pair<>(1, "apple"); Pair<Integer, String> p2 = new Pair<>(2, "pear"); boolean same = Util.<Integer, String>compare(p1, p2); //也可以不同指定方法的type argument,因为其会compile会自动推断出其类型 Pair<Integer, String> p1 = new Pair<>(1, "apple"); Pair<Integer, String> p2 = new Pair<>(2, "pear"); boolean same = Util.compare(p1, p2);

    3.2 Generic Method and Bound Type Parameters

    跟上面讲的概念差不多

    例子

    public static <T> int countGreaterThan(T[] anArray, T elem) { int count = 0; for (T e : anArray) if (e > elem) // compiler error ++count; return count; } //改进 public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) { int count = 0; for (T e : anArray) if (e.compareTo(elem) > 0) ++count; return count; } public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) { int count = 0; for (T e : anArray) if (e.compareTo(elem) > 0) ++count; return count; }

    4.generic 算法

    4.1 什么是generic 算法

    可以针对某一范围内的类,为其提供通用的算法,其实bound type parameter就可以实现实现该功能(但类型在编译期间就确定了),但如果该算法在static method中实现的话,因为generic method不能修饰为static,所以上面的技术都不能满足为什么需要把generic 算法实现在static method,因为可以实现操作与数据的分离,可以使得整个代码的结构更加的清晰,耦合性低

    4.2 借用什么技术可以实现在static method中的generic 算法

    可以使用WildCards技术实现该功能其实本质上就是使用多态的功能来完成该算法的,即父类指向子类

    5.WildCards

    what:

    就是之前有讲过,List 和List,List之间不存在subtype,那如果想要List,List共同的Paramter type 的父类,如果做到 ,那则需WildCards,来创建该Paramterized type 父类,

    why

    可以在static method中实现通用算法

    如何使用Wild

    //List<? extends Number>是已经参数化(parameterd)的类,其是List<Integer>,List<Double>共同的父类,这样就可以通过该父类来动态操作List中一些通用功能,例如遍历 public static double sumOfList(List<? extends Number> list) { double s = 0.0; for (Number n : list) s += n.doubleValue(); return s; } List<Integer> li = Arrays.asList(1, 2, 3); System.out.println("sum = " + sumOfList(li)); List<Double> ld = Arrays.asList(1.2, 2.3, 3.5); System.out.println("sum = " + sumOfList(ld)); class NaturalNumber { private int i; public NaturalNumber(int i) { this.i = i; } // ... } class EvenNumber extends NaturalNumber { public EvenNumber(int i) { super(i); } // ... } //注意:不是在List中所有的通用方法都可以被调用,一旦涉及到具体类型的操作,则不可以,否则出现编译错误 List<EvenNumber> le = new ArrayList<>(); List<? extends NaturalNumber> ln = le; ln.add(new NaturalNumber(35)); // compile-time error //原则: You can add null. You can invoke clear. You can get the iterator and invoke remove. You can capture the wildcard and write elements that you've read from the list. //总结 就是如果某些操作是涉及到特定类型的时候,则不能使用该操作,例如add(),所以只能去添加null clear()操作是所有的List类型都是可以的,所以可以进行

    更多具体的内容,请查看官方文档

    6.generic 的限制

    Cannot Instantiate Generic Types with Primitive TypesCannot Create Instances of Type ParametersCannot Declare Static Fields Whose Types are Type ParametersCannot Use Casts or instanceof With Parameterized TypesCannot Create Arrays of Parameterized TypesCannot Create, Catch, or Throw Objects of Parameterized TypesCannot Overload a Method Where the Formal Parameter Types of Each Overload Erase to the Same Raw Type

    7.Generic(How)

    8.资料

    https://docs.oracle.com/javase/tutorial/java/generics/restrictions.html
    Processed: 0.010, SQL: 9