<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://wiki.riguz.com/index.php?action=history&amp;feed=atom&amp;title=Java_generics</id>
	<title>Java generics - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.riguz.com/index.php?action=history&amp;feed=atom&amp;title=Java_generics"/>
	<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=Java_generics&amp;action=history"/>
	<updated>2026-06-02T19:41:49Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.42.3</generator>
	<entry>
		<id>https://wiki.riguz.com/index.php?title=Java_generics&amp;diff=3785&amp;oldid=prev</id>
		<title>Riguz：​Riguz移动页面Blog:关于 Java泛型至Java generics，不留重定向</title>
		<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=Java_generics&amp;diff=3785&amp;oldid=prev"/>
		<updated>2023-12-19T06:02:05Z</updated>

		<summary type="html">&lt;p&gt;Riguz移动页面&lt;a href=&quot;/index.php?title=Blog:%E5%85%B3%E4%BA%8E_Java%E6%B3%9B%E5%9E%8B&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;Blog:关于 Java泛型（页面不存在）&quot;&gt;Blog:关于 Java泛型&lt;/a&gt;至&lt;a href=&quot;/Java_generics&quot; title=&quot;Java generics&quot;&gt;Java generics&lt;/a&gt;，不留重定向&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2023年12月19日 (二) 06:02的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;zh-Hans-CN&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;（没有差异）&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Riguz</name></author>
	</entry>
	<entry>
		<id>https://wiki.riguz.com/index.php?title=Java_generics&amp;diff=2619&amp;oldid=prev</id>
		<title>imported&gt;Riguz：​泛型是Java1.5之后一个比较有用的特性，有点类似于C++的模板。最简单的一个例子：

```java
class Wrapper&lt;T&gt; {
    final T data;

    Wrapper(T data) {
        this.data = data;
    }
}
```
有一些可能不是特别常用的Generics，我们来简单看一下。</title>
		<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=Java_generics&amp;diff=2619&amp;oldid=prev"/>
		<updated>2017-12-21T00:00:00Z</updated>

		<summary type="html">&lt;p&gt;泛型是Java1.5之后一个比较有用的特性，有点类似于C++的模板。最简单的一个例子：  ```java class Wrapper&amp;lt;T&amp;gt; {     final T data;      Wrapper(T data) {         this.data = data;     } } ``` 有一些可能不是特别常用的Generics，我们来简单看一下。&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;泛型是Java1.5之后一个比较有用的特性，有点类似于C++的模板。最简单的一个例子：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
class Wrapper&amp;lt;T&amp;gt; {&lt;br /&gt;
    final T data;&lt;br /&gt;
&lt;br /&gt;
    Wrapper(T data) {&lt;br /&gt;
        this.data = data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
有一些可能不是特别常用的Generics，我们来简单看一下。&lt;br /&gt;
&lt;br /&gt;
= Bounded Generics=&lt;br /&gt;
== Multiple bound==&lt;br /&gt;
如果一个类继承了多个接口，是这样的写法：&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
interface I {}&lt;br /&gt;
interface M {}&lt;br /&gt;
abstract class C {}&lt;br /&gt;
&lt;br /&gt;
class Foo extends C implements I,M {}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
假如一个方法的泛型参数包含多个Bound，则要这样写了：&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;T extends I &amp;amp; M&amp;gt; void bar(T arg){}&lt;br /&gt;
&amp;lt;T extends C&amp;gt; void ooo(T arg){}&lt;br /&gt;
&amp;lt;T extends C &amp;amp; I &amp;amp; M&amp;gt; void xxx(T arg){}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
== Unbounded wildcards==&lt;br /&gt;
&lt;br /&gt;
使用 ? 修饰符可以用作类型转换，List&amp;lt;?&amp;gt; 意味着是一个未知类型的List，可能是`List&amp;lt;A&amp;gt;` 也可能是`List&amp;lt;B&amp;gt;`&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
private final List&amp;lt;String&amp;gt; strList = Arrays.asList(&amp;quot;Hello&amp;quot;, &amp;quot;World!&amp;quot;);&lt;br /&gt;
private final List&amp;lt;Integer&amp;gt; intList = Arrays.asList(1, 2, 3);&lt;br /&gt;
private final List&amp;lt;Float&amp;gt; floatList = Arrays.asList(1.1f, 2.1f, 3.1f);&lt;br /&gt;
private final List&amp;lt;Number&amp;gt; numberList = Arrays.asList(1, 1.0f, 3000L);&lt;br /&gt;
&lt;br /&gt;
public void cast() {&lt;br /&gt;
    List&amp;lt;?&amp;gt; unknownList = null;&lt;br /&gt;
    unknownList = strList;&lt;br /&gt;
    unknownList = intList;&lt;br /&gt;
    unknownList = floatList;&lt;br /&gt;
    unknownList = numberList;&lt;br /&gt;
&lt;br /&gt;
    for (int i = 0; i &amp;lt; unknownList.size(); i++) {&lt;br /&gt;
        // Number item = unknownList.get(i); wrong! &lt;br /&gt;
        Object item = unknownList.get(i);&lt;br /&gt;
        System.out.println(item + &amp;quot;(&amp;quot; + item.getClass() + &amp;quot;)&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
/* output&lt;br /&gt;
1(class java.lang.Integer)&lt;br /&gt;
1.0(class java.lang.Float)&lt;br /&gt;
3000(class java.lang.Long)&lt;br /&gt;
*/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
== Upper bounded wildcards==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public static double sumOfList(List&amp;lt;? extends Number&amp;gt; list) {&lt;br /&gt;
    double s = 0.0;&lt;br /&gt;
    for (Number n : list)&lt;br /&gt;
        s += n.doubleValue();&lt;br /&gt;
    return s;&lt;br /&gt;
}&lt;br /&gt;
//...&lt;br /&gt;
sumOfList(Arrays.asList(1, 2, 3));&lt;br /&gt;
sumOfList(Arrays.asList(1.0f, 2.0f, 3.0f));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Lower bounded wildcards==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public static void addNumbers(List&amp;lt;? super Number&amp;gt; list) {&lt;br /&gt;
    for (int i = 1; i &amp;lt;= 10; i++) {&lt;br /&gt;
        list.add(i);&lt;br /&gt;
        list.add(1.0f);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
addNumbers(new ArrayList&amp;lt;Number&amp;gt;());&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Type erase=&lt;br /&gt;
== Type erase process==&lt;br /&gt;
&lt;br /&gt;
Java的泛型是编译时有效的，在运行时，所有泛型参数会被编译器擦除。擦除的规则如下：&lt;br /&gt;
&lt;br /&gt;
* 如果参数是有Bound的，则会替换成这个Bound&lt;br /&gt;
* 如果是Unbounded，则会替换成Object&lt;br /&gt;
&lt;br /&gt;
如下所示：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class Node&amp;lt;T&amp;gt; {                         // public class Node {&lt;br /&gt;
    private T data;                            //     private Object data;&lt;br /&gt;
    private Node&amp;lt;T&amp;gt; next;                      //     private Node next;&lt;br /&gt;
    public Node(T data, Node&amp;lt;T&amp;gt; next) {        //     public Node(Object data, Node next) {&lt;br /&gt;
        this data = data;                      //         this data = data;&lt;br /&gt;
        this next = next;                      //         this next = next;&lt;br /&gt;
    }                                          //     }&lt;br /&gt;
                                               // &lt;br /&gt;
    public T getData() { return data; }        //    	public Object getData() { return data; }&lt;br /&gt;
}                                              // }&lt;br /&gt;
&lt;br /&gt;
public class Node&amp;lt;T extends Comparable&amp;lt;T&amp;gt;&amp;gt; {   // public class Node {&lt;br /&gt;
    private T data;                            //     private Comparable data;&lt;br /&gt;
    private Node&amp;lt;T&amp;gt; next;                      //     private Node next;&lt;br /&gt;
    public Node(T data, Node&amp;lt;T&amp;gt; next) {        //     public Node(Comparable data, Node next) {&lt;br /&gt;
        this.data = data;                      //         this.data = data;&lt;br /&gt;
        this.next = next;                      //         this.next = next;&lt;br /&gt;
    }                                          //     }&lt;br /&gt;
                                               // &lt;br /&gt;
    public T getData() { return data; }        //     public Comparable getData() { return data; }&lt;br /&gt;
}                                              // }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
== Bridge method==&lt;br /&gt;
按照上面的擦除也会带来问题。考虑下面的例子，如果有一个子类：&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class MyNode extends Node&amp;lt;Integer&amp;gt; {       // public class MyNode extends Node {&lt;br /&gt;
    public MyNode(Integer data) { super(data); }  //     public MyNode(Integer data) { super(data); }&lt;br /&gt;
                                                  // &lt;br /&gt;
    public void setData(Integer data) {           //     public void setData(Integer data) {&lt;br /&gt;
        System.out.println(&amp;quot;MyNode.setData&amp;quot;);     //         System.out.println(&amp;quot;MyNode.setData&amp;quot;);&lt;br /&gt;
        super.setData(data);                      //         super.setData(data);&lt;br /&gt;
    }                                             //     }&lt;br /&gt;
}                                                 // }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
然后，我们考虑如下的代码：&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
MyNode mn = new MyNode(5);                     // MyNode mn = new MyNode(5);&lt;br /&gt;
Node n = mn;                                   // Node n = (MyNode)mn;&lt;br /&gt;
n.setData(&amp;quot;Hello&amp;quot;);                            // n.setData(&amp;quot;Hello&amp;quot;);&lt;br /&gt;
Integer x = mn.data;                           // Integer x = (String)mn.data;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
这里调用setData则会参数类型不能匹配。为了解决这个问题，Java编译器会生成一个Bridge method:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public void setData(Object data) {&lt;br /&gt;
    setData((Integer) data);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Q&amp;amp;A=&lt;br /&gt;
&lt;br /&gt;
== List\&amp;lt;?\&amp;gt; vs List\&amp;lt;Object\&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
&amp;gt;It&amp;#039;s important to note that List&amp;lt;Object&amp;gt; and List&amp;lt;?&amp;gt; are not the same. You can insert an Object, or any subtype of &amp;gt;Object, into a List&amp;lt;Object&amp;gt;. But you can only insert null into a List&amp;lt;?&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== extends vs super==&lt;br /&gt;
&lt;br /&gt;
实际上泛型仅仅是为了做一个编译时的检查，从逻辑上确保程序是类型安全的。假设我们有这样的类定义：&lt;br /&gt;
Object-&amp;gt;Parent-&amp;gt;T-&amp;gt;Child&lt;br /&gt;
我们有这样几种写法：&lt;br /&gt;
&lt;br /&gt;
* ```List&amp;lt;?&amp;gt;``` 代表一种未知类型的List，可能是```List&amp;lt;Object&amp;gt;```，也可能是```List&amp;lt;Child&amp;gt;```，都可以&lt;br /&gt;
* ```List&amp;lt;? extends T&amp;gt;``` 代表T或者T的子类的List，可以是```List&amp;lt;T&amp;gt;```，也可以是```List&amp;lt;Child&amp;gt; ```&lt;br /&gt;
* ```List&amp;lt;? super T&amp;gt;``` 代表T或者T的父类的List，可以是```List&amp;lt;T&amp;gt;，List&amp;lt;Parent&amp;gt;，List&amp;lt;Object&amp;gt;```&lt;br /&gt;
&lt;br /&gt;
我们有一个事实就是，Child是一定可以转化T或者Parent的，但是一个T不一定能转化成Child，因为可能会是别的子类。&lt;br /&gt;
比如我们现在做两个列表的拷贝，&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public static &amp;lt;T&amp;gt; void copy(List dest, List src)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
想实现从一个列表拷贝到另一个列表，比如&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
List&amp;lt;Parent&amp;gt; parents;&lt;br /&gt;
List&amp;lt;T&amp;gt; ts;&lt;br /&gt;
List&amp;lt;Child&amp;gt; childs;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
基于上面说的类的继承的事实，ts/childs显然是可以转化成parents的，但是ts无法确保能转化成childs。因此我们的拷贝方法要这样定义：&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class Collections { &lt;br /&gt;
  public static &amp;lt;T&amp;gt; void copy  &lt;br /&gt;
  ( List&amp;lt;? super T&amp;gt; dest, List&amp;lt;? extends T&amp;gt; src) {  // uses bounded wildcards &lt;br /&gt;
      for (int i=0; i&amp;lt;src.size(); i++) &lt;br /&gt;
        dest.set(i,src.get(i)); &lt;br /&gt;
  } &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
因为在desc.set()方法中，需要的是一个能够转化为T的对象的，src中&amp;lt;? extends T&amp;gt; 保证了src中的元素一定是一个T。&lt;br /&gt;
&lt;br /&gt;
See also:&lt;br /&gt;
&lt;br /&gt;
* [https://docs.oracle.com/javase/tutorial/java/generics/index.html Lesson: Generics (Updated)]&lt;/div&gt;</summary>
		<author><name>imported&gt;Riguz</name></author>
	</entry>
</feed>