What Are Generics in Java

What are Generics in Java?

Generics allow you to customize a "generic" method or class to whatever type you're working with. For example, suppose you have a method that adds two numbers together. In order to work with the types themselves, you might have to create multiple versions of this method. For instance:

public int Add(int a, int b)

public double Add(double a, double b)

public float Add(float a, float b)

Generics allow you to create a single method that is customized for the type that invokes it.

public <T> T Add(T a, T b)

T is substituted for whatever type you use.

Is there any reason to use generics in Java?

Well, if you don't use generics, you get to cast each time. You would have to:

// if raw List
MyClass c = (MyClass) myClassList.get(0);
// if List<MyClass>
MyClass c = myClassList.get(0);

for instance.

Yes, generics are erased at runtime, yes, they are here to enforce type safety at compile time only; however there is still runtime type erasure when you use bounds. Example:

public <E extends RuntimeException> E get(final Class<E> c,
final Throwable t)
{
try {
return (E) getHandle(c).invokeExact(t);
} catch (Error | RuntimeException e) {
throw e;
} catch (Throwable oops) {
final RuntimeException exception = new IllegalStateException(oops);
exception.addSuppressed(t);
throw exception;
}
}

The E here has a runtime type erasure; it extends RuntimeException. Therefore the cast is to RuntimeException, not Object.

See the javadoc of Collections.max() for another interesting example of runtime type erasure (hint: why does it define T extends Object & Comparable<? super T> instead of T extends Comparable<? super T>?)

Understanding generics in Java

Class java.util.Queue uses type parameters to assure that you won't add type other than it was created with.

If you create Queue like:

Queue <TreeNode> queue = new LinkedList<TreeNode>();

It means queue can store only TreeNode objects. This is used for type checking in methods add,offer,remove,poll.

Java Generics T Meaning

The <T> is indeed a syntax defined by Java, but you can use whatever name you want to name a type, you don't need to use T, for example this is valid:

public class Box<MyType> {
private MyType t;

public void set(MyType t) { this.t = t; }
public MyType get() { return t; }
}

But, stick with T or other common type names, as other people are already used to seeing those as the "generic types" so it makes reading your code simpler.

I recommend you read Java's Trail about Generics, where you can find the most commonly used type parameter names:

E - Element
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types

As for "what the meaning of generics is", check this other page.

Java Generics : Is any meta information about the generic type preserved at runtime as well?

Of course the information that a class is generic is supported.

In other words: when you decompile ArrayList.class you will find hints about the fact that this class allows for one generic type parameter. In other words: class files contain meta information. And using reflection it is possible to inspect this meta information at runtime.

But when you have another class that uses some List<Integer> object - then you do not find information about that "list uses an Integer" in the compiled class - unless you use some specific patterns, as outlined here for example.

So the answer is basically: for almost all use cases of practical relevance, "generics" are compile time only.

Example:

public class GenericsExample<T> {
private T member;
public T foo(T bar) {
return member;
}
}

Now run: javap -p -c GenericsExample

Compiled from "GenericsExample.java"
public class GenericsExample<T> {
private T member;

public GenericsExample();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return

public T foo(T);
Code:
0: aload_0
1: getfield #2 // Field member:Ljava/lang/Object;
4: areturn
}

As you can see the decompiler understands that the class uses that generic type T. For more details see here or there.

What is the difference between 'E', 'T', and '?' for Java generics?

Well there's no difference between the first two - they're just using different names for the type parameter (E or T).

The third isn't a valid declaration - ? is used as a wildcard which is used when providing a type argument, e.g. List<?> foo = ... means that foo refers to a list of some type, but we don't know what.

All of this is generics, which is a pretty huge topic. You may wish to learn about it through the following resources, although there are more available of course:

  • Java Tutorial on Generics
  • Language guide to generics
  • Generics in the Java programming language
  • Angelika Langer's Java Generics FAQ (massive and comprehensive; more for reference though)

What does a generic in front of a method mean?

The first is a kind of declaring that functionName will use generics, generally we use R to represent "return", which means this function will return an instance of MyClass which manipulates R objects.

For better understanding, this is a way to call functionName if it was static:

public class AClass{

class MyClass<TYPE>{}

static <R> MyClass<R> functionName(){return null;}

public static void main(String[] args) {
AClass.<String>functionName();
}

}

Generics in Java

There's the pseudo-typedef antipattern...

class StringList extends ArrayList<String> { }

Good stuff, drink up! ;-)

As the article notes, this technique has some serious issues, primarily that this "typedef" is actually a separate class and thus cannot be used interchangeably with either the type it extends or other similarly defined types.



Related Topics



Leave a reply



Submit