简体   繁体   English

泛型:如何捕获通配符?

[英]Generics: How to capture a wildcard?

No, this question is not about the difference between ? 不,这个问题不是关于它们之间的区别吗? and T; 和T; it is about how I turn a < ? 这是关于我如何变成<? > argument into a named < T >. >参数命名为<T>。 Consider this example code: 考虑这个示例代码:

import java.io.Serializable;

class A<T extends Serializable> {
    <S extends Serializable> void bar(S arg) { }
    void bar2(T arg) { }
}

public class B {
    A<? extends Serializable> myA = null;    
    <T extends Serializable> void foo(T arg) {
        myA.bar(arg);
        myA.bar2(arg);
    }
}

My problem is the fact that the above doesn't compile; 我的问题是上面没有编译的事实; the call to bar2() gives me 对bar2()的调用给了我

The method bar2(capture#2-of ? extends Serializable) in the type
A<capture#2-of ? extends Serializable> is not applicable for the arguments (T)

I guess the "reason" for that is that myA is a < ? 我猜这个“原因”是myA是<? extends Serializable > ; extends Serializable> ; but the T in B.foo ... is well, a named T; 但B.foo中的T ......很好,一个名叫T; and not the wildcard ?. 而不是通配符?

One way to "fix" this would be to make < T extends Serializable > a type parameter for class B ... but that basically conflicts with my other usage of that class. “修复”这种方法的一种方法是使<T extends Serializable>为B类的类型参数...但这基本上与我对该类的其他用法冲突。 Meaning: I ended up writing down B and its member myA like this - exactly because I don't want to parameterize the B class. 含义:我最终写下了B及其成员myA,这完全是因为我不想参数化B类。 So, I started with only the bar2() method; 所以,我开始只使用bar2()方法; and then added bar() later on ... but that doesn't really help either. 然后稍后添加了bar()......但这并没有真正帮助。

So - is there a way to for my class B to use A.bar2() as "intended" in my example code? 那么 - 有没有办法让我的班级B在我的示例代码中使用A.bar2()作为“预期”?

EDIT: and just to be precise - the bar() method doesn't help me; 编辑:而且确切地说 - bar()方法对我没有帮助; as the "S" there ... isn't compatible with the "T" that I am really using in my A class. 因为那里的“S”......与我在A班中真正使用的“T”不兼容。

You're in a dead end. 你走到了尽头。

A<? extends Serializable> myA = ...;

So myA is a A of something unknown. 所以myAA的未知的东西。 It could be a A<String> , or a A<Integer> or a A<Banana> . 它可以是A<String> ,或A<Integer>A<Banana> You just don't know. 你只是不知道。 Let's say it's a A<Banana> . 让我们说这是一个A<Banana>

<T extends Serializable> void foo(T arg) {

So foo() accepts any serializable: String, Integer, Banana, Apple, anything. 所以foo()接受任何可序列化的:String,Integer,Banana,Apple,等等。 Let's say it's called with an Integer as argument. 假设它以Integer作为参数调用。

myA.bar2(arg);

So, based on the assumptions above, that would call bar2() with an Integer as argument, although myA is a A<Banana> . 因此,基于上面的假设,虽然myAA<Banana> ,但它会调用bar2()并将Integer作为参数。 That can't be accepted by the compiler: it's clearly not type-safe. 编译器无法接受这一点:它显然不是类型安全的。 B must be made generic. B必须是通用的。

@JBNizet already explains why this can't be done. @JBNizet已经解释了为什么不能这样做。 This answer aims to explain the possible options you have (one of them being rightly pointed out by in your question but that's not the only option). 这个答案旨在解释你可能有的选择(其中一个在你的问题中正确指出,但这不是唯一的选择)。

Make B take a type parameter 使B采用类型参数

class B<T extends Serializable> {

    A<T> myA = null;    

    void foo(T arg) {
        myA.bar(arg);
        myA.bar2(arg);
    }
}

Make B extend from A (If B passes the is-a test for A) 使B从A延伸(如果B通过A的a-a测试)

class B extends A<String> {

    public void foo(String arg) {
        bar2(arg);
        bar(1);
    }
}

The difference between the two options is that in 1) both bar and bar2 need to be passed the same type where as in 2) bar and bar2 can be passed different types since bar2 is bound by the type parameter declared for A where as bar is bound by the type parameter declared for the method. 两个选项之间的区别在于:1) barbar2需要传递相同的类型,其中2) barbar2可以传递不同的类型,因为bar2由为A声明的类型参数绑定,其中bar是由为方法声明的类型参数绑定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM