Java Generics Concepts: Difference between revisions
Line 74: | Line 74: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
===<span id='The_Diamond'></span>The Diamond <>=== | ===<span id='The_Diamond'></span>The Diamond <>=== | ||
Starting with [[Java#Java_7|Java 7]], the type arguments required to invoke the constructor can be replaced with an empty set of type arguments <code><></code> | Starting with [[Java#Java_7|Java 7]], the type arguments required to invoke the constructor of a generic class can be replaced with an empty set of type arguments <code><></code>, as long as the compiler can infer the type arguments from the context: | ||
<syntaxhighlight lang='java'> | |||
SomeType<Integer> st = new SomeType<>(); | |||
</syntaxhighlight> | |||
=Type Inference= | =Type Inference= |
Revision as of 23:18, 14 September 2021
Internal
Overview
Generics, or generic types, or parameterized types are a Java language extension and a set of compiler features introduced in Java 5 and improved in subsequent Java releases, which allow writing more reliable, type-safe code. Generics make certain categories of type-related bugs detectable at compile time.
Generics enable types (classes and interfaces) and individual methods to be parameterized with other types when they are declared in the source code. Type parameters are formal parameters of a type or of a method much like a function parameters allow the function code to produce different results when invoked in the presence of different arguments. Type parameters provide a way to re-use the same code with different inputs - other types in this case.
public class SomeClass<T> {
public T doSomething(T t) {
System.out.println(t);
return t;
}
public <V> V doSomethingElse(V v) {
System.out.println(v);
return v;
}
}
public class Main() {
public static void main(String[] args) {
SomeClass<String> scs = new SomeClass<>();
String s = scs.doSomething("something"); // no cast
// scs.doSomething(new Object()); // compile-time failure: "error: incompatible types: Object cannot be converted to String"
SomeClass<Integer> sci = new SomeClass<>();
Integer i = sci.doSomething(1); // no cast
Double d = sci.doSomethingElse(1.0d); // no cast
}
}
Java code that uses generics has several benefits over non-generic code:
- Allows for stronger type checks at compile time.
- Removes the need to cast.
- Enables programmers to implement generic algorithms - algorithms that work on collections of different types, can be customized, are type safe and easier to read.
Generic Type
Generic Type Declaration
A generic type or a parameterized type is a class or an interface that is parameterized over types.
The syntax of a generic type declaration is:
class|interface name<T1, T2, ... Tn> { // ... }
Type Parameters
The type parameter section is delimited by angle brackets (<...>
). The type parameters are also called type variables. A type variable can be any non-primitive type: any class type, any interface type, any array type, or even another type variable. The type variables can be used anywhere inside the class:
private T1 a; private T2 b; public void something(T1 t1, T2 t2) { // ... }
By convention, type parameter names are single, uppercase letters. Without this convention it would be difficult to tell the difference between a type variable and an ordinary class or interface name. The most commonly used parameter names are:
- E - Element
- K - Key
- V - value
- N - Number
- T - type
- S, U, V, etc. - 2nd, 3rd and 4th types
Generic Type Invocation
To use a generic type from code, the generic type variable must be declared by replacing the type variables with concrete type values, such as String
or Integer
. This is called "invoking the type". A generic type invocation can be thought to be similar to an ordinary method invocation, where instead of passing method arguments, we are passing type arguments, which are actual types. As such, a variable that has a generic type is declared as follows:
SomeType<String> s;
Note that type parameters and type arguments are not the same, and are not interchangeable, in the same way function parameters and arguments are not the same. See:
To instantiate a class of a generic type, use the new
keyword as usual, but replace the generic type parameter with an actual class or interface - the type argument:
SomeType<String> s = new SomeType<String>();
The Diamond <>
Starting with Java 7, the type arguments required to invoke the constructor of a generic class can be replaced with an empty set of type arguments <>
, as long as the compiler can infer the type arguments from the context:
SomeType<Integer> st = new SomeType<>();
Type Inference
Organizatorium
Covariance
Let T and S be two types (class or function types), such that S is a subtype of T. If method m of T is overridden in S, then the corresponding types from the m's signature can either preserve the relationship between T and S (the type used in S is a subtype of the corresponding type in T), reverse the relationship (the type used in S is a super type of the type used in T), or neither preserve nor reverse this relationship. If they preserve the relationship to T and S, we say they are covariant, if they reverse the relationship of T and S, we say they are contravariant.