Skip to content

Commit ddbb2ad

Browse files
committed
第二十章 泛型 校订+翻译更新 边界
1 parent 14b4717 commit ddbb2ad

File tree

1 file changed

+309
-6
lines changed

1 file changed

+309
-6
lines changed

docs/book/20-Generics.md

Lines changed: 309 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
然而,如果你了解其他语言(例如 C++ )的参数化机制,你会发现,Java 泛型并不能满足所有的预期。使用别人创建好的泛型相对容易,但是创建自己的泛型时,就会遇到很多意料之外的麻烦。
1919

20-
这并不是说 Java 泛型毫无用处。在很多情况下,它可以使代码更直接更优雅。不过,如果你见识过那种实现了更纯粹的泛型的编程语言,那么,Java 可能会令你失望。本章会介绍 Java 泛型的优点与局限。我会解释 Java 的泛型是如何发展成现在这样的,希望能够帮助你更有效地使用这个特性。
20+
这并不是说 Java 泛型毫无用处。在很多情况下,它可以使代码更直接更优雅。不过,如果你见识过那种实现了更纯粹的泛型的编程语言,那么,Java 可能会令你失望。本章会介绍 Java 泛型的优点与局限。我会解释 Java 的泛型是如何发展成现在这样的,希望能够帮助你更有效地使用这个特性。[^1]
2121

2222
### 与 C++ 的比较
2323

@@ -1756,13 +1756,317 @@ Note: Recompile with -Xlint:unchecked for details.
17561756

17571757
果然,标准库会产生很多警告。如果你使用过 C 语言,尤其是使用 ANSI C 之前的语言,你会记住警告的特殊效果:发现警告后,可以忽略它们。因此,除非程序员必须对其进行处理,否则最好不要从编译器发出任何类型的消息。
17581758

1759-
Neal GafterJava 5的主要开发人员之一)在他的博客中[^2]指出,他在重写 Java 库时很懒惰,我们不应该做他所做的事情Neal 还指出,他在不破坏现有接口的情况下无法修复某些 Java 库代码。因此,即使某些习惯用法出现在 Java 库源代码中,也不一定是正确的做法。当查看库代码时,我们不能假设这是您在自己的代码中必须要遵循的示例
1759+
Neal GafterJava 5的主要开发人员之一)在他的博客中[^2]指出,他在重写 Java 库时是很随意、马虎的,我们不应该像他那样做Neal 还指出,他在不破坏现有接口的情况下无法修复某些 Java 库代码。因此,即使在 Java 库源代码中出现了一些习惯用法,它们也不一定是正确的做法。当查看库代码时,我们不能认为这就是要在自己代码中必须遵循的示例
17601760

17611761
请注意,在 Java 文献中推荐使用类型标记技术,例如 Gilad Bracha 的论文《Generics in the Java Programming Language》[^3],他指出:“例如,这种用法已广泛用于新的 API 中以处理注解。” 我发现此技术在人们对于舒适度的看法方面存在一些不一致之处;有些人强烈喜欢本章前面介绍的工厂方法。
17621762

17631763
<!-- Bounds -->
17641764
## 边界
17651765

1766+
*边界*(bounds)在本章的前面进行了简要介绍。边界允许我们对泛型使用的参数类型施加约束。尽管这可以强制执行有关应用了泛型类型的规则,但潜在的更重要的效果是我们可以在绑定的类型中调用方法。
1767+
1768+
由于擦除会删除类型信息,因此唯一可用于无限制泛型参数的方法是那些 **Object** 可用的方法。但是,如果将该参数限制为某类型的子集,则可以调用该子集中的方法。为了应用约束,Java 泛型使用了 `extends` 关键字。
1769+
1770+
重要的是要理解,当用于限定泛型类型时,`extends` 的含义与通常的意义截然不同。此示例展示边界的基础应用:
1771+
1772+
```java
1773+
// generics/BasicBounds.java
1774+
1775+
interface HasColor {
1776+
java.awt.Color getColor();
1777+
}
1778+
1779+
class WithColor<T extends HasColor> {
1780+
T item;
1781+
1782+
WithColor(T item) {
1783+
this.item = item;
1784+
}
1785+
1786+
T getItem() {
1787+
return item;
1788+
}
1789+
1790+
// The bound allows you to call a method:
1791+
java.awt.Color color() {
1792+
return item.getColor();
1793+
}
1794+
}
1795+
1796+
class Coord {
1797+
public int x, y, z;
1798+
}
1799+
1800+
// This fails. Class must be first, then interfaces:
1801+
// class WithColorCoord<T extends HasColor & Coord> {
1802+
1803+
// Multiple bounds:
1804+
class WithColorCoord<T extends Coord & HasColor> {
1805+
T item;
1806+
1807+
WithColorCoord(T item) {
1808+
this.item = item;
1809+
}
1810+
1811+
T getItem() {
1812+
return item;
1813+
}
1814+
1815+
java.awt.Color color() {
1816+
return item.getColor();
1817+
}
1818+
1819+
int getX() {
1820+
return item.x;
1821+
}
1822+
1823+
int getY() {
1824+
return item.y;
1825+
}
1826+
1827+
int getZ() {
1828+
return item.z;
1829+
}
1830+
}
1831+
1832+
interface Weight {
1833+
int weight();
1834+
}
1835+
1836+
// As with inheritance, you can have only one
1837+
// concrete class but multiple interfaces:
1838+
class Solid<T extends Coord & HasColor & Weight> {
1839+
T item;
1840+
1841+
Solid(T item) {
1842+
this.item = item;
1843+
}
1844+
1845+
T getItem() {
1846+
return item;
1847+
}
1848+
1849+
java.awt.Color color() {
1850+
return item.getColor();
1851+
}
1852+
1853+
int getX() {
1854+
return item.x;
1855+
}
1856+
1857+
int getY() {
1858+
return item.y;
1859+
}
1860+
1861+
int getZ() {
1862+
return item.z;
1863+
}
1864+
1865+
int weight() {
1866+
return item.weight();
1867+
}
1868+
}
1869+
1870+
class Bounded
1871+
extends Coord implements HasColor, Weight {
1872+
@Override
1873+
public java.awt.Color getColor() {
1874+
return null;
1875+
}
1876+
1877+
@Override
1878+
public int weight() {
1879+
return 0;
1880+
}
1881+
}
1882+
1883+
public class BasicBounds {
1884+
public static void main(String[] args) {
1885+
Solid<Bounded> solid =
1886+
new Solid<>(new Bounded());
1887+
solid.color();
1888+
solid.getY();
1889+
solid.weight();
1890+
}
1891+
}
1892+
```
1893+
1894+
你可能会观察到 **BasicBounds.java** 中似乎包含一些冗余,它们可以通过继承来消除。在这里,每个继承级别还添加了边界约束:
1895+
1896+
```java
1897+
// generics/InheritBounds.java
1898+
1899+
class HoldItem<T> {
1900+
T item;
1901+
1902+
HoldItem(T item) {
1903+
this.item = item;
1904+
}
1905+
1906+
T getItem() {
1907+
return item;
1908+
}
1909+
}
1910+
1911+
class WithColor2<T extends HasColor>
1912+
extends HoldItem<T> {
1913+
WithColor2(T item) {
1914+
super(item);
1915+
}
1916+
1917+
java.awt.Color color() {
1918+
return item.getColor();
1919+
}
1920+
}
1921+
1922+
class WithColorCoord2<T extends Coord & HasColor>
1923+
extends WithColor2<T> {
1924+
WithColorCoord2(T item) {
1925+
super(item);
1926+
}
1927+
1928+
int getX() {
1929+
return item.x;
1930+
}
1931+
1932+
int getY() {
1933+
return item.y;
1934+
}
1935+
1936+
int getZ() {
1937+
return item.z;
1938+
}
1939+
}
1940+
1941+
class Solid2<T extends Coord & HasColor & Weight>
1942+
extends WithColorCoord2<T> {
1943+
Solid2(T item) {
1944+
super(item);
1945+
}
1946+
1947+
int weight() {
1948+
return item.weight();
1949+
}
1950+
}
1951+
1952+
public class InheritBounds {
1953+
public static void main(String[] args) {
1954+
Solid2<Bounded> solid2 =
1955+
new Solid2<>(new Bounded());
1956+
solid2.color();
1957+
solid2.getY();
1958+
solid2.weight();
1959+
}
1960+
}
1961+
```
1962+
1963+
**HoldItem** 拥有一个对象,因此此行为将继承到 **WithColor2** 中,这也需要其参数符合 **HasColor****WithColorCoord2****Solid2** 进一步扩展了层次结构,并在每个级别添加了边界。现在,这些方法已被继承,并且在每个类中不再重复。
1964+
1965+
这是一个具有更多层次的示例:
1966+
1967+
```java
1968+
// generics/EpicBattle.java
1969+
// Bounds in Java generics
1970+
1971+
import java.util.List;
1972+
1973+
interface SuperPower {
1974+
}
1975+
1976+
interface XRayVision extends SuperPower {
1977+
void seeThroughWalls();
1978+
}
1979+
1980+
interface SuperHearing extends SuperPower {
1981+
void hearSubtleNoises();
1982+
}
1983+
1984+
interface SuperSmell extends SuperPower {
1985+
void trackBySmell();
1986+
}
1987+
1988+
class SuperHero<POWER extends SuperPower> {
1989+
POWER power;
1990+
1991+
SuperHero(POWER power) {
1992+
this.power = power;
1993+
}
1994+
1995+
POWER getPower() {
1996+
return power;
1997+
}
1998+
}
1999+
2000+
class SuperSleuth<POWER extends XRayVision>
2001+
extends SuperHero<POWER> {
2002+
SuperSleuth(POWER power) {
2003+
super(power);
2004+
}
2005+
2006+
void see() {
2007+
power.seeThroughWalls();
2008+
}
2009+
}
2010+
2011+
class
2012+
CanineHero<POWER extends SuperHearing & SuperSmell>
2013+
extends SuperHero<POWER> {
2014+
CanineHero(POWER power) {
2015+
super(power);
2016+
}
2017+
2018+
void hear() {
2019+
power.hearSubtleNoises();
2020+
}
2021+
2022+
void smell() {
2023+
power.trackBySmell();
2024+
}
2025+
}
2026+
2027+
class SuperHearSmell
2028+
implements SuperHearing, SuperSmell {
2029+
@Override
2030+
public void hearSubtleNoises() {
2031+
}
2032+
2033+
@Override
2034+
public void trackBySmell() {
2035+
}
2036+
}
2037+
2038+
class DogPerson extends CanineHero<SuperHearSmell> {
2039+
DogPerson() {
2040+
super(new SuperHearSmell());
2041+
}
2042+
}
2043+
2044+
public class EpicBattle {
2045+
// Bounds in generic methods:
2046+
static <POWER extends SuperHearing>
2047+
void useSuperHearing(SuperHero<POWER> hero) {
2048+
hero.getPower().hearSubtleNoises();
2049+
}
2050+
2051+
static <POWER extends SuperHearing & SuperSmell>
2052+
void superFind(SuperHero<POWER> hero) {
2053+
hero.getPower().hearSubtleNoises();
2054+
hero.getPower().trackBySmell();
2055+
}
2056+
2057+
public static void main(String[] args) {
2058+
DogPerson dogPerson = new DogPerson();
2059+
useSuperHearing(dogPerson);
2060+
superFind(dogPerson);
2061+
// You can do this:
2062+
List<? extends SuperHearing> audioPeople;
2063+
// But you can't do this:
2064+
// List<? extends SuperHearing & SuperSmell> dogPs;
2065+
}
2066+
}
2067+
```
2068+
2069+
接下来将要研究的通配符将会把范围限制在单个类型。
17662070

17672071
<!-- Wildcards -->
17682072
## 通配符
@@ -1805,10 +2109,9 @@ Neal Gafter(Java 5的主要开发人员之一)在他的博客中[^2]指出
18052109

18062110

18072111

1808-
1809-
1810-
1811-
2112+
[^1]: 在编写本章期间,Angelika LangerJava 泛型常见问题解答以及她的其他著作(与Klaus Kreft一起)是非常宝贵的。
2113+
[^2]: [http://gafter.blogspot.com/2004/09/puzzling-through-erasureanswer.html](http://gafter.blogspot.com/2004/09/puzzling-through-erasureanswer.html)
2114+
[^3]: 参见本章章末引文。
18122115

18132116

18142117

0 commit comments

Comments
 (0)