Java: Generics Interview Questions

Over the years, I’ve created, been asked, and acquired a number of interview questions. So I’ve decided to publish them because I think others will find them useful. Though the questions are a combination of my own creations and what I’ve seen, all the answers are of my own(unless noted). Please let me know if there are typos are mistakes.

Write a generic method to return the last non null element in a array.

Write Answer

Show Answer

public static <T> T returnLast(T[] array) {
    T lastItemFound = null;
    for (int i = 0; i < array.length; i++) { 
        if (array[i] != null) {
            lastItemFound = array[i];
        } 
     } 
    return lastItemFound;
}

Can you talk about type erasure?

Write Answer

Show Answer

Generics were introduced for strong compile time checking and generic programing. Type erasure removes many of the references to generics in the Java byteocde. Ideal answer describe the following concepts:
  • Replace generic types with bounds or Object.
  • Bytecode only contains regular classes and methods.
  • Concept of bridge method generation. This is a more advanced answer.

Can you change this code to use a parametrized version of List?

List aList = new ArrayList();
aList.add("string1");

Write Answer

Show Answer

List<String> aList = new ArrayList<>();
aList.add("string1");

How can you restrict a type argument to be a subclass of two or more classes?

Write Answer

Show Answer

Generics allows for types to be bounded by multiple types.

public class Box<T extends ClassA & ClassB> {

This restricts the types provided by the user to be a subclass of ClassA and ClassB. Remember, taken straight from the official documentation: If one of the bounds is a class, it must be specified first.

What is the difference between a raw type and a non-generic?

Write Answer

Show Answer

A raw type is the name of a generic class or interface without any type arguments were a non-generic type is a regular class. More specifically, generics add compile time type safety with the use of type parameter provided by the user. If these are omitted, you loose the intended type safety. Non-generic classes do make this contract.

Explain why <Object> is different than <?>.

Write Answer

Show Answer

The unbounded wildcard <?> represents any Object. <Object> represents specifically the Object type.

Why is the following method not possible? In particular, why can we not create a generic array in this way?

public <T> T[] createArray(size) {
    return new T[size]; 
}

Write Answer

Show Answer

Though this may seem ok at face value, lets consider what happens after type erasure. At runtime, the createArray() is return Object[]. So while this code may look valid at compile time:

Integer[] array = createArray(10);
}

At runtime, we’ve are assigning an Object[] to a variable declared to be a Integer[] which violates type safety.

What is a type parameter in generics?

Write Answer

Show Answer

Used in Java generics, a type parameter is used when a type can be used as a parameter in a class, method, or interface.

Why use Generic Types, name some advantages?

Write Answer

Show Answer

  1. Provides better type safety, especially when working with Lists (or Collections). We can declare a List to contain objects of just one type.
  2. Avoiding unnecessary casts that clutter up code.
  3. Allows for the creation of methods and classes that can be used on with different types. No need to sublcass or create duplicates.

What happens if you instantiate a generic class without provide a type argument?

Write Answer

Show Answer

In order to maintain backwards combability, you can are allowed to create instances of generic classes without providing a type argument. It is not considered practice to omit the type and the compiler will generate a warning.

What is Type Inference?

Write Answer

Show Answer

Type inference describes Java’s ability to look at context and for a method invocation or class instantiation and determine the type arguments to make the generic type invocation.
  1. With respect to method invocations, type inference allows you to invoke generic methods as you would a ordinary method (omitting the type arguments)
  2. With class instantiation, you can invoke the constructor of a generic class using an empty set of type parameters ().

Can you write classes/interfaces ClassA, ClassB, and ClassC such that ClassC can be provided as a type argument when we perform a generic type on a generic class with the following definition:

public class Box<T extends ClassA & ClassB & Comparator> {

Write Answer

Show Answer

public class ClassA {}
public interface ClassB {}
public class ClassC extends B implements Comparable{}

What is the difference between List<? extends AClass> and List<T extends AClass>?

Write Answer

Show Answer

List<? extends A> – Defines a wildcard bounded by the class A. Type arguments provide can include any class that extends or implements (if A is a interface) A. This syntax is typically used for example, in a method parameter definition.

List<T extends A> – This definition also accepts type arguments that are extends/implements A. However, this syntax is applicable for generic class, interface or method definitions.

What is difference between List<? extends A> and List <? super A>?

Write Answer

Show Answer

Both are an example of bounded wildcards. List<? extends A> will accept any parameterized typed List with a type argument that is a subclass of A or if A is an interface, implements A. This is an example of a upper bounded wildcard. List <? super A>? accepts any List whos type that is a super class of A. This is an example of a lower bounded wildcard.

Can you pass List<String> to a method which accepts List<Object>?

Write Answer

Show Answer

No you cannot. Even though String is a subclass of Object, this relationship does not exist between List<String> and List<Object>?

Let’s take at the following class definitions

public class ClassA<T> {}
public class ClassB extends ClassA<String> {}
public class ClassC<T> extends ClassD<T> {

Which of the assignments fail and why?

ClassA<String> a = new ClassA<>();
ClassB<Integer> b = new ClassB<>();
ClassA<Integer> a2 = new ClassA<>();
ClassC<String> c1 = new ClassC<>();
ClassC<Integer> c2 = new ClassC<>();

a = b;  // 1
a = a2;  // 2
a2 = b;  // 3
a= c1;  // 4
c1 = a;  // 5
c1= c2;   // 6
a2 = c2;  // 7

Write Answer

Show Answer

  1. Valid. b (ClassB) is a subclass of ClassA, thus the b can be assigned to to “a” since A is of type Class A.
  2. Invalid. “a” and “a2” are of different types. “a” is a ClassA<String> and a2 is a ClassA<Integer>
  3. Invalid. Because “b” is actually a subclass of ClassA<String>.
  4. Valid. “a” is a super class of “c1”, thus “a” can be assigned c1.
  5. Invalid. Since “a” is a super class of “c1” so while “c1” is a ClassA, the opposite is not true.
  6. Invalid. “c1” is the parameterized type ClassC<String> and “c2” is the parametrized type ClassC<Integer>. There is no relationship between these two parametrized types even if the generic class is the same.
  7. Valid. “a2” is actually super class (ClassA) of a ClassC. When “c2” is created, it is of a parameter type ClassC<Integer> which extends ClassA<Integer>. ClassA<Integer> is the type of “a2”.

What are the differences between List<?> and List<Object>?

Write Answer

Show Answer

It’s important to know that the wildcard character (?) represent unknown types and Object represents specifically the object type.

  • A variable declared as List can be assigned List,List or even List
  • List can only be assigned List
  • It cannot be assigned List<String> even though Strings are a subclass of Object and a String can be added to a List declared as List<Object>.

Take a look at the Box class. Right now it can only hold Strings. Can you modify it so that it can take other types?

public class Box {
    private String object;

    public void set(String object) { this.object = object; }
    public String get() { return object; }
}

Write Answer

Show Answer

We don’t want to duplicate the Box class for every single type of object we want to store. Instead, we’ll convert Box into a generic class using a type parameter T.

public class Box<T> {
    private T object;

    public void set(T object) { this.object = object; }
    public T get() { return object; }
}

Can you declare static fields whose types are generic type parameters?

Write Answer

Show Answer

No. Think of how we pass type arguments during the generic type invocation process. Since static fields are shared by all classes of an instance, it does not make sense to have static fields who are type parameters since different instances of the Class can be parameterized by different types.

Why won't the following Util class compile?

public class AnotherUtil<T> {
    private static T instance = null;
    public static T getInstance() {
        if (instance == null)
	    instance = new Singleton<T>();
            return instance;
        }
    }
}

Write Answer

Show Answer

No, it will not compile. The type parameter T is non-static but is referenced in a static context. More generally, you cannot use type parameters in statically defined fields.

Given the following classes:

class Shape { /* ... */ }
class Circle extends Shape { /* ... */ }
class Rectangle extends Shape { /* ... */ }

class Node<T> { /* ... */ }

Will the following compile?

Node<Circle> nc = new Node<>();
Node<Shape>  ns = nc;

This question is from the official generics documentation.</p

Write Answer

Show Answer

No, this is not a valid assignment. Node<Shape> is not a super class of Node<Circle> even if Shape is a super class of Circle.

Can Java generics be applied to primitive types?

Write Answer

Show Answer

No Java generics cannot be applied to primitive types.

Can you create instances of generic type parameters?

Write Answer

Show Answer

No, you cannot create an instance like the following:

public class Test <T> {	
    public T getSomething() {
        T t = new T(); // error, will not compile
        return t;
    }
}

However, there are workarounds to use parameterized factory types to create instances:

public class Test<T> {
    private Supplier<T> supplier;
    
    Test(Supplier<T> supplier) {
        this.supplier = supplier;
    }

    public T getSomething() {
        return supplier.get();
    }
}
/ ** **/
Supplier<String> stringSupplier = () -> "abc";
Supplier<Integer> integerSupplier = () -> Integer.valueOf(1);

Test<String> s = new Test<>(stringSupplier);
String str = s.getSomething();
	
Test<Integer> n = new Test<>(integerSupplier);
Integer num = n.getSomething();

When do you implement Unbounded wildcards?

Write Answer

Show Answer

Unbounded wildcards can be useful when are writing a method that does not need to know (or deal with) actual type. A simplistic example is a method to return the first non-null value of a List. We don't care about actual type of the contents of the List.

What are the types of bounded wildcards?

Write Answer

Show Answer

  • <? extends T>
  • <? super T>

Can you summarize the main objections for the introduction of generics?

Write Answer

Show Answer

  • Stronger compile time type checking./li>
  • Remove unnecessary type casting.
  • Enabling programmers to implement generic algorithms.

Leave a Reply

Your email address will not be published. Required fields are marked *