Java Generics <T> Meaning - java

I was reading and reviewing the following site and had a question.
https://www.geeksforgeeks.org/angle-bracket-in-java-with-examples/
In the explanations below they show class definitions followed by <T> and then when actually implementing these classes they use different types such as or as the parameters. My question is: is the '' notation actually a defined syntax in Java? In particular, is the T a necessary thing in order to define a "Generic"? And then does it basically mean that the parameters can be of multiple different types? Also, if anyone can reword or explain in simpler terms what the meaning of a generic is that would be very helpful. Thanks.

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.

It’s defined syntax since Java 5. You need a type parameter (one or more) for defining a generic. The type parameter needs not be called T, any Java identifier will do. A single uppercase letter is conventional, and T for type is what we often pick if we haven’t got a specific reason for some other letter.
The actual type parameter has to be a reference type. Values still always go into actual parameters in round brackets, not into type parameters (unlike in C++, for example). You can make a new ArrayList<Integer>(50), a list of Integer objects with an initial capacity for 50 of them.
That the actual type parameter has to be a reference type means that you can have a List<String>, a List<LocalDate> or a list of an interface type that you have declared yourself, even a List<int[]>. In the Java versions I have used (up to Java 10) the type parameter cannot be a primitive type (like int), but it can be an array type (like int[] or String[][], though often impractical). Allowing primitive types may come in a future Java version.
Link: Similar question: What does < T > (angle brackets) mean in Java?

Related

Difference between V, T and E in Java [duplicate]

This question already has answers here:
What is the difference between 'E', 'T', and '?' for Java generics?
(6 answers)
Generic type parameter naming convention for Java (with multiple chars)?
(5 answers)
Where does the T, U, V convention for generic type params come from? [closed]
(1 answer)
Understanding Java generics. Type parameter conventions
(5 answers)
Closed 7 months ago.
I use javap often.
So when I see JDK classes across, I understood that probably:
T means Type;
E means Enumertion;
Meaning of V is unclear for me.
Please shed some light on this question?
Maybe I am wrong. But I see several JDK classes belongs to package java.util.function.* , java.util.concurrent.* has this V, T, E in place of class type, return type.
In Java 5 Generic types were introduced in the language. In a nutshell generics - is a mechanism of type safety, they are meant to make the code more robust. Generics allow writing clean and highly reusable code without performing instanceof checks and type-casting (to be precise type-casts are still there, they would be added by the compiler under the hood, and they are safe).
V, T, E, etc. are so-called type variables. These are only placeholders, not the actual types, i.e. it's a way to tell the compiler that you expect a particular type at runtime and you can refer to this type using type variable.
In your code, you can call type variables with any name you like. The common convention is to use single uppercase letters like T, R, but compiler be happy with Cat as a type variable, and even with a name of existing JDK classes and interfaces like Integer (which is highly discouraged, but your code would compile).
public class MyClass<T> {} // OK
public class MyClass<CAT> {} // OK
public class MyClass<Integer> {} // OK, note `Integer` is just a placeholder and has the the same meaning as `T` or `A`
public class MyClass<super> {} // will NOT compile, keywords and restricted identifiers (like `record` which isn't a keyword) can't be used as generic type parameters
Regarding type variables that you can encounter in the JDK, there's no common policy that has been listed anywhere. Sometimes there's some informal intuition behind these names, sometimes probably not (e.g. when you see T, U, V defined together as generic variables you can clearly observe that it's an order of letters in the English alphabet, T - stands for type, and U, V are simply some other types distinct from T and each other).
Speaking of cases when probably there's some meaning:
E - in Collection<E> most likely means element, and in Enum<E> - stands for enum.
R in Function<T,R> stands for result, or return type of the function.
K and V in Map<K,V> and Map.Entry<K,V> stand for key and value.
A in the Collector<T,A,R> interface is meant to represent accumulation type (type of the mutable container which collector uses internally).
Java has a feature called generics which is used to develop classes such that its functionality can be used with any type of objects. The letter you see like T, E or V are just place holders. For example List<E>. This is substituted with actual class when start using the list like below.
List<Integer> numbers = new ArrayList<Integer>();
Java uses this approach to check type safety so that a String object cannot be added to an Integer list.
numbers.add(1); //Good
numbers.add("Harry"); //Compilation error
Here are some useful resources.
https://docs.oracle.com/javase/tutorial/java/generics/index.html
https://www.baeldung.com/java-generics

How DWR cast incoming data and evade type erasure

I would like to request for an item class of collection (kind of specific reflection). But regarding to type erasure it seems not possible and also regarding to some topics I've read here on stack. There are some workarounds (here), but I'm curious if somebody know how is it done for example by DWR:
http://directwebremoting.org/dwr/documentation/server/configuration/dwrxml/signatures.html
or in case that there is some better workaround it would be great.
Let's say we have something like:
public String foo(List<String> possibleFoos) {
and all I need to is find out that parameter possibleFoos is list of Strings, not just List
While it's true that Java will erase types at runtime (thus turning List<String> into just List), in many cases it actually does store the generic type in runtime allowing you to restore the information lost to erasure.
You can retrieve the actual generic types for these:
Method arguments (your case)
Method return types
Field types
Super classes/interfaces
This means if you simply have an object of type List, there's nothing you can do to get it's generic type (object.getClass() will get you List and that's it) - it's been permanently lost. But, if you're trying to figure out the generic type for a method argument or any of the above, you usually can by using reflection. As your case doesn't involve type variables or other complications, it's pretty straightforward to get the actual type:
ParameterizedType listArgument = (ParameterizedType) ClassDeclaringFoo.class.getMethod("foo", List.class).getGenericParameterTypes()[0];
Type listType = listArgument.getActualTypeArguments()[0]; //This will be a Class representing String, the type of the List
If you had a more parameters and a map instead:
public String foo(Object bar, Map<String, Number> possibleFoos) { ... }
The code would be similar:
ParameterizedType mapArgument = (ParameterizedType) ClassDeclaringFoo.class.getMethod("foo", Object.class, Map.class).getGenericParameterTypes()[1]; //1 is the index of the map argument
Type keyType = mapArgument.getActualTypeArguments()[0]; //This will be a Class representing String, the type of the Map key
Type valType = mapArgument.getActualTypeArguments()[1]; //This will be a Class representing Number, the type of the Map value
It's safe to assume this is what DWR is using as well, as the types are method arguments.
Similar methods are available for other listed cases:
Class.getMethod(...).getGenericReturnType() will get you the real return type
Class.getField(fieldName).getGenericType() will get you the real type of the field
Class.getGenericSuperClass() will get you the real super type
Class.getGenericInterfaces() will get you the real interface types
Equivalent methods exist allowing access to AnnotatedType (generic type plus annotations on the type usage) introduced in Java 8:
Class.getMethod(...).getAnnotatedParameterTypes()
Class.getMethod(...).getAnnotatedReturnType()
Class.getField(fieldName).getAnnotatedType()
Class.getAnnotatedSuperClass()
Class.getAnnotatedInterfaces()
Now, this is all dandy when your case as simple as in the example.
But, imagine if your example looked like this:
public T foo(List<T> possibleFoos) {...}
In this case, getGenericParameterTypes()[0].getActualTypeArguments()[0] would give you T which is rather useless. To resolve what T stands for, you'd have to look into the class definition, and perhaps super classes, while keeping track of how the type variables are named in each class, as the names could be different in each.
To make working with generic type reflection easier, you can use a wonderful library called GenTyRef that does the hard work for you, and if you need support for AnnotatedTypes, you can use my fork called GeAnTyRef (both are in Maven Central). They also include a type factory, that allows you to construct instances of (Annotated)Type, which you can not easily do using normal Java API. There's also a handy super type token implementation allowing you to get an (Annotated)Type literal.
With those, you can do everything with generic types that Java allows without the hassle I explained above:
GenericTypeReflector#getExactParameterTypes( ... )
GenericTypeReflector#getExactReturnType( ... )
GenericTypeReflector#getExactFieldType( ... )
GenericTypeReflector#getExactSuperType( ... )
And many more operations, like figuring out if one Type is a super type of another (similar to Class#isAssignableFrom but for generic types), resolving specific type variables etc.

What is that <E> in the method signature?

I was reading about Set interface from here which the code sipped below which is a generic method that removes duplicates from a collection.
My question is what is that **< E>** placed after static before Set<E> ?
I mean wouldn't that Set<E> be enough ? why <E> was there twice?
public static <E> Set<E> removeDups(Collection<E> c) {
return new LinkedHashSet<E>(c);
}
Here **<E>** is a generic type. Generic type is defined as
A generic type is a generic class or interface that is parameterized
over types. The following Box class will be modified to demonstrate
the concept. LINK
And regarding you question related to <E>. A good description for it can be found on the same tutorial
Type Parameter Naming Conventions
By convention, type parameter names are single, uppercase letters.
This stands in sharp contrast to the variable naming conventions that
you already know about, and with good reason: 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 type parameter names are:
E - Element (used extensively by the Java Collections Framework)
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types
You'll see these names used throughout the Java SE API and the rest of
this lesson.
This means that this method declares a generic parameter type which the class does not define; in this case, you MUST declare the parameter type before the return type (even if this "return type" is void).
Think about it this way. Remove the initial <E>. Your declaration would then become:
public static Set<E> removeDups(Collection<E> c)
What is E here? Unless it is a generic parameter type defined by the class itself, it can only be an existing class.
Hence this syntax. It allows you to define a generic parameter for use in the method signature.
It's just the generic type used within the method. Static methods that use generic types must specify that type before the return type.

Java Generics: Wildcard capture misunderstanding

Reading the Java online tutorial I haven't understood anything about wildcard capture.
For example:
import java.util.List;
public class WildcardError {
void foo(List<?> i) {
i.set(0, i.get(0));
}
}
Why can't the compiler retain the assignment safely?
It knows that, by executing for instance, the method with an Integer List, it gets from i.get an Integer value. So it tries to set an Integer value at index 0 to the same Integer list (i).
So, what's wrong? Why write Wildcard helper?
why the compiler can't retain the assignment safe? It knows that,by executing for instance, the method with an Integer List, it gets from i.get an Integer value. So it try to set an Integer value at index 0 to the same Integer list (i).
Put differently, why does the compiler not know that the two usages of the wildcard type List<?> in
i.set(0, i.get(0));
refer to the same actual type?
Well, that would require the compiler to know that i contains the same instance for both evaluations of the expression. Since i isn't even final, the compiler would have to check whether i could possibly have been assigned in between evaluating the two expressions. Such an analysis is only simple for local variables (for who knows whether an invoked method will update a particular field of a particular object?). This is quite a bit of additional complexity in the compiler for rarely manifesting benefits. I suppose that's why the designers of the Java programming language kept things simple by specifying that different uses of the same wildcard type have different captures.
why the compiler can't retain the assignment safe?
The compiler doesn't know anything about the type of elements in List<?> i, by definition of ?. Wildcard does not mean "any type;" it means "some unknown type."
It knows that,by executing for instance, the method with an Integer List, it gets from i.get an Integer value.
That's true, but as I said above: the compiler can only know – at compile time, remember – that i.get(0) returns an Object, which is the upper bound of ?. But there's no guarantee that ? is at runtime Object, so there is no way for the compiler to know that i.set(0, i.get(0)) is a safe call. It's like writing this:
List<Foo> fooz = /* init */;
Object foo = fooz.get(0);
fooz.set(0, foo); // won't compile because foo is an object, not a Foo
More reading:
Can't add value to the Java collection with wildcard generic type
Java Collections using wildcard
Generic collection & wildcard in java
Generics - Cannot add to a List with unbounded wildcard
What is the difference betwen Collection<?> and Collection<T>
According to Get-Put principle:
If you have extends wildcard as in List<? extends Something>, then:
1A. You can get from the structure using Something or its superclass reference.
void foo(List<? extends Number> nums) {
Number number = nums.get(0);
Object number = nums.get(0); // superclass reference also works.
}
1B. You cannot add anything to the structure (except null).
void foo(List<? extends Number> nums) {
nums.add(1); Compile error
nums.add(1L); Compile error
nums.add(null); // only null is allowed.
}
Similarly, if you have super wildcard as in List<? super Something>, then:
2A. You can add to the structure which is Something or its subclass.
For eg:
void foo(List<? super Number> nums) {
nums.add(1); // Integer is a subclass of Number
nums.add(1L); // Long is a subclass of Number
nums.add("str"); // Compile error: String is not subclass of Number
}
2A. You cannot get from the structure (except via Object reference).
For eg:
void foo(List<? super Integer> nums) {
Integer num = nums.get(0); // Compile error
Number num = nums.get(0); // Compile error
Object num = nums.get(0); // Only get via Object reference is allowed.
}
Coming back to OP's question, List<?> i is just the short representation for List<? extends Object> i. And since it's a extends wildcard, the set operation fails.
The final piece remaining is WHY the operation fails ? Or why the Get-Put principle in the first place? - This has to do with type safety as answered by Jon Skeet here.
I also find this question hard to understand; splitting the single command into two commands helped me.
Below code is what actually happens in the background when the original method is inspected&compiled, the compiler makes its own local variable: the result of the i.get(0) call is placed in the register on the local variable stack.
And that is - for the understanding of this issue - the same as making a local variable which for convenience I have given the name element.
import java.util.List;
public class WildcardError {
void foo(List<?> i) {
Object element = i.get(0); // command 1
i.set(0, element); // command 2
}
}
When command 1 is inspected, it can only set the type of element to Object (--> upperbound concept, see Matt's answer), as it can not use ? as a variable type; the ? is only used for indicating that the generic type is unknown.
Variable types can only be real types or generic types, but since you don't use a generic type in this method like <T> for example, it is forced to use a real type. This forcing is done because of the following lines in the java specification (jls8, 18.2.1):
A constraint formula of the form ‹Expression → T› is reduced as follows:
[...]
– If the expression is a class instance creation expression or a method invocation expression, the constraint reduces to the bound set B3 which would be used to determine the expression's invocation type when targeting T, as defined in §18.5.2. (For a class instance creation expression, the corresponding "method" used for inference is defined in §15.9.3).
Solution Will Be,
import java.util.List;
public class WildcardError {
private void fooHelper(List<T> i){
i.set(0, i.get(0));
}
public void foo(List<?> i){
fooHelper(i);
}
}
here fooHelper will capture type T of wildcard ? (so as the name wildcard capture).
I think you misunderstand the ? in Generics. It isn't "wildcard capture" at runtime. It is "wildcard capture" at compile time. Since that capture is gone after compilation, the List<?> often becomes List<Object> or a list of some interface or common base class that is the lowest subclass that is shared amongst the instances according to the Generics type.
Because Java had to make the Generics system compatible with non-Generics supporting JVMs, there are no Generics types at runtime. This means that all checks / captures don't exist at runtime. Either the compiler permits a very narrow range of compatible Generics type assignments when it compiles, or it throws an error.
Now if you want to hold a Generics type at runtime, there are approaches. Most of them involve passing the Class object as a parameter into a constructor, which holds it in a field. Then you can refer to the field for the exact passed type. You can entangle this type with your Generics parameters; and by doing so, you can then have the actual type in places in the runtime code where the "Generics type parameters" have been replaced by their most permissive type supported in the real Java type system. I don't recommend doing this for many situations, as it is a lot of work (and not likely to give you much more security); but, occasionally you really do need the type.
I guess your misunderstanding of the restriction comes from substitution of ? for any type, Object or something like that in your mind. But that assumption is not correct, ? in fact means unknown type. So in the following line
fooz.set(0, foo);
you're trying to assign the variable of some type to the variable of unknown type (since the function signature is like void set(int, ?)), which can never be possible, whatever the type of foo would be. In your case the type of foo is Object and you cannot assign it to a variable of some unknown type, which in fact may be Foo, Bar or any other.

Wikipedia says for Generics - "One version of the class or function is compiled, works for all type parameters. "

How does Java do this? If there are not multiple Classes being created, then how does it support multiple Typed instantiations of the Generic class?
Until now I used to believe that it is like C++, but now i am totally confused.
Can't figure out how Java pulls this off?
-Ajay
This is due to type erasure. Java's generics are primarily a compile-time feature. All generic types are, at runtime, Objects replaced with their lower bound.
Thanks to Michael for the correction:
Generics are not strictly a compile-time feature. If a class, method or field has a generic type with a concrete type parameter specified, this information will be present at runtime and is available via reflection.
To elaborate:
When runtime inspecting a parameterizable type itself, like java.util.List, there is no way of knowing what type is has been parameterized to. This makes sense since the type can be parameterized to all kinds of types in the same application. But, when you inspect the method or field that declares the use of a parameterized type, you can see at runtime what type the paramerizable type was parameterized to. In short:
You cannot see on a type itself what type it is parameterized to a runtime, but you can see it in fields and methods where it is used and parameterized. Its concrete parameterizations in other words.
Source
Since only reference types can be used as generic type arguments in Java, and all pointers are the same size, the same byte code can be used.
As for type safety, generics in Java a compile/link-time only. That is, during compilation generic types are replaced by their erasure. The erasure of a type variable T is its lower bound (or Object, if it doesn't have one). For instance,
class Complex<N extends Number> {
N real;
N imag;
}
becomes
class Complex {
Number real;
Number imag;
}
as far as byte code is concerned.
Needless to say that is not pretty and causes numerous limitations. The most obvious one is that
new N();
does not compile, because the runtime does not know the type N stands for and hence can't instiate the type. Similarly,
(N) n
will compile, but unlike an ordinary cast in Java, will not be checked at runtime. An incorrect cast can therefore cause a variable to hold an object of the wrong type. This is called heap pollution. To ensure (a weaker form of) type safety, the compiler will introduce casts into calling code. For instance,
boolean right(Complex<Integer> c) {
return c.real > 0;
}
will become
boolean right(Complex c) {
return ((Integer) c.real) > 0;
}
To sum things up, the generics implementation in Java is not pretty, especially compared to the .NET one. The things we have to live with for the sake of backwards compatibility ...
good question. The genetic information is not kept during runtime. E.g if you have this code
List<Apple> apples = new ArrayList<Apple>(); // this is a list of apples
But in runtime it becomes :
List apples = new ArrayList(); // this is how it looks in runtime

Categories

Resources