CuriousMind
CuriousMind

Reputation: 8903

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);

    }
}

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.

Upvotes: 1

Views: 1606

Answers (2)

EpicPandaForce
EpicPandaForce

Reputation: 81539

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>.

Upvotes: 2

blalasaadri
blalasaadri

Reputation: 6188

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.)

Upvotes: 1

Related Questions