Java Generics Interview Questions and Answers

Web Stories

Introduced by JDK 5, generics changed Java in two important ways. First, it added a new syntactical element to the language. Second, it caused changes to many of the classes and methods in the core API. Today, generics are an integral part of Java programming, and a solid understanding of this important feature is required.

It is examined here in detail. Through the use of generics, it is possible to create classes, interfaces, and methods that will work in a type-safe manner with various kinds of data. Many algorithms are logically the same no matter what type of data they are being applied to. For example, the mechanism
that supports a stack is the same whether that stack is storing items of type Integer, String, Object, or Thread. With generics, you can define an algorithm once, independently of any specific type of data, and then apply that algorithm to a wide variety of data types without any additional effort. 

The expressive power generics added to the language fundamentally changed the way that Java code is written. Perhaps the one feature of Java that has been most significantly affected by generics is the Collections Framework. The Collections Framework is part of the Java API, but a brief mention is useful now. A collection is a group of objects. The Collections Framework defines several classes, such as lists and maps, that manage collections. The collection classes have always been able to work with any type of object. 

The benefit that generics added is that the collection classes can now be used with complete type safety. Thus, in addition to being a powerful language element on its own, generics also enabled an existing feature to be substantially improved. This is another reason why generics were such an important addition to Java.

TechShitanshu has prepared a list of the top java Abstract Class interview questions and answers that are frequently asked in the interview. It is going to help you to crack the java interview questions and answers to get your dream job.

java generics interview questions

Table of Contents

1. What Are Generics?

At its core, the term generics means parameterised types. Parameterised types are important because they enable you to create classes, interfaces, and methods in which the type of data upon which they operate is specified as a parameter. Using generics, it is possible to create a single class, for example, that automatically works with different types of data. A class, interface, or method that operates on a parameterised type is called generic, as in generic
class or generic method.

It is important to understand that Java has always given you the ability to create generalised classes, interfaces, and methods by operating through references of type Object. Because Object is the superclass of all other classes, an Object reference can refer to any type object. Thus, in pre-generics code, generalised classes, interfaces, and methods used Object references to operate on various types of objects. The problem was that they
could not do so with type safety.

Generics added the type safety that was lacking. They also streamlined the process, because it is no longer necessary to explicitly employ casts to translate between Object and the type of data that is actually being operated upon. With generics, all casts are automatic and implicit. Thus, generics expanded your ability to reuse code and let you do so safely and easily.

2. Why Generics Work Only with Reference Types?

When declaring an instance of a generic type, the type argument passed to the type parameter must be a reference type. You cannot use a primitive type, such as int or char. For example, with Gen, it is possible to pass any class type to T, but you cannot pass a primitive type to a type parameter. Therefore, the following declaration is illegal:
Gen<int> intOb = new Gen<int>(53); // Error, can’t use primitive type

Of course, not being able to specify a primitive type is not a serious restriction because you can use the type wrappers (as the preceding example did) to encapsulate a primitive type. Further, Java’s autoboxing and auto-unboxing mechanism makes the use of the type wrapper transparent

3. How Generic Types Differ Based on Their Type Arguments

A key point to understand about generic types is that a reference of one specific version of a generic type is not type compatible with another version of the same generic type. For example, assuming the program just shown, the following line of code is in error and will not compile:
iOb = strOb; // Wrong!

Even though both iOb and strOb are of type Gen<T>, they are references to different types because their type parameters differ. This is part of the way that generics add type safety and prevent errors.

4. How Generics Improve Type Safety

At this point when asked in java interview questions, you might be asking yourself the following question: Given that the same functionality found in the generic Gen class can be achieved without generics, by simply specifying Object as the data type and employing the proper casts, what is the benefit of making Gen generic? The answer is that generics automatically ensure the type safety of all operations involving Gen. In the process, they eliminate the need for you to enter casts and to type-check code by hand.

To understand the benefits of generics, first consider the following program that creates a non-generic equivalent of Gen:

				
					// NonGen is functionally equivalent to Gen
// but does not use generics.
class NonGen {
Object ob; // ob is now of type Object
// Pass the constructor a reference to
// an object of type Object
NonGen(Object o) {
ob = o;
}
// Return type Object.
Object getob() {
return ob;
}
// Show type of ob.
void showType() {
System.out.println("Type of ob is " +
ob.getClass().getName());
}
}
// Demonstrate the non-generic class.
class NonGenDemo {
public static void main(String args[]) {
NonGen iOb;
// Create NonGen Object and store
// an Integer in it. Autoboxing still occurs.
iOb = new NonGen(88);
// Show the type of data used by iOb.
iOb.showType();
// Get the value of iOb.
// This time, a cast is necessary.
int v = (Integer) iOb.getob();
System.out.println("value: " + v);
System.out.println();
// Create another NonGen object and
// store a String in it.
NonGen strOb = new NonGen("Non-Generics Test");
// Show the type of data used by strOb.
strOb.showType();
// Get the value of strOb.
// Again, notice that a cast is necessary.

String str = (String) strOb.getob();
System.out.println("value: " + str);
// This compiles, but is conceptually wrong!
iOb = strOb;
v = (Integer) iOb.getob(); // run-time error!
}
}
				
			

There are several things of interest in this version. First, notice that NonGen replaces alluses of T with Object. This makes NonGen able to store any type of object, as can the generic version. However, it also prevents the Java compiler from having any real knowledge about the type of data actually stored in NonGen, which is bad for two reasons. First, explicit casts must be employed to retrieve the stored data. Second, many kinds of type mismatch errors
cannot be found until run time. Let’s look closely at each problem.
Notice this line:

int v = (Integer) iOb.getob();
Because the return type of getob( ) is Object, the cast to Integer is necessary to enable that value to be auto-unboxed and stored in v. If you remove the cast, the program will not compile. With the generic version, this cast was implicit. In the non-generic version, the cast must be explicit. This is not only an inconvenience, but also a potential source of error.

Now, consider the following sequence from near the end of the program:
// This compiles, but is conceptually wrong!
iOb = strOb;
v = (Integer) iOb.getob(); // run-time error!

Here, strOb is assigned to iOb. However, strOb refers to an object that contains a string, not an integer. This assignment is syntactically valid because all NonGen references are the same, and any NonGen reference can refer to any other NonGen object. However, the statement is semantically wrong, as the next line shows. Here, the return type of getob( ) is cast to Integer, and then an attempt is made to assign this value to v. The trouble is that iOb now refers to an object that stores a String, not an Integer. Unfortunately, without the use of generics, the Java compiler has no way to know this. Instead, a run-time exception occurs when the cast to Integer is attempted. 

As you know, it is extremely bad to have run-time exceptions occur in your code!

The preceding sequence can’t occur when generics are used. If this sequence were attempted in the generic version of the program, the compiler would catch it and report an error, thus preventing a serious bug that results in a run-time exception. The ability to create type-safe code in which type-mismatch errors are caught at compile time is a key advantage of generics. Although using Object references to create “generic” code has always been possible, that code was not type safe, and its misuse could result in run-time exceptions. Generics prevent this from occurring. In essence, through generics, run-time errors are converted into compile-time errors. This is a major advantage.

5. What is Erasure in Generics?

Usually, it is not necessary to know the details about how the Java compiler transforms your source code into object code. However, in the case of generics, some general understanding of the process is important because it explains why the generic features work as they do—and why their behavior is sometimes a bit surprising. For this reason, a brief discussion of how generics are implemented in Java is in order. An important constraint that governed the way that generics were added to Java was the need for compatibility with previous versions of Java. Simply put, generic code had to be
compatible with preexisting, non-generic code. 

Thus, any changes to the syntax of the Java language, or to the JVM, had to avoid breaking older code. The way Java implements generics while satisfying this constraint is through the use of erasure. In general, here is how erasure works. When your Java code is compiled, all generic type information is removed (erased). This means replacing type parameters with their bound type, which is Object if no explicit bound is specified, and then applying the appropriate casts (as determined by the type arguments) to maintain type compatibility with the types specified by the type arguments. The compiler also enforces this type compatibility.

 This approach to generics means that no type parameters exist at run time. They are simply a source-code mechanism.

Leave a Comment

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

Scroll to Top
Java Sealed Classes Java Generics