Reading the Javadoc for the #Override annotation, I came across the following rule:
If a method is annotated with this
annotation type compilers are required to generate an error message
unless at least one of the following conditions hold:
The method does override or implement a method declared in a supertype.
The method has a signature that is override-equivalent to that of any public method
declared in Object.
I'm clear on the first point, but I'm unsure about the second one.
What does it mean by "override-equivalent"? How are public methods of Object special in this respect? And why is this not covered under the first criterion?
Moreover, this is only true of the Java 7+ documentation. The Java 6 doc doesn't say anything about override-equivalence. Why the change?
Update:
After further consulting the JLS (Section 8.4.2), I found the following explanation of override-equivalence:
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.
Two method signatures m1 and m2 are override-equivalent iff either m1 is a
subsignature of m2 or m2 is a subsignature of m1.
As far as I can tell, this answers the first question ("What does it mean?") and the third question ("Why doesn't the first condition cover this?").
If I understand correctly (please inform me if I don't!), there is only one case where two methods are override-equivalent and which doesn't fall under the first condition of the original question. This is the case when the erasure of the signature of the subclass method is the same as the signature of the superclass method, but not the other way around.
The second condition of the original question, then, would only come into play when we attempt to add type parameters when attempting to "override" a public method of the Object class. I tried the following simple example to test this, with an unused type parameter:
public class Foo {
#Override
public <T> boolean equals(Object obj) {
return true;
}
}
Of course, this class doesn't compile, because the method doesn't actually override the equals method and thus clashes with it. But I also still receive a compiler error for using the #Override annotation. Am I wrong in assuming that this example meets the second condition for #Override usage? Or is the compiler generating this error despite not being required to?
The reason for this is to allow you to use the #Override annotation in interfaces, which do not inherit from Object but implicitly declare all public methods from Object (see JLS section 9.2 interface members). You are thus allowed to declare an interface like:
interface Bar { #Override int hashCode(); }
However, you would not be allowed to declare the following interface:
interface Quux { #Override Object clone(); }
since the clone() method is not implicitly declared in an interface (it is not public).
This is described in JLS section 9.6.3.4 #Override (the Javadoc for #Override still refers to an old section number)
Your question is basically a design question and JLS explains its:
"The notion of subsignature is designed to express a relationship
between two methods whose signatures are not identical, but in which
one may override the other. Specifically, it allows a method whose
signature does not use generic types to override any generified
version of that method. This is important so that library designers
may freely generify methods independently of clients that define
subclasses or subinterfaces of the library."
Your code is not a valid example of this , see the below code it works:
public class SubSignatureTest extends SignatureTest {
#Override
public List test(Collection p) {
return null;
}
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
class SignatureTest {
public <T> List<T> test(Collection<T> t) {
return null;
}
}
Whole point is that signature of superclass and subclass should be same after erasure.
EDIT:
When we talk of override equivalence then parent class should have generic method and child class should have non generic method. Here is an example to explain this .Below code will not work because child class have generic method. For a moment lets assume that java allowed that then the call in main method will always fail :
class A{
public int compareTo(Object o){
return 0;
}
}
class B extends A implements Comparable<B>{
public int compareTo(B b){
return 0;
}
public static void main(String[] argv){
System.out.println(new B().compareTo(new Object()));
}
}
In class B method will be like this after compilation:
public int compareTo(Object x){
return compareTo((B)x);
}
Which means this is always error: new B().compareTo(new Object()) .
Therefore java will not allow child class to have generic method if parent class has non generic method. So you can't define override equivalence methods for object class.
Hope that clarifies.
I used the post http://lists.seas.upenn.edu/pipermail/types-list/2006/001091.html for reference, it has lot more details.
Related
I have a code and I am not able to get why the output will be "Radial Tire with long".Can somebody help me to understand this code?
class Tyre {
public void front() throws RuntimeException {
System.out.println("Tire");
}
public void front(long a) {
System.out.println("Radial Tire with long");
}
}
class TestSolution extends Tyre {
public void front() {
System.out.println("Radial Tire");
}
public void front(int a) throws RuntimeException {
System.out.println("Radial Tire with int");
}
public static void main(String... args) {
Tyre t = new TestSolution();
int a = 10;
t.front(a);
}
}
front is not overridden in TestSolution, it is overloaded.
You can regard an overloaded function as a completely different function, like one with a different name.
So t.front(a) will call the one in Tyre, with an a implicitly converted to long.
So if we go with definitions
Overloading means methods with same name but with different number or order of parameters.
Overriding means method with same name with same number of parameters along with rules mentioned here
So in your case front method is overloaded in both the classes Tyre and TestSolution
method front() from Tyre class is overridden in class TestSolution.
no overriding in case of method front(long a) and front(int a).
There's no overriding taking place in your main.
t's static (compile-time) type is Tyre, so, since method overload resolution is determined by the compile-time type of the instance, the only front methods available for the compiler to choose from are those declared in the base class Tyre :
public void front()
public void front(long a)
Only the latter (public void front(long a)) matches the arguments of the call t.front(a), and that method is not overridden by the sub-class. Therefore Radial Tire with long is displayed.
Calling ((TestSolution)t).front(a); would invoke the sub-class's method - public void front(int a).
General rule: if I have a variable of one class I can access only methods and components defined in that class.
The only particular case is:
you have a component or method both in the super class and in the subclass (overriding)
you have a variable of the super class and an object of the subclass (your case)
In these cases you can follow the following rule:
for the components the type of the variable decides which to use
for the methods the type of the object does (late binding)
In your case as stated before the method is not overridden so you can't apply the last rule.
Lets understand the difference between overloading and overriding
Overloading:
The Java programming language supports overloading methods, and Java can distinguish between methods with different method signatures. This means that methods within a class can have the same name if they have different parameter lists
Overriding:
An instance method in a subclass with the same signature (name, plus the number and the type of its parameters) and return type as an instance method in the superclass overrides the superclass's method.
Tyre declared front() method with long as parameter.
TyreSolution declared front() method with int as parameter.
Since the method signature is different, TyreSolution overloads Tyre's front() method
If you change signature of front() in TyreSolution to accept long value as input parameter instead of int, then TyreSolution overrides Tyre's front() method.
e.g. TestSolution class definition of front() method
public void front(long a) throws RuntimeException {
System.out.println("Radial Tire with long in TestSolution");
}
output:
Radial Tire with long in TestSolution
Problem outline
I'm generifying the better part of my current project's base and I had an idea that I decided to test regarding overriding an abstract method. Here are my test classes in Java:
public abstract class Base {
public abstract <T extends Base> T test();
}
First implementation:
public class Inheritor extends Base {
#Override
public Inheritor test() {
return null;
}
}
Second implementation:
public class Inheritor2 extends Base {
#Override
public <T extends Base> T test() {
return null;
}
}
Question 1
Why does it compile? I admit I had high hopes it would be legal, since it makes the contract not only ensure it returns something that does extend Base, but is more specialized already (so that I don't need to cast the result to my specialized class somewhere later).
All sounds nice but do I really fulfill the contract that the base class forces me into? My overriden implementation in Inheritor loses certain layer of genericness doesn't it? My implementation of this method in Inheritor doesn't ever return an instance of Inheritor2, possibility of which the abstract method seemed to enforce (as both extend Base).
I would like pointing to some excerpt from documentation. My guess is it has something to do with type erasure, would be nice if someone mentioned it's accuracy in his/her answer.
Question 2
Does this procedure have a formal name other than one I stated in the title?
Question 3
Is this possible in C#? Colleague's scratch test seemed to fail on compilation. Is there then a difference in approach to generic abstract method overriding?
Here are the technicalities.
Concerning overriding:
An instance method mC declared in or inherited by class C, overrides
from C another method mA declared in class A, iff all of the following
are true:
A is a superclass of C.
C does not inherit mA.
The signature of mC is a subsignature (§8.4.2) of the signature of mA.
One of the following is true:
mA is public.
[...]
In your case, A is Base and C is Inheritor, Base#test() is mA and Inheritor#test() is mC.
mC is a subsignature of mA because
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.
The erasure of mA is
public abstract Base test()
and mC
public Inheritor test()
is a subsignature. What about the return type?
If a method declaration d1 with return type R1 overrides or hides the
declaration of another method d2 with return type R2, then d1 must be
return-type-substitutable (§8.4.5) for d2, or a compile-time error
occurs.
Following the return-type-substitutable, we see
If R1 is a reference type then one of the following is true:
R1 can be converted to a subtype of R2 by unchecked conversion (§5.1.9).
Inheritor is a subtype of T extends Base through unchecked conversion, so we're all good (though you should have gotten a warning from your compiler).
So to answer your questions:
It compiles because of the rules declared in the Java Language Specification.
It's called overriding.
I don't have a full answer for you, but C# doesn't seem to have type erasure, so these rules wouldn't apply.
The dangers of unchecked conversion would allow you to do
class Inheritor extends Base {
#Override
public Inheritor test() {
return new Inheritor();
}
}
and then
Base ref = new Inheritor();
Inheritor2 wrong = ref.<Inheritor2>test();
which would cause a ClassCastException at runtime. Use it at your own risk.
I can tell you why it should work - Liskov substitution principle
The question to ask is, if you replace Base with Inheritor, or Inheritor2, will all the consumers continue to work without negative consequences? If they expect anything that extends Base from test, then swapping Inheritor2 with Inheritor, or vice versa, will be fine from the perspective a consumer. So, the compiler ought to allow it.
You do really fulfill the contract, which says any subtype of Base can be returned. Any subtype can be one subtype, a random subtype, etc.
Like the commenter Elliott, I believe it's just called overriding a method.
Here's a similar implementation in C# but with generics on the class level.
public abstract class Base<Type>
where Type : Base<Type>
{
public abstract Type test();
}
public class Inheritor:Base<Inheritor>
{
public override Inheritor test()
{
return null;
}
}
public class Inheritor2<Type> : Base<Type>
where Type : Base<Type>
{
public override Type test()
{
return default(Type);
}
}
public class Test
{
public Test(Object o) {
System.out.println("object");
}
public Test(int[] o) {
System.out.println("array");
}
public static void main(String[] args) {
new Test(null);
}
}
Output :
array
Can somebody please explain me the reason behind this?
The rule is: the more specific method will be called. In this case, it's the method receiving a int[] which is more specific than the one receiving a java.lang.Object parameter.
Here's a link to Java's official documentation referencing to this case. Take a look at section 15.2.2. Quoting an interesting part (section 15.2.2.5):
If more than one member method is both accessible and applicable to a
method invocation, it is necessary to choose one to provide the
descriptor for the run-time method dispatch. The Java programming
language uses the rule that the most specific method is chosen.
The informal intuition is that one method is more specific than
another if any invocation handled by the first method could be passed
on to the other one without a compile-time type error.
An another one:
It is possible that no method is the most specific, because there are
two or more methods that are maximally specific. In this case:
If all the maximally specific methods have override-equivalent
(§8.4.2) signatures, then: If exactly one of the maximally specific
methods is not declared abstract, it is the most specific method.
Otherwise, if all the maximally specific methods are declared
abstract, and the signatures of all of the maximally specific methods
have the same erasure (§4.6), then the most specific method is chosen
arbitrarily among the subset of the maximally specific methods that
have the most specific return type. However, the most specific method
is considered to throw a checked exception if and only if that
exception or its erasure is declared in the throws clauses of each of
the maximally specific methods. Otherwise, we say that the method
invocation is ambiguous, and a compile-time error occurs.
It's always subclass would be preferred over the parent class. If you want to call Object one you could do the following:
new goFuncTest((Object) null);
As pablo's answer suggests, the most specific / least generic method will be called. Actually, the classlevel in the class hierarchy is checked to decide which method to call. The method with lower class level is called.
If 2 classes are at the same level, then you will get a compile time error stating - ambiguous method call just like in the below case.
public class Sample {
void someMethod(Object o) {
System.out.println("object");
}
void someMethod(String s) {
System.out.println("String");
}
void someMethod(int[] o) {
System.out.println("int[]");
}
public static void main(String[] args) {
new Sample().someMethod(null); // error ambiguous call both array and String are direct children of Object
}
Case -2 : To prove that the method with lower class level will be called.
public class Sample {
void someMethod(Object o) {
System.out.println("object");
}
void someMethod(OutputStream os) {
System.out.println("OutputStream");
}
void someMethod(FileOutputStream fos) {
System.out.println("FileOutputStream");
}
public static void main(String[] args) {
new Sample().someMethod(null);
}
}
O/P :FileOutputStream
Since FileOutputStream is child of OutputStream which is again a child of Object class (FileOutputStream is also a child of both OutputStream and Object classes). So the compiler goes like this Object --> OutputStream --> FileOutputStream while resolving the method call.
Thumb rule is child first in method call. As Object is parent of all and as null can be assigned to any type of object instance variable, it will first match any java type(which of course is child of object) and then super parent i.e. Object.
up gradation of Null to Array is preferred over casting it to Object. Object is top in the hierarchy while Array is closest to Null.
This is like up gradation of byte to int.
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.
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).
Because Java is a strictly-typed language, it has to be careful about covariance and how types work together. Erasure is not an excuse to break the type rules.
For example:
class BaseGood<T> {
public void doStuff(T elem) {
// ...
}
}
class DerivedGood<T> extends BaseGood {
public void doStuff(Object elem) {
super.doStuff(elem);
}
}
class BaseBad {
public void doStuff(List<Double> list) {
// ...
}
}
class DerivedBad extends BaseBad {
public void doStuff(List<Integer> list) {
super.doStuff(list);
// ...
}
}
Here, we have two different cases for erasure.
With the BaseGood and DerivedGood classes, the two methods have the same erasure: void doStuff(Object elem) and it can be known that T will always be of type Object and therefore the function is type-safe.
With the BaseBad and DerivedBad classes, the two methods have the same erasure: void doStuff(List list); however, the type system cannot convert from a List<Integer> to a List<Double> safely (or to and from any List for that matter). Allowing this conversion would potentially allow attempts to put Doubles into lists of Integers (or the issue that generics moves detection of to compile-time).
Having the methods override friendly after erasure does not mean that the type system cannot check for incompatibilities pre-erasure.
EDIT
Also, real erasure as applied to class/method definitions does not occur at compile-time, it occurs at runtime. Code that references generic methods just compile as if the function was called without generics, with type-safety enforced by the compiler and by run-time checking.
See: Java generics - type erasure - when and what happens
There is also another case where you pass a type-erased generic class to an override and because the type system is unable to check whether you passed a proper list based on the type of the method, it must allow it.
Something called the "bridge method" concept related to Java Generics made me stop at a point and think over it.
Btw, I only know that it occurs at the
bytecode level and is not available
for us to use.
But I am eager to know the concept behind the "bridge method" used by the Java compiler.
What exactly happens behind the scenes and why it is used?
Any help with an example would be greatly appreciated.
It's a method that allows a class extending a generic class or implementing a generic interface (with a concrete type parameter) to still be used as a raw type.
Imagine this:
public class MyComparator implements Comparator<Integer> {
public int compare(Integer a, Integer b) {
//
}
}
This can't be used in its raw form, passing two Objects to compare, because the types are compiled in to the compare method (contrary to what would happen were it a generic type parameter T, where the type would be erased). So instead, behind the scenes, the compiler adds a "bridge method", which looks something like this (were it Java source):
public class MyComparator implements Comparator<Integer> {
public int compare(Integer a, Integer b) {
//
}
//THIS is a "bridge method"
public int compare(Object a, Object b) {
return compare((Integer)a, (Integer)b);
}
}
The compiler protects access to the bridge method, enforcing that explicit calls directly to it result in a compile time error. Now the class can be used in its raw form as well:
Object a = 5;
Object b = 6;
Comparator rawComp = new MyComparator();
int comp = rawComp.compare(a, b);
Why else is it needed?
In addition to adding support for explicit use of raw types (which is mainly for backwards compatability) bridge methods are also required to support type erasure. With type erasure, a method like this:
public <T> T max(List<T> list, Comparator<T> comp) {
T biggestSoFar = list.get(0);
for ( T t : list ) {
if (comp.compare(t, biggestSoFar) > 0) {
biggestSoFar = t;
}
}
return biggestSoFar;
}
is actually compiled into bytecode compatible with this:
public Object max(List list, Comparator comp) {
Object biggestSoFar = list.get(0);
for ( Object t : list ) {
if (comp.compare(t, biggestSoFar) > 0) { //IMPORTANT
biggestSoFar = t;
}
}
return biggestSoFar;
}
If the bridge method didn't exist and you passed a List<Integer> and a MyComparator to this function, the call at the line tagged IMPORTANT would fail since MyComparator would have no method called compare that takes two Objects...only one that takes two Integers.
The FAQ below is a good read.
See Also:
The Generics FAQ - What is a bridge method?
Java bridge methods explained (thanks #Bozho)
If you want to understand why you need bridge method, you better understand what happens without it. Suppose there is no bridge method.
class A<T>{
private T value;
public void set(T newVal){
value=newVal
}
}
class B extends A<String>{
public void set(String newVal){
System.out.println(newVal);
super.set(newVal);
}
}
Notice that after erasure, method set in A became public void set(Object newVal) since there is no bound on Type parameter T. There is no method in class B the signature of which is the same as set in A. So there is no override. Hence, when something like this happened:
A a=new B();
a.set("Hello World!");
Polymorphism won't work here. Remember you need to override the method of parent class in child class so that you can use parent class var to trigger polymorphism.
What bridge method does is silently override the method in parent class with all the information from a method with the same name but a different signature. With the help of the bridge method, polymorphism worked. Though on the surface, you override the parent class method with a method of different signature.
It's insteresting to note that the compiler infers that MyComparator's method:
public int compare(Integer a, Integer b) {/* code */}
is trying to override Comparator<T>'s
public int compare(T a, T b);
from the declared type Comparator<Integer>. Otherwise, MyComparator's compare would be treated by the compiler as an additional (overloading), and not overridding, method. And as such, would have no bridge method created for it.
As indicated by this article and this article, the key reason of the Java bridge method is Type Erasure and Polymorphism.
Let's take the class ArrayDeque (source code) as example, it contains a clone() method as bellow, because the class ArrayDeque implements the Cloneable interface so it must override the Object.clone() method.
public class ArrayDeque<E> extends AbstractCollection<E>
implements Deque<E>, Cloneable, Serializable
{
public ArrayDeque<E> clone() {
....
}
}
But the problem is the return type of ArrayDeque.clone() is ArrayDeque<E>, and it did not match to the method signature defined in the parent Object.clone(), and in Object.java the return type is Object instead.
public class Object {
protected native Object clone() throws CloneNotSupportedException;
}
The return type mismatch is a problem for Polymorphism. So in the compiled result file ArrayDeque.class, the Java compiler generated two clone() methods, one match the signature in the source code, the other one match to the signature in the parent class Object.clone().
clone() method returns ArrayDeque<E>, which is generated based on the corresponding source code
clone() method returns Object, which is generated based on Object.clone(). This method is doing nothing but calling the other clone() method. And, this method is tagged as ACC_BRIDGE, which indicates this method is generated by the compiler for the Bridge purpose.