代码之家  ›  专栏  ›  技术社区  ›  Albert

Java:通用接口和函数

  •  2
  • Albert  · 技术社区  · 15 年前

    我还在尝试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());
    }
    

    这给了我这个错误(对于 foo -呼叫):

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

    我不知道为什么。Eclipse告诉我 剧组结束后 A<?> foo(? obj) 我想这和 foo(Object obj)

    这个 assert 成功。

    我想弄清楚的是当我调用 功能。

    还有,我怎么打电话 ? 这是我真正需要做的事情。或者用其他参数 null ?

    一个更真实的例子,我真的很好奇:我使用 Comparable<T>

    7 回复  |  直到 15 年前
        1
  •  10
  •   Mark Peters    15 年前

    我不知道为什么。Eclipse告诉我,foo在转换到A之后的签名是foo(?)?我认为它和foo(Object obj)一样。

    不,绝对不是。想象 A<T> List<T> 具有 foo(T) add(T) 所以 A<?> List<?> . 你能做到吗?

     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作为参数传递,可以将其分配给 任何

        2
  •  3
  •   Tom Hawtin - tackline    15 年前

    如果你有” foo(? obj) “然后 ? 可以是任何类型。如果说 String 那你就不能通过,比如说 Integer 为了它。你能通过的就是 null .

    instanceof 通常应该避免,除非不可避免(例如 equals )尤其是泛型。

        3
  •  0
  •   Buhake Sindi Tesnep    15 年前

    编译器是正确的,因为它执行 编译时测试。

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

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

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

    意思是它想要任何A型的东西或它的孩子。 Object A 并且它与编译的编译测试参数类型不匹配。

        4
  •  0
  •   Colin Hebert    15 年前

    当您检查 B A<?> 你只是做了同样的事情 new B() instanceof A T 已经准备好了,这只是“某物”。

    在后面的代码中,您将使用 A<?> A 但是泛型类型仍然是“某物”。这个“something”是存在的,可能是一个指定的类,但是您不关心确切的类型。

    所以当你使用 foo() 采取的方法 在参数中,不能在参数中传递“something”,因为您不知道它是什么,它可能是 Object 但可能是别的什么。

    foo(capture#1-of ?) 不适用于论点 . 所需的参数是“某物”,但不一定是 对象 .


    那么,你什么时候需要这个功能呢?

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

    Map<?, V> m 
    

    这样,您就不能使用与地图键相关的功能(但您不关心这个问题),但是您可以将地图与 任何 有点关键。

        5
  •  0
  •   Community Mohan Dere    8 年前

    不, foo(? obj) foo(Object obj) . 区别在于,当参数类型为 Object ,它明确声明任何类型的对象都是合法的。参数类型为 ? ,方法声明 什么样的对象是合法的。。。因此,除了 null .

    当你考虑 List

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

    这个 ? 列表 是可以接受的。。。这个 列表 传入可能是 List<String> List<Integer> 或者 List<Map<Foo, Bar>> . 没办法知道。注意,这只是方法的一个问题 泛型参数,例如 add 或者你的 foo 生产 (return)泛型类型的对象,使用这样的方法并将结果作为 对象 . 这与使用者方法不同,不能损坏泛型对象的内部状态。

    ((A<?>) new B()).foo(new Object()) ,你想做些违法的事。。。如果某物(如 对象 B 将被传递给 方法,它将在运行时爆炸。编译器正确地阻止您执行此操作。

    你也许还想看看我对另一个问题的回答 here 这解释了一些关于有界通配符类型之类的事情。

        6
  •  0
  •   Peter Knego    15 年前

    这是一个简单的解释:

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

    A<?> ref = new B()
    

    ref 可以指向任何一个: A<Object , A<String> ,任何事。所以你不能打电话 A.foo(new Object()) 因为万一 无法知道哪个参数 ref.foo() ref.foo(null) .

        7
  •  -1
  •   Albert    15 年前

    ? 但还没有人真正回答过主要问题,所以这里是:

    可以打电话 A#foo

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

    那演员就完了 里面 foo .