how does erasure handles overriding scenarios in Java?

generics, java, overriding

Solution

Whether a method overrides another doesn't just deal with the erasures of the methods. The compiler determines whether a method overrides another, and it has access to the generic type parameters involved before type erasure occurs.

Your thoughts about using erasure to determine overrides are not quite correct. Let's add the following JLS Section, 8.4.8.1, to the discussion:

An instance method m1, declared in class C, overrides another instance method m2, declared in class A iff all of the following are true:

C is a subclass of A.

The signature of m1 is a subsignature (§8.4.2) of the signature of m2.

Either:

m2 is public, protected, or declared with default access in the same package as C, or

m1 overrides a method m3 (m3 distinct from m1, m3 distinct from m2), such that m3 overrides m2.

It's required that `m1` is a subsignature of `m2`, but not the other way around.

Example 1:

class A {
   public void foo(List<String> list) { }
}

class B extends A {
   @Override
   public void foo(List list) {}
}

This is legal, because the signature of `B`'s `foo` method is the same as the erasure of `A`'s `foo` method.

Example 2:

class A {
   public void foo(List list) { }
}

class B extends A {
   @Override
   public void foo(List list) {}
}

This is legal, because the signatures are the same (even if they are raw).

Example 3:

class A {
   public void foo(List list) { }
}

class B extends A {
   @Override
   public void foo(List<Integer> list) {}
}

This is not legal, because the erasure of the overriding method is not taken into account. That is, `List<Integer>` is compared with the erasure of `List`, which is still just `List`, and they're not the same.

Example 4:

class A {
   public void foo(List<String> list) { }
}

class B extends A {
   @Override
   public void foo(List<Integer> list) {}
}

This is again not legal, because the erasure of the overriding method is not taken into account. That is, `List<Integer>` is compared with the erasure of `List<String>` (`List`), and they're not the same.

You cannot change the generic type parameters of the parameters in the overriding method (e.g. `List<String>` to `List<Integer>`. You cannot introduce generics when overriding a method that didn't utilize generics (e.g. (`List` to `List<Integer>`). However, you can remove generics when overriding (e.g. `List<String>` to `List`).

Problem

This question goes from my previous post in here.. Before I post my question, I am pasting the contents from oracle docs; ``` 8.4.8.1. Overriding (by Instance Methods) An instance method m1, declared in class C, overrides another instance method m2, declared in class A iff all of the following are true: C is a subclass of A. The signature of m1 is a subsignature (§8.4.2) of the signature of m2. 8.4.2. Method Signature The signature of a method m1 is a subsignature of the signature of a method m2 if either: m2 has the same signature as m1, or the signature of m1 is the same as the erasure (§4.6) of the signature of m2. ``` My understanding of `type erasure` when `overriding` is involved is as follows: if after `erasure`, the `signature of m1 and m2` are same, then then they are considered `overridden`. so in my previous post above, I tried to `override` a `parent class method` that takes `List<String>` by a `subclass method` that takes `List<Integer>` assuming after `type erasure` what is left is just `List<Object>`. but that is wrong. so my understanding of the above definition of method `overriding` when `erasure` is involved is totally wrong. can some give a simple example to explain the above point. Thanks. btw the above points come from here.

Original source

Related problems