How do these three parameterized variables differ?

Specified by AGenericClass , listed below:

 public class AGenericClass<T> { T subject; public void setSubject(T subject) { this.subject = subject; } } 

What is the difference between a , b and c ?

 AGenericClass<String> a = new AGenericClass<>(); AGenericClass<?> b = new AGenericClass<String>(); AGenericClass c = new AGenericClass<String>(); a.setSubject("L"); // OK. b.setSubject("M"); // Error: setSubject(capture<?>) cannot be // applied to (java.lang.String) c.setSubject("N"); // Warning: Unchecked call to 'setSubject(T)' // as a member of raw type 'AGenericClass' 

a b and c are declared without complaint from the IDE, but they all behave differently when setSubject is setSubject .

+6
source share
3 answers

The differences between the three are mainly related to the checks you get at compile time. Given that generics are designed to protect the user from unsafe use at runtime, critical and fundamental differences between them are rooted there.


AGenericClass<String> declares an instance of a generic class specific to the String type. Any operation performed on this generic type that requires a generic parameter will have this parameter bound to String and will provide type checking and type safety at compile time .

That is, if you have AGenericClass<String> a = new AGenericClass<>(); and you are trying to call a.setSubject(3) , Java will not allow compilation of the application since the types do not match.

AGenericClass<?> Declares an instance of a generic class with unknown types. Formally ? is a wildcard in which it can be of any type, which is great if you want to extract elements from it, but not very well if you want to add elements from it.

Cause? AGenericClass<?> Actually AGenericClass<? extends Object> AGenericClass<? extends Object> , and this is important because of the principle of entry and exit . Generally (although this is not a strict guarantee), anything in common with extends implies a read-only operation.

As I said, it’s ok to read, because you are guaranteed a class that is no more than Object , but you cannot write to it, since you do not know and cannot guarantee which object you add to it from any given call.

AGenericClass without type declarations is a raw type. You can read more about them here , but you know that they exist for reasons related to outdated compatibility. If your code uses raw types, you lose compile-time checking , and your code can cause a meta call to ClassCastException at runtime, which is much more difficult to debug, diagnose and resolve.

+3
source
 AGenericClass<String> a = new AGenericClass<>(); 

The so-called Diamond is a generic instance. When you set an empty <> in the constructor of the generic type, the compiler will try to determine the type from the context. In the case example, the compiler will use <String> because a declared with <String> .


 AGenericClass<?> b = new AGenericClass<String>(); 

This is called Unlimited Wildcards . b will be created as a generic unknown type. When you try to use setSubject() , the compiler cannot check the type of the argument. That is why you get an exception. To solve this problem, you can create a helper method with a specific generic type.


 AGenericClass c = new AGenericClass<String>(); 

In this case, c declared as " Raw type ". c will be created as shared with the <Object> parameter. Since you can assign String to Object , the setSubject() method will work with String . In fact, it will work with any type that inherits from Object , and perhaps this may be the cause of the error, and the compiler warns you about this.

+2
source
 AGenericClass<String> a = new AGenericClass<>(); 

Indicates that it is an AGenericClass of type String and will take a string in a parameter instead of a parameter of type T. Therefore, it does not complain when you called a.setSubject("L"); .

 AGenericClass<?> b = new AGenericClass<String>(); 

? indicates that this is an unbounded wildcard, means

not specified or unknown

Moreover, all that is guarantees is an Object return type, if you have a method such as public T getSubject() . You can assign a variable of type Object or pass it as a parameter where the type of Object is expected. Cannot perform the installed operation. extends and super are two keywords you can use with ? to set the lower / upper border that you might want to explore further.

 AGenericClass c = new AGenericClass<String>(); 

Warning: Unchecked call to 'setSubject(T)'.. indicates that this call is executed as a raw type, so it will not complain even if you call setSubject(new Integer(1)) , i.e. it does not perform type security checks. But later, when you try to get this topic and pass it to String, you will encounter a ClassCastException , because you ignored the compiler warning, and we do not get the type safety benefits provided by generics.

+1
source

All Articles