The Java™ Tutorials — Generics :Wildcard Capture and Helper Methods 通配符匹配和辅助方法

The Java™ Tutorials — Generics :Wildcard Capture and Helper Methods 通配符匹配和辅助方法

原文地址:https://docs.oracle.com/javase/tutorial/java/generics/capture.html

关键点

  • 利用辅助方法解决通配符类型推断问题: 
    • 原理:利用泛型的类型推断
public class WildcardFixed {

void foo(List<?> i) {
fooHelper(i);
}


// Helper method created so that the wildcard can be captured
// through type inference.
private <T> void fooHelper(List<T> l) {
l.set(0, l.get(0));
}

}
  • 辅助方法格式:“所辅助的方法的名称+Helper”

全文翻译

In some cases, the compiler infers the type of a wildcard. For example, a list may be defined as List<?> but, when evaluating an expression, the compiler infers a particular type from the code. This scenario is known as wildcard capture.

在某些情况下,编译器会自动推断出通配符的具体类型。例如,一个列表也许被定义为List<?>,但是求一个表达式的值时,编译器就会从代码环境中推断出一个具体的类型。这个场景被称为“通配符匹配”

For the most part, you don’t need to worry about wildcard capture, except when you see an error message that contains the phrase “capture of”.

多半情况下,你不用担心通配符匹配,除非当你看到一条包含短语“capture of”的错误信息。

The WildcardError example produces a capture error when compiled:

这个WildcardError例子在编译时产生了一个匹配错误:

import java.util.List;

public class WildcardError {

void foo(List<?> i) {
i.set(0, i.get(0));
}
}

In this example, the compiler processes the i input parameter as being of type Object. When the foo method invokes List.set(int, E), the compiler is not able to confirm the type of object that is being inserted into the list, and an error is produced. When this type of error occurs it typically means that the compiler believes that you are assigning the wrong type to a variable. Generics were added to the Java language for this reason — to enforce type safety at compile time.

在本例中,编译器将输入参数i处理为Object类型。当foo方法调用了List.set(int,E)时,编译器是无法确定当前正在插入列表的对象的类型,错误就会产生。当这样的错误发生时,这通常意味着编译器认为你将一个错误的类型传给了变量。这也正是泛型被引入Java语言的原因——增加编译时类型安全。

The WildcardError example generates the following error when compiled by Oracle’s JDK 7 javac implementation:

这个WildcardError的例子在编译时产生了下面的错误,编译是通过Oracle的JDK7版本实现的javac命令进行的:

WildcardError.java:6: error: method set in interface List<E> cannot be applied to given types;
i.set(0, i.get(0));
^
required: int,CAP#1
found: int,Object
reason: actual argument Object cannot be converted to CAP#1 by method invocation conversion
where E is a type-variable:

E extends Object declared in interface List
where CAP#1 is a fresh type-variable:
CAP#1 extends Object from capture of ?
1 error

In this example, the code is attempting to perform a safe operation, so how can you work around the compiler error? You can fix it by writing a private helper method which captures the wildcard. In this case, you can work around the problem by creating the private helper method, fooHelper, as shown in WildcardFixed:

在这个例子中,代码正在尝试执行安全操作,那么如何处理这个错误呢?你可以通过写一个私有辅助方法来解决这个问题。对于本例而言,你可以创建一个私有辅助方法fooHelper,正如WildcardFixed中所示的那样:

public class WildcardFixed {

void foo(List<?> i) {
fooHelper(i);
}


// Helper method created so that the wildcard can be captured
// through type inference.
private <T> void fooHelper(List<T> l) {
l.set(0, l.get(0));
}

}

Thanks to the helper method, the compiler uses inference to determine that T is CAP#1, the capture variable, in the invocation. The example now compiles successfully.

多亏了辅助方法,编译器利用类型推断得出T是CAP#1,即为方法调用中的匹配变量。这个案例现在可以成功编译了。

By convention, helper methods are generally named originalMethodNameHelper.

按惯例,辅助方法一般被命名为“对应方法名 + Helper”。

Now consider a more complex example, WildcardErrorBad:

现在看个更复杂的例子,WildcardErrorBad:

import java.util.List;

public class WildcardErrorBad {

void swapFirst(List<? extends Number> l1, List<? extends Number> l2) {
Number temp = l1.get(0);
l1.set(0, l2.get(0)); // expected a CAP#1 extends Number,
// got a CAP#2 extends Number;
// same bound, but different types
l2.set(0, temp); // expected a CAP#1 extends Number,
// got a Number
}
}

In this example, the code is attempting an unsafe operation. For example, consider the following invocation of the swapFirst method:

在这个例子中,代码正在尝试一种不安全的操作。例如,考虑下下面的swapFirst方法调用:

List<Integer> li = Arrays.asList(1, 2, 3);
List<Double> ld = Arrays.asList(10.10, 20.20, 30.30);
swapFirst(li, ld);

While List<Integer> and List<Double> both fulfill the criteria ofList<? extends Number>, it is clearly incorrect to take an item from a list of Integer values and attempt to place it into a list of Double values.

虽然LIst<Integer>List<Double>都满足List<? extends Number>的条件,但是很明显,想把一个Integer列表的元素放入一个Double类型的列表是不正确的。

Compiling the code with Oracle’s JDK javac compiler produces the following error:

利用Oracle JDK的javac命令编译这段代码就会产生下面的错误信息:

WildcardErrorBad.java:7: error: method set in interface List<E> cannot be applied to given types;
l1.set(0, l2.get(0)); // expected a CAP#1 extends Number,
^
required: int,CAP#1
found: int,Number
reason: actual argument Number cannot be converted to CAP#1 by method invocation conversion
where E is a type-variable:

E extends Object declared in interface List
where CAP#1 is a fresh type-variable:
CAP#1 extends Number from capture of ? extends Number
WildcardErrorBad.java:10: error: method set in interface List<E> cannot be applied to given types;
l2.set(0, temp); // expected a CAP#1 extends Number,
^
required: int,CAP#1
found: int,Number
reason: actual argument Number cannot be converted to CAP#1 by method invocation conversion
where E is a type-variable:

E extends Object declared in interface List
where CAP#1 is a fresh type-variable:
CAP#1 extends Number from capture of ? extends Number
WildcardErrorBad.java:15: error: method set in interface List<E> cannot be applied to given types;
i.set(0, i.get(0));
^
required: int,CAP#1
found: int,Object
reason: actual argument Object cannot be converted to CAP#1 by method invocation conversion
where E is a type-variable:

E extends Object declared in interface List
where CAP#1 is a fresh type-variable:
CAP#1 extends Object from capture of ?
3 errors

There is no helper method to work around the problem, because the code is fundamentally wrong.

没有哪种辅助方法可以解决这个问题,因为代码从根本上就是错误的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值