简体   繁体   中英

Java Generics - use of extends keyword

I read the document on Java Generics, and it said that the java 'extends' keyword in connection with Generics means and class which implements that interface.

Based on this, i tried to create generic classes to understand this further. Here is my sample code.

Interface code:

package com.vipin.generics.doubtclear;

public interface DemoInterface1<T> {

    void display(T t);
}

Now, I created few simple classes which implements this interface:

package com.vipin.generics.doubtclear;

class myClass<T> implements DemoInterface1<T> {

    public myClass(T t) {

    }

    @Override
    public void display(T t) {
        System.out.println("Inside display method of myClass, object is ---> "+t);
    }
}

class myClass1<T> implements DemoInterface1<T> {

    public myClass1(T t) {

    }

    @Override
    public void display(T t) {
        System.out.println("Inside display method of myClass1, object is ---> "+t);
    }
}

Here is the class which has main, which tries to create objects:

public class DoubtClear1 {

    static <T extends DemoInterface1<T>> void myFunc(T t) {
        t.display(t);
    }

    public static void main(String[] args) {

        myClass<Integer> iObj = new myClass<Integer>(1);
        myClass1<Integer> iObj1 = new myClass1<Integer>(1);
        DoubtClear1.myFunc(iObj);

    }
}
  • In main I am creating myClass<Integer> and myClass1<Integer> objects.

  • As per my understanding of 'extends' keyword when applied to Generics myFunc() is capable of taking any object reference which implements DemoInterface1 interface .

  • This is what i am doing in call ==> DoubtClear1.myFunc(iObj);

However, this is giving me compile-time error:

The method myFunc(T) in the type DoubtClear1 is not applicable for the arguments (myClass<Integer>)

This is really confusing. I am doing what is written in the documentation on this topic and it is failing. I am not sure if my understanding of this topic is correct.

From what I feel, Generics is confusing, and it takes repeated study to really get what this is.

Any information to clear this point really appreciated.

Currently you are evaluating the condition

static <myClass1<Integer> extends DemoInterface1<myClass1<Integer>> void myFunc(myClass1<Integer> t) {

Which is not true, myClass1<Integer> does not match DemoInterface1<myClass1<Integer>> , because Integer generic condition of myClass1 is not myClass1<Integer> (because it is Integer ).

You should instead do the following

static <T> void myFunc(DemoInterface1<T> interface, T t) {
    interface.display(t);
}

As such, the following should work

myClass<Integer> iObj = new myClass<Integer>(1);

myClass1<Integer> iObj1 = new myClass1<Integer>(1);

DoubtClear1.myFunc(iObj, 1);

EDIT: If you wanted to add a new interface that extends from DemoInterface1 then that would change the myFunc parameters like so

static <T, N extends DemoInterface1<T>> void myFunc(N interface, T t) {
    interface.display(t);
}

Which I assume is originally what you wanted.

EDIT2:

The error in your code didn't happen because of this:

<T extends XYZ>

This indeed means that T implements or extends from XYZ .

The error was because you used it like this:

/*
    T extends from DemoInterface1, okay - this is myClass1 
       |
       |             the generic parameter of that 
       |             DemoInterface1 is bound to T, 
       |             which as mentioned, 
       |             extends from DemoInterface1 
       |             (in your case, it means this is myClass1<Integer>, NOT Integer)
       |                         |
       |                         |
       |                         |
       |                         |          here you receive a bound for T
       |                         |          where T is meant to extend from
       |                         |             DemoInterface1<T>
       |                         |          in your example, T is myClass1<Integer>, and NOT `Integer` that is the <T> of DemoInterface1<T> (myClass1<Integer>)
       |                         |              
       |                         |               |
      \|/                       \|/             \|/         */
static <T extends DemoInterface1<T>> void myFunc(T t) {
    t.display(t);
}

Basically, the T that your display method receives is not Integer , it's myClass1

EDIT3:

I got your point 
we have to pass object like myClass1<Integer> 
and NOT Integer. However, when we do like: 

myClass1<Integer> iObj1 = new myClass1<Integer>(1), 

isn't iObj1 of myClass1<Integer> type, and NOT Integer. 

This i am passing to myFunc(). 
Does <T> gets replaced with Integer? 
or with the object with which we are calling it? 
May be, this is the cause of confusion. 
Please explain. Thanks a lot!

Yes, you are giving myFunc your iObj1 instance. As such, the <T> in static <T extends DemoInterface1<T>> void myFunc(T t) { is resolved to be myClass1<Integer> .

However, you are also using this as the parameter for display in t.display(__) . As a result, you are trying to give a myClass1<Integer> to the method of iObj1.display(__) , which however awaits Integer . Essentially, you're pretty much calling iObj1.display(iObj1) , and display(T) awaits Integer , not myClass1<Integer> .

What you have is this function:

static <T extends DemoInterface1<T> > void myFunc(T t) {
    t.display(t);
}

Then you call it like such:

myClass<Integer> iObj = new myClass<Integer>(1);
DoubtClear1.myFunc(iObj);

Now, myClass<Integer> does not match the type T extends DemoInterface1<T> but the type T extends DemoInterface1<Integer> . So maybe you want something like this:

static <T extends DemoInterface1<?> > void myFunc(T t) {
    t.display(t);
}

That would work. (Unless I misunderstood your intentions.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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