Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Generics, return generic extending

Tags:

java

generics

Why am i not allowed to do this?

public abstract class A {}
public class B extends A {}
...

public ArrayList<A> foo()
{
  return new ArrayList<B>();
}

I changed to public since there are so many people that love to point stupid errors.

Why should i have to write ALL this code. Just to satisfy Java's non-senses?

public List<A> foo() 
{ 
  List<A> aList = new ArrayList<A>(); 
  List<B> bList = new ArrayList<B>();
  /* fill bList*/

  for (B b : bList)
  {
    aList.add(b);
  }
  return aList;
}
like image 585
Gabriel Avatar asked Jan 11 '11 11:01

Gabriel


People also ask

Can a generic class be extended?

We can add generic type parameters to class methods, static methods, and interfaces. Generic classes can be extended to create subclasses of them, which are also generic.


2 Answers

An ArrayList<B> is not an ArrayList<A>. You can't add any arbitrary A into it, for example. Or as I like to think of it: a bunch of bananas isn't a fruitbowl. When you try to add an apple to a bunch of bananas, it rolls off...

You can use wildcards to make it work though:

public ArrayList<? extends A> foo()
{
    return new ArrayList<B>();
}

See the Java Generics FAQ for more details.

EDIT: To answer your specific question of why you need to write all that extra code: you don't. Just create an ArrayList<A> within foo() to start with. There's no need to copy the contents of one list to another.

If you still object to Java's behaviour, what would you want to happen with the following code?

// Doesn't compile, fortunately...
List<String> strings = new List<String>();
List<Object> objects = strings;
objects.add(new Date());
String string = strings.get(0); // Um, it's a Date, not a String...
like image 79
Jon Skeet Avatar answered Sep 29 '22 18:09

Jon Skeet


a) For one thing, function does not exist in Java. Java methods have the format

modifiers <type_parameters[,type_parameter]*>? return_type method_name (
   [parameter[,parameter]*]?
) [throws exceptiontype[, exceptiontype]*]{ method_body }

b) Here's how to do it:

public List<? extends A> foo()
{
  return new ArrayList<B>();
}

c) I changed the method signature to List. It's bad practice to have implementation types in your class' external API if an appropriate interface exists.

like image 26
Sean Patrick Floyd Avatar answered Sep 29 '22 19:09

Sean Patrick Floyd