Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generics extending return type of methods

Take a look at these three classes. Minatchi allows itself to be extended so that its methods' returning type could be extended as well. To illustrate, I used a static method.

public class Minatchi<T extends Minatchi<?>>{

  static public <T extends Minatchi<?>>
    List<T> listAll(){
      return
        (List<T>) query();
  }
}

And so I subclass Minatchi into Lady

public class Lady
extends Minatchi<Lady>{

}

This is where the questionable behaviour takes place.

public class HelloMinatchi{

  private void listA(){
    List<Lady> uvs = Lady.listAll();
    for (Lady uv: uvs){
      logger.info(uv.getName() );
    }
  }

  private void listB(){
    for (Lady uv: Lady.listAll()){
      logger.info(uv.getName() );
    }
  }
}

Methods listA and listB are essentially the same. listA places the list into an intermediate variable uvs, whereas listB directly places listAll into the for-loop header.

However, for listB, the compiler complains Cannot convert Minatchi<?> to Lady.

So this question is about the design integrity of Java generics. Yet another generics gripe.

Is this a deliberate design feature or an unintentional design bug that Java generics designers did not know how to solve. If deliberate, why did they do that? If bug, are they planning to solve it?

Or is this my personal problem that I do not know a better way to declare the generics? If so, tell me how.

(I used a generic Minatchi class because I have non-static methods to be exposed to class extension too, which I left out in the question.)

like image 652
Blessed Geek Avatar asked Jan 14 '10 12:01

Blessed Geek


People also ask

Can Java return type be generic?

So methods of generic or nongeneric classes can use generic types as argument and return types as well. Here are examples of those usages: // Not generic methods class GenericClass < T > { // method using generic class parameter type public void T cache ( T entry ) { ... } }

How do you restrict the types used as type arguments in generic classes and methods?

Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class. These are known as bounded-types in generics in Java.

Can generics take multiple type parameters?

A Generic class can have muliple type parameters.

Can methods have more than one return type?

A method cannot return more than one type. The signature of a method contains the return type or void if the method doesn't return anything. Since it must be defined in the method signature, you must return something of that type.


2 Answers

The static method does not take the generic type definition from the class. i.e. the listAll() method does not know about the Lady (in extends Minatchi<Lady>).

Its return type is inferred by the left-hand side of the expression:

  • in listA() the left-hand side defines that it expects List<Lady>
  • in listB() the forEach loop looks like it should also expect a Lady, but it appears that the compiler isn't properly instructed withing the forEach loop.

The way to make listB() work is to tell it what generic type to use:

for (Lady uv : Lady.<Lady>listAll()) {..}
like image 157
Bozho Avatar answered Oct 12 '22 07:10

Bozho


Unfortunately, as I mentioned in another question: Why implicit type inference only works in an assignment?, implicit type inference in Java only works in an assignment.

I still don't know the reason. It still seems stupid for me, though.

like image 43
nanda Avatar answered Oct 12 '22 07:10

nanda