Skip to content

Instantly share code, notes, and snippets.

@darrenbkl
Created January 16, 2020 15:01
Show Gist options
  • Save darrenbkl/74f30db82170889a27b831ec50690f4a to your computer and use it in GitHub Desktop.
Save darrenbkl/74f30db82170889a27b831ec50690f4a to your computer and use it in GitHub Desktop.

Java Generics Explained

#blog

Table of terms and their scariness

It is important to understand that Java generics is not true generics, it offers only syntactical support to take advantage of compile time safety check. All generics gets compiled to non-generic code during byte code generation.

Before Generics…

In the beginning, Java doesn’t support generics, and this is how you would manipulate a List: https://gist.github.com/2f64727c74d63959280943d72b4c5f0c

Notice that it is exactly the same as how one would write the code pre-Java 5. You can think of Java generics as syntactic sugar over using raw type and manual castings.

With Type-Erased Generics, you get

  1. Compile-time safety check 👌
  2. Backward compatibility with pre-Java 5 code 👌
  3. No type information available at runtime 😢

Reification & Reified Types

Reification sounds like a term that software people invented to protect their job. This is the definition of Reify from Merriam Webster,

to consider or represent (something abstract) as a material or concrete thing

Reification is the opposite of type erasure, it is the process of making type information available at runtime. Java supports reification for most of the types, like primitives (int, char) , non-parameterised type (Number, InputStream), array of primitives (int[]), etc. These are called Reifiable Types, they retain their type information at runtime, because they are not subjected to type erasure.

The following 2 types are NOT Reifiable Type:

  1. Exact Parameterised type - List
  2. Bounded parameterised type - List<? Extends Number> They lose their parameterised type information at runtime due to type erasure.

Reifiable types in action https://gist.github.com/a1e760088948b972ec7084ccff61d109

Non-Reifiable types in action https://gist.github.com/3a1ce22cc7840b132a9ded2b51512fa1


Reified Generics vs Type-Erased Generics

Reified Generics is the type of generics system that makes generics type information available at runtime. C# is one language that supports Reified Generics natively, as opposed to Java’s Type-Erased Generics.

There are, however, some obscure dark magic that allows you to make reified generics happen in Java using Type Token, but that belongs in the Restricted Section.

Let’s take a look at what is possible if java were to support Reified Generics.

Overload method with generics

https://gist.github.com/435312a74e4deb0a59e712ea633023fe

Get type at runtime

The 2 non-reifiable types above will have their type reified https://gist.github.com/4448ef9cd8d577601f060819c2d0c5d2

Generic Array

https://gist.github.com/ab6061e0e9a8dc7eb152c92a120a545f


Raw Type

Sometimes we get a warning about using raw type in the IDE https://gist.github.com/804bba4d106f2726b27620a39f4e2636

Raw type is basically the use of generic without type parameter. It was ubiquitous before Java 5, but with the introduction of generics, the added benefit of compile time checking is completely subverted by the usage of raw type, defeating the purpose of generics.

Notice how this is a merely a warning instead of error, because raw type is known to be potentially dangerous, nevertheless, it is allowed for backward compatibility with pre-Java 5 code.

Usage of raw type could lead to Heap Pollution, which in turn produces ClassCastException™️. There is even a rule from Effective Java - Item 26: Don’t use raw types.

How does Raw Type causes Heap Pollution?

Another simple concept with a complicated name. Heap pollution happens when a variable of type X doesn’t point to X or its subclass, but points to Y. How is this even possible with a strongly typed language? Well, because Java allows you to use Raw Type!

Consider the following code: https://gist.github.com/479f699607ba1fe179510f9a2c5645ae

In line 2, strList is pointing to a list of integer (intList), but compiler doesn’t complain because it doesn’t know that intList is a list of Integer due to the use of raw type in line 1. When you’re getting string out of strList, ClassCastException happens. In a way you are “polluting” the heap by putting a type where it shouldn’t be.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment