English 中文(简体)
Java:这样的通用接口和函数
原标题:Java: generic interfaces and functions in such

我仍在试验Java如何处理泛型。我偶然发现了一个事实/问题/事情,如果你有一个通用接口,比如a<;T>,之后您不能真正检查某个对象是否真的实现了A<;B>A<;C>

我想知道这是否会造成实际问题。

现在我已经尝试了这个代码:

static interface A<T> { void foo(T obj); }
static class B implements A<B> {
    public void foo(B obj) { obj.bar(); }       
    void bar() {}
}
static {
    assert (new B() instanceof A<?>);
    ((A<?>) new B()).foo(new Object());
}

这给了我这个错误(对于<code>foo</code>-调用):

The method foo(capture#1-of ?) in the type Main.A<capture#1-of ?> is not applicable for the arguments (Object)

我不知道为什么。Eclipse告诉我,在转换到A<;之后,foo的签名是什么>foo(?obj),我认为这与foo(Object obj)[/code>相同。

断言成功。

我试图弄清楚的是,当我调用<code>foo</code>函数时,它到底在什么时候抛出对象。

此外,如何从A<;调用foo>?这就是我真正需要做的事情。或者,除了<code>null</code>之外,其他任何参数都不可能做到这一点吗?

一个更真实的例子,我真的对此感到好奇:我使用Comparable<;T>接口很多。这种情况实际上更为复杂;如果这里没有回答这个问题,我可能会提出另一个问题。

最佳回答

许多人已经澄清了关于<code>的这一点但还没有人真正回答主要问题,所以这里是:

可以这样调用A#foo

((A) new B()).foo(new Object());

然后在foo的内部执行强制转换。

问题回答

我想知道为什么会这样。Eclipse告诉,在转换到A之后,foo的签名是foo(?obj),我认为它与foo(Object obj)相同。

不,绝对不是。想象一下A<;T>列表<;T>foo(T)add(T)[/code>,所以A<>列表<>。你应该能够做到这一点吗?

 List<String> strList = new ArrayList<String>();
 List<?> wcList = strList;
 wcList.add(Integer.valueOf(6));  //possible if add(?) is same as add(Object)

 //...
 String str = strList.get(0);

当然不是,因为在最后一行中会出现ClassCastException。

foo(?)真正的意思是,该方法适用于某些未知但特定的类型。除非将null作为参数传递,否则通常无法调用这些方法,这对于分配给任何引用类型都是可以接受的。

如果您有“foo(?obj)”,那么可以是任何类型。如果它是String,那么你不能向它传递,比如说,一个Integer。你所能传递的只是null。

除非不可避免(例如实现equals),否则通常应避免强制转换和使用实例,尤其是泛型。

编译器是正确的,因为它在编译时执行编译强制转换测试。

((A<?>) new B()).foo(new Object());

是错误的,因为需要编译器

((A<?>) new B()).foo(A object)....

这意味着它想要任何A类或其子女ObjectA的父对象,它与要编译的编译测试参数类型不匹配。

当您检查B的实例是否为A<;?的实例时>new B()instanceof A相同的事情。你并没有真正检查t是如何设置的,它只是“一些东西”。

稍后,在带有强制转换的代码中,您将使用B作为a<>,所以变量将具有a的特性,但泛型类型仍然是“something”。这个“某物”存在,并且可能是一个指定的类,但您不关心确切的类型。

这就是为什么当你使用<code>foo()</code>方法,该方法采用<code>T</code〕in参数时,你不能在参数中传递“something”,因为你不知道它是什么,它可以是<code>Object</code>,但它可以是其他任何东西。

因此,编译器告诉foo(capture#1-of?)不适用于参数Object。所需的参数是“something”,但不一定是对象


Then, when would you need this feature ?

例如,如果您使用映射,如果您并不真正关心键的类型(例如,如果只使用values()方法),则可以执行以下操作:

Map<?, V> m 

这样,您将无法使用与地图键相关的功能(但您并不关心这一点),但您可以使用带有任何类型键的地图。

不,foo(?obj)实际上与foo(Object obj)[/code>不同。不同的是,当参数类型为<code>Object</code>时,它明确表示任何类型的对象都是合法的。参数类型为<code>,该方法声明它不知道什么类型的对象是合法的。。。因此,除了<code>null</code>之外,没有任何东西是合法的。

当您考虑List而不是任意接口时,其原因就变得显而易见了。看看这个方法:

public void foo(List<?> list) {
  list.add(...); // what can we add here?
}

<代码>表示任何类型的List都是可接受的。。。传入的<code>列表、列表<;整数>列表<;映射<;Foo,酒吧>>。没有办法知道。请注意,这只是使用泛型参数的方法的问题,例如addfoo方法。对于生成(返回)泛型类型对象的方法,可以使用这样的方法并将结果分配为对象。与使用者方法不同,这不会破坏泛型对象的内部状态。

还要注意,当您调用((A<;?>;)new B()).foo(new Object())时,您正试图做一些非法的事情。。。如果不是B的东西(如Object)被传递给Bsfoo方法,它将在运行时爆炸。编译器正确地阻止了您执行此操作。

您可能还想查看我对另一个问题的回答这里解释了一些关于有界通配符类型之类的东西。

这是一个简单的解释:

A<>表示未知参数化类型的A。鉴于

A<?> ref = new B()

ref可以指向任何A:A<;对象A<;字符串>,任何东西。因此,您不能调用A.foo(new Object()),因为在A<>reference无法知道ref.foo()接受哪个参数。实际上,唯一有效的是ref.foo(null)





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...