开发者

Java Generics: How does Java determine whether it's a set or get process for a bounded wildcard

Ok guys. This is a revision

class Node<E> { // (1)

  private E            data;    // Data                           (2)
  private Node<E>      next;    // Reference to next node         (3)
  Node(E data, Node<E> next) {                                 // (4)
    this.data = data;
    this.next = next;
  }

  public void    setData(E e)    {}   // (5)
  public void    xxxData(E e)    {}   // (6)
  public E       getData(E e)    {return null;}   // (7)

  public static void main(String [] args) {

      Node<? extends Integer> n1 = new Node<Integer>(1,null);  //8
      Node<? super Integer> n2 = new Node<Integer>(1,null);  //9

      n1.setData(new Integer(1));  //10 compiler error
      n1.xxxData(new Integer(1));  //11 compiler error
      n2.setData(new Integer(1));  //12 ok

  }

}

Here's a rewrite hopefully i can convey my confusion nicely.

1. n1 is upper bounded wildcard. So this wont allow adding of records. Clause 10 proves this.

2. clause 11 also proves that method names (in this case 'SET' to determine adding of records) not being used since xxxData method gives the same compiler error.

3. n2 is lower bounded wildcard. Since method names doesn't play a role here, how does compiler knows that setData method can be used on n2 (since n2 is a lower bounded wildcard and this wildcard allows for adding of records)? Basically what the difference on method setData on clause 10 and 12?

Bear in mind nothing happ开发者_如何学Goens in those methods. It's empty or returning null.


If I understood your question properly, I guess it's because Integer is both super- and subtype to itself.


Yes, you are confusing three things:

  1. java method names are just names, you can call them anything you want
  2. there is a convention in Java to use what are called getters and setters. If you have a field (data or next in your example), then you define two methods: .

    public void setData(E data) { this.data = data; }

    public E getData() { return this.data; }

This convention is called Java Beans. You'd do the same for node by the way.

3) Java selects the method to call based upon the types of the parameters that you pass to the method. This is called method overloading. It means that you can define things like:

public void setFile(String name) {
    // do something here
}

public void setFile(File file) {
   // do something here
}

so you can call:

setFile(new File("barbar"));

or

setFile("c:\stuff");

and the correct method will be chosen.

The generic types that you have just confuse the situation even more :-)


Java doesn't care about get/set in the method name; it's all based on method parameter types. Consider

interface G<T>

    T f1();

    void f2(T t);

    void f3();

Substitute T with different types, methods signatures are changed too; for example, G<Int> methods

    Int f1();

    void f2(Int t);

    void f3();

So we can do the following

G<Int> o = ...;
Int i = o.f1();
o.f2(i);
o.f3();

What happens with wildcards? Actually compiler can't directly reason about wildcards; they must be replaced with fixed albeit unknown types; this process is called "wildcard capture".

For example, given a G<? super Int> type, compiler internally treats it as G<W>, where W is an unknown supertype of Int. G<W> has methods

W f1();

void f2(W t);

void f3();

So we can do

G<? super Int> o = ...;
Object i = o.f1();   // f1() returns W, which is subtype of Object
o.f2( new Int(42) ); // f2() accepts W; Int is a subtype of W, accepted.
o.f3();

Similarly

G<? extends Int> o = ...; // G<W>, where W is a subtype of Int
Int i = o.f1();      // f1() returns W, which is subtype of Int
o.f2( new Int(42) ); // error: f2() accepts W; Int is NOT a subtype of W
o.f3();


I think i have the answer to this problem. It's true that method name doesn't play a role here but rather whether the reference assignment is valid.

Compiler error for clause 10 & 11 is due to the following in terms of parameter assignment.

? extends Integer = Integer

One cannot assign the Integer to ? extends Integer since the ? extends Integer could have type which is lower than Integer (figuratively speaking).

Of course this works for clause 12.


The question really changed now... The answer to this is PECS
(or here, page 28)

Also see, What is PECS (Producer Extends Consumer Super)? or How can I add to List<? extends Number> data structures?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜