What is the type erasure of "?"? - java

If I have the following method:
public <U extends Number> void doSomething(List<U> l){
}
Then due to type erasure the compiler will make it to doSomething(List<Number> l). Right?
If this is the case, then why it is not possible to declare the following along with this:
public void doSomething(List<?> l){
}
Isn't this second method, type erased to doSomething(List<Object> l)? Why do I get compiler error of same erasure for these 2 methods?

Your thinking is wrong. Erasure leads to both methods having this signature (List argument types being erased):
public void doSomething(List l) {
}
Hence, the collision. What you thought was possible to do is this:
public <U extends Number> void doSomething(U argument) {
}
public <U extends Object> void doSomething(U argument) {
}
In this case, after erasure, the method signatures will become this (after U having been erased)
public void doSomething(Number argument) {
}
public void doSomething(Object argument) {
}
In this case, there is no signature collision.

? is used as wildcard in generics.
It will be erased.
U extends Number tells that upper bound is Number
List<?> doesn't tell what is upper bound.
EDIT: Based on edited question, after compilation, byte code just contains.
public void doSomething(List argument) {
}
public void doSomething(List argument) {
}
Inheritance in generics is little different than what we know as inheritance in java.

1. ? is used as wild card in Generics.
Eg:
Assume Animal is a Class.
ArrayList<? extends Animal> means Any Class's instance which extends Animal
During the Erasure, which is a process in which Compiler removes the Generics in Class and Methods during the Compilation time, to make the Generics code compatible to the one which was written when Generics were not introduced.
So ? and U will be removed during compilation time.. so during runtime it will be absent

Related

Generic method does not compile when passed a generic argument

I found a strange inconsistence when implementing a Java interface that makes heavy use of generics and I can't find an explanation to why this happens.
I've stripped down the example as much as possible and I'm aware that the usage of generics makes not much sense in this example anymore.
public interface Service<T> {
public List<T> thisCompiles();
public List<T> andThisCompiles(List<Object> inputParam);
public <S extends T> List<S> thisCompilesAswell();
public <S extends T> List<S> evenThisCompiles(List inputParam);
public <S extends T> List<S> butThisDoesnt(List<Object> inputParam);
}
public class ServiceImpl implements Service<Number> {
#Override
public List<Number> thisCompiles() {
return null;
}
#Override
public List<Number> andThisCompiles(List<Object> inputParam) {
return null;
}
#Override
public List<Number> thisCompilesAswell() {
return null;
}
#Override
public List<Number> evenThisCompiles(List inputParam) {
return null;
}
#Override
public List<Number> butThisDoesnt(List<Object> inputParam) {
return null;
}
}
Please note that in the implementation, all return types are List<Number>, although the interface is more generous.
When compiling this snippet (I tried Oracle JDK 8 u144 and OpenJDK 8 u121), I get the following error messages:
The method butThisDoesnt(List<Object>) of type ServiceImpl must override or implement a supertype method
The type ServiceImpl must implement the inherited abstract method Service<Number>.butThisDoesnt(List<Object>)
Name clash: The method butThisDoesnt(List<Object>) of type ServiceImpl has the same erasure as butThisDoesnt(List<Object>) of type Service<T> but does not override it
It seems that compilation fails as soon as the parameter that I pass to the function has some generic parameter itself.
Implementing the 5th function as
#Override
public <S extends Number> List<S> butThisDoesnt(List<Object> inputParam) {
return null;
}
works as expected.
Is there an explanation for this sort of behaviour or did I stumble upon a bug (although it happens in OpenJDK aswell)? Why is the 5th function behaving differently?
I am not interested in finding out how I can make this code compile (I fixed it for my codebase). I just stumbled upon this problem and am curious about the logical explanation why exactly the compilers accept the first four methods but reject the fifth.
I have included a simplified version of the issue. In the following example, the program will not compile because of the method broken.
import java.util.List;
import java.util.ArrayList;
public class Main{
static interface Testing{
<S> List<S> getAList();
<S> List<S> broken(List<String> check);
}
static class Junk implements Testing{
public List<Number> getAList(){
return new ArrayList<>();
}
public List<Number> broken(List<String>check){
return new ArrayList<>();
}
}
public static void main (String[] args) throws java.lang.Exception
{
// your code goes here
}
}
There are two errors and one warning.
Main.java:11: error: Junk is not abstract and does not override
abstract method broken(List) in Testing static class Junk
implements Testing{
^ where S is a type-variable:
S extends Object declared in method broken(List)
Main.java:12: warning: [unchecked] getAList() in Junk implements
getAList() in Testing public List getAList(){
^ return type requires unchecked conversion from List to List where S is a type-variable:
S extends Object declared in method getAList()
Main.java:15: error: name clash: broken(List) in Junk and
broken(List) in Testing have the same erasure, yet neither
overrides the other public List broken(Listcheck){
^ where S is a type-variable:
S extends Object declared in method broken(List)
2 errors
1 warning
Why does the first method infer a cast and only give a warning?
"An unchecked conversion is allowed in the definition, despite being unsound, as a special allowance to allow smooth migration from non-generic to generic code."
https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.5
The other method has a Generic in the argument list, therefor it is not a migration from previously non-generic code, and it is unsound and should be considered an error.
The Problem with your fifth method is that one might think that following snippet works:
List<Integer> ints = new ArrayList<>(); // this works as expected
List<Number> number = new ArrayList<>(); // this works too
number = ints; // this doesn't work
That is, because with generics there exists no such thing as hierarchy relation and so List<Number> is in no sense related to List<Integer>.
This is due to type erasure, generics are only used during compilation. At runtime you only have List-objects (type erasure = no type available anymore at runtime).
In the interface the method is defined as <S extends T, V> List<S> butThisDoesnt(List<V> inputParam); where S can be any subtype of Number. If we now apply the above mentioned to your implementation, then it should make sense.
public List<Number> butThisDoesnt(List<Object> inputParam) {
return null;
}
List<Number> clashes with the definition in the interface, in that way, because List<Number> can contain any Number but can not be a List<Integer>.
Read more to type erasure in this other question. And on this page.
Note please correct me if i'm wrong or if I did miss something.

Java Generics at method level

Can anyone please explain me below code
public <T extends Emp> void foo(ArrayList<T> list) {
list.add(list.remove(0)); // (cycle front element to the back)
}
I am trying to understand how Generics will apply on void return type.
Note: i have changed the code now it is not giving any error.
I am trying to understand how generics will apply on void return type.
This is only a syntax. Generics do not apply to void return type, they apply to the method as a whole.
The name and restrictions on the generic parameter need to go somewhere in the text of your program. In a class declaration they follow the class name in angular brackets. In a generic method declaration they follow the accessibility designator public, and precedes the return type void.
One could easily imagine an alternative placement of generic types, such as
public void foo<T extends Emp>(ArrayList<T> list) // Imaginary syntax
or even
public void foo(ArrayList<T> list) <T extends Emp> // Imaginary syntax
but Java designers decided on the placement before the return type designator.
Generics won't be applied to void.
If you say that the type is <T extends Emp>, you are saying, that any subtype of Emp can be applied in place of T.
In your code, You can use <T> instead of <T extends Emp> as you aren't doing anything with Emp
public <T> void foo(ArrayList<T> list) {
list.add(list.remove(0)); // (cycle front element to the back)
}
Regarding how it'll work, the type will be provided by you when you use this method and at compile time, java will place required casts automatically. So, if you are using this:
ArrayList<String> list = new ArrayList<>();
// Add some items into list
foo(list);
in that case, your foo() method will find out that type <T> is String and so, will behave something like:
public void foo(ArrayList<String> list) {
list.add((String)(list.remove(0)));
}

Using Wildcard to limit the function to take only class and its subclasses

public <T extends Exception> void testFunction(T t) {
}
This is same as writing testFunction(Exception t). I used generics above just to show that java allows this.
But Java is not allowing to do the same using wildcards
public void testFunction(<? Extends Exception> t) {
}
How can i use the wildcards here? There is no real purpose for doing this.But still wanted to see if there is a possible way from a syntax point of view.
public <T extends Integer> void testFunction(T t) { ... }
This function accepts an Integer or any subtype (if such could exist). It does not force you to supply a subtype of Integer. Therefore it accepts the exact same range of types as just
public void testFunction(Integer i) { ... }
There is actually no way to specify a strict subtype (an exclusive upper type bound) in Java.
You don't need generics for that (even if you replace Integer with a non-final class) :
public void testFunction(Integer t) {

Java Generics: Type Extension In Method Declaration Parameters

I am learning Java Generics. My understanding is that Generics parameterize Collections by type. In the Oracle tutorial there is the following comment:
In generic code, the question mark (?), called the wildcard,
represents an unknown type.
On the next page there is the following example of method declaration with an upper-bounded wildcard in the parameters:
public void process(List<? extends Foo> list)
Given that, I am wondering why this method declaration is illegal:
public void process(List<E extends Number> list)
while this one is legal:
public <E extends Number> void process(List<E> list)
When specifying the method parm types, you're using the generic type, so it has to be defined upfront. In this statement, you use E without definition
public void process(List<E extends Number> list) { /* ... */ }
However, in the second one, it is defined before the method return type (void):
public <E extends Number> void process(List<E> list) { /* ... */ }
There's not a much better answer than "because that was how the language was designed." But one way of thinking about it is that type parameters are treated like another list of arguments to the method: they have to all appear at once, in one (ordered) list.
You can call generic methods by passing the type arguments explicitly: for example, foo.<Integer, String>process(list). That means that the type parameters have to have an explicit order, just like normal value arguments.
To complete on #phoenix's answer, the problem in this statement
public void process(List<E extends Number> list) { /* ... */ }
is that the declaration of your generic type E is in the wrong place. The right place is before the return type:
public <E extends Number> void process(List<E> list) { /* ... */ }
However, another possible place to define your generic type would be in the class declaration itself:
class MyClass<E extends Number> {
public void process(List<E> list) { /* ... */ }
}
Approximately both are same , but i am using first one only.

Java Generics Class Parameter Type Inference

Given the interface:
public interface BasedOnOther<T, U extends BasedList<T>> {
public T getOther();
public void staticStatisfied(final U list);
}
The BasedOnOther<T, U extends BasedList<T>> looks very ugly in my use-cases. It is because the T type parameter is already defined in the BasedList<T> part, so the "uglyness" comes from that T needs to be typed twice.
Problem: is it possible to let the Java compiler infer the generic T type from BasedList<T> in a generic class/interface definition?
Ultimately, I'd like to use the interface like:
class X implements BasedOnOther<Y> {
public SomeType getOther() { ... }
public void staticStatisfied(final Y list) { ... }
} // Does not compile, due to invalid parameter count.
Where Y extends BasedList<SomeType>.
Instead:
class X implements BasedOnOther<SomeType, Y> {
public SomeType getOther() { ... }
public void staticStatisfied(final Y list) { ... }
}
Where Y extends BasedList<SomeType>.
Update: ColinD suggested
public interface BasedOnOther<T> {
public T getOther();
public void staticSatisfied(BasedList<T> list);
}
It is impossible to create an implementation such as:
public class X implements BasedOnOther<SomeType> {
public SomeType getOther() { ... }
public void staticStatisfied(MemoryModel list);
} // Does not compile, as it does not implement the interface.
Where MemoryModel extends BasedList<SomeType>, which is needed (as it provides other methods).
It looks as if you don't actually need the type parameter U extends BasedList<T>, if you don't actually need to do anything in the class that requires some specific subclass/implementation of BasedList<T>. The interface could just be:
public interface BasedOnOther<T> {
public T getOther();
public void staticSatisfied(BasedList<T> list);
}
Edit: Based on your update, I don't think there's any way you can do this. I think you'll have to either just go with your original declaration or make some intermediate type that specifies T, like:
public interface BasedOnSomeType<U extends BasedList<SomeType>>
extends BasedOnOther<SomeType, U>
{
}
public class X implements BasedOnSomeType<MemoryModel> { ... }
That seems like kind of a waste though, and I don't really think the original declaration looks that bad.
What about this?
public interface BasedOnOther<T> {
public T getOther();
public <U extends BasedList<T>> void staticStatisfied(final U list);
}
ColinD is almost correct. What you probably want is this:
public interface BasedOnOther<T> {
public T getOther();
public void staticSatisfied(BasedList<? extends T> list);
}
That's because method arguments are covariant but the generics are invariant. Look at this example:
public test() {
Number n1;
Integer n2; //Integer extends Number. Integer is a more-specific type of Number.
n1 = n2; //no problem
n2 = n1; //Type mismatch because the cast might fail.
List<Number> l1;
List<Integer> l2;
List<? extends Number> l3;
l1 = l3; //No problem.
l1 = l2; //Type mismatch because the cast might fail.
}
Why:
Trying to put an Integer where a Number belongs is covariance and it's usually correct for function arguments.
Trying to put a Number where an Integer belongs is the opposite, contravariance, and it's usually correct for function return values. For example, if you defined a function to return a Number, it could return an Integer. If you defined it to return an Integer, however, you couldn't return a Number because that might be a floating-point, for example.
When you're dealing with generics, the compiler can't tell if the generic parameter (in your case, T) is going to be covariant or contravariant. In your code, for example, T is once a return value and once part of an argument. For that reason, generic parameters are invariant by default.
If you want covariance, use <? extends T>. For contravariance, use <? super T>. As a rule of thumb, you probably always want to specify the covariance/contravariance on all public functions. For private functions it doesn't matter as much because you usually already know the types.
This isn't specific to java, other object-oreiented languages have similar issue.
I recently had a very similar problem.
I would suggest, if you are do not need to specifically refer to MemoryModel, i.e. if U extends BasedList<T> is enough, then I would definitely do what Pepe answered.
However, if you must type check for at least two methods that both methods must use MemoryModel specifically and the type inferencing in Pepe's answer is not enough, then the only way to make the use of the clumsy/verbose parameterized constructor more simplistic, is to exploit the generic method parameter inferencing. You would need to create generic static factory methods for each constructor, where the factory methods do the type inferencing (constructors can't type inference in Java).
How to do this is covered in
Effective Java, by Joshua Block; Item 27: Favor generic methods
I also explained this and quoted the solution (with code) here.

Categories

Resources