Java: Overriding an abstract method in subclass - java

I really should know this, but for some reason I don't understand the following.
My abstract class contains the following abstract method:
protected abstract RuleDTO createRowToBeCloned(RuleDTO ruleDTO);
I also have another class as follows:
EvaluationRuleDTO extends from RuleDTO
Then in a subclass of my abstract class I have the following implementation which is not allowed due to "must override or implement a supertype method":
protected EvaluationRuleDTO createRowToBeCloned(EvaluationRuleDTO ruleDTO) {
However, the following is allowed:
protected EvaluationRuleDTO createRowToBeCloned(RuleDTO ruleDTO) {
I realize this is probably a basic question but I am a little bemused. How come I can I can return a subclass of RuleDTO in the overridden method, but I can't pass in a subclass?
Thanks

You're breaking the Liskov principle: everything a superclass can do, a subclass must be able to do. The superclass declares a method accepting any kind of RuleDTO. But in your subclass, you only accept instances of EvaluationRuleDTO. What would happen if you did the following?
RuleDTO rule = new EvaluationRuleDTO();
rule.createRowToBeCloned(new RuleDTO());
An EvaluationRuleDTO is a RuleDTO, so it must fulfill the contract defined by RuleDTO.
The method in the subclass may return an instance of EvaluationRuleDTO instead of a RuleDTO, though, because the contract is to return a RuleDTO, and EvaluationRuleDTO is a RuleDTO.

Java allows return type covariance for overrides, so you can specify the return type of an override as a more-derived type. However, Java does not allow parameter type covariance for overrides.
The reason the former is safe is that the object you return will have, at minimum, the functionality of the less-derived type, so a client relying on that fact will still be able to utilize the returned object correctly.
That's not the case for the arguments, though. If it were legal, a user could call the abstract method and pass in a less-derived type (since that's the type declared on the abstract class,) but then your derived override might try to access the argument as a more-derived type (which it isn't) resulting in an error.
In theory, Java could have allowed parameter-type contra-variance, since that is type-safe: if the overriden method only expects a less-derived argument, you can't accidentally utilize a method or field that's not there. Unfortunately, that is not currently available.

It is because when you override a method, you MUST use as parameter type the same type or a more general (wider) type, never a narrower type.
Just think about it. If you could override a method using a narrower type, you would break the polymorphism capability, don't you agree? So, doing this, you would break the Liskov Substitution Principle as JB Nizet said in his answer.

Java 1.5 has co-variant return types which why it is valid
 
The subclass method's return type R2 may be different from superclass
method's return type R1, but R2 should be a subtype of R1. i.e.,
subclass can return type may be a subtype of superclass return type.

In early java that was not the case, but it was changed in Java 5.0.
You cannot have two methods in the same class with signatures that only differ by return type. Until the J2SE 5.0 release, it was also true that a class could not override the return type of the methods it inherits from a superclass. In this tip you will learn about a new feature in J2SE 5.0 that allows covariant return types. What this means is that a method in a subclass may return an object whose type is a subclass of the type returned by the method with the same signature in the superclass. This feature removes the need for excessive type checking and casting.
Source: http://www.java-tips.org/java-se-tips/java.lang/covariant-return-types.html
This implies that the return types of the overriding methods will be subtypes of the return type of the overridden method.

Please see the following code:
class A {
A foo(A a) {
return new A();
}
}
class B extends A {
#Override
// Returning a subtype in the overriding method is fine,
// but using a subtype in the argument list is NOT fine!
B foo(B b) {
b.bar();
return new B();
}
void bar() {
// B specific method!
}
}
Yes ok, B IS AN A, but what happens if someone does:
B b = new B();
b.foo(new A());
A does not have a bar method.. This is why the argument can not be a subtype of the type of argument in the method being overridden.
Returning A or B in the overriding method is fine. The following snippet will compile and run just fine..
class A {
A foo(A a) {
return new B(); // B IS AN A so I can return B!
}
}
class B extends A {
#Override
B foo(A b) {
return new B(); // Overridden method returns A and
// B IS AN A so I can return B!
}
public static void main(String[] args) {
A b = new B();
final A foo = b.foo(new B());
// I can even cast foo to B!
B cast = (B) foo;
}
}

Related

Invoking a Method of the Superclass expecting a Superclass argument on a Subclass instance by passing the an instance the of the Subclass

Can anyone please explain the output of the following code, and what's the Java principle involved here?
class Mammal {
void eat(Mammal m) {
System.out.println("Mammal eats food");
}
}
class Cattle extends Mammal{
void eat(Cattle c){
System.out.println("Cattle eats hay");
}
}
class Horse extends Cattle {
void eat(Horse h) {
System.out.println("Horse eats hay");
}
}
public class Test {
public static void main(String[] args) {
Mammal h = new Horse();
Cattle c = new Horse();
c.eat(h);
}
}
It produces the following output:
Mammal eats food
I want to know how we are coming at the above result.
Overloading vs Overriding
That's not a valid method overriding, because all the method signatures (method name + parameters) are different:
void eat(Mammal m)
void eat(Cattle c)
void eat(Horse h)
That is called method overloading (see) and class Horse will have 3 distinct methods, not one. I.e. its own overloaded version of eat() and 2 inherited versions.
The compiler will map the method call c.eat(h) to the most specific method, which is eat(Mammal m), because the variable h is of type Mammal.
In order to invoke the method with a signature eat(Horse h) you need to coerce h into the type Horse. Note, that such conversion would be considered a so-called narrowing conversion, and it will never happen automatically because there's no guarantee that such type cast will succeed, so the compiler will not do it for you.
Comment out the method void eat(Mammal m) and you will see the compilation error - compilers don't perform narrowing conversions, it can only help you with widening conversions because they are guaranteed to succeed and therefore safe.
That what would happen if you'll make type casting manually:
Coercing h into the type Horse:
c.eat((Horse) h);
Output:
Cattle eats hay // because `c` is of type `Cattle` method `eat(Cattle c)` gets invoked
Because variable c is of type Cattle it's only aware of the method eat(Cattle c) and not eat(Horse h). And behind the scenes, the compiler will widen the h to the type Cattle.
Coercing both c and h into the type Horse:
((Horse) c).eat((Horse) h);
Output:
Horse eats hay // now `eat(Horse h)` is the most specific method
Rules of Overriding
The rules of method overriding conform to the Liskov substitution principle.
Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.
The child class should declare its behavior in such a way so that it can be used everywhere where its parent is expected:
Method signatures must match exactly. I.e. method names should be the same as well as the types of parameters. And parameters need to be declared in the same order. It is important to note that if method signatures differ (for instance like in the code snippet provided in the question, name of one of the methods was misspelled) the compiler will have no clue that these methods are connected anyhow. I.e. it no longer be considered a case of overriding, methods will be considered to be distinct, and all other requirements listed below will not be applicable. That's why it's highly advisable to add the #Override annotation to the overridden method. With it, the compiler will give a clear feedback when it fails to find a matching method in the parent classes and interfaces, if you've misspelled the name, or declared parameters in the wrong order. Your IDE will add this annotation for you if you ask it to generate a template (shortcut in IntelliJ CTRL + O).
The access modifier of an overridden method can be the same or wider, but it can not be more strict. I.e. protected method in the parent class can be overridden as public or can remain protected, we can not make it private.
Return type of an overridden method should be precisely the same in case primitive type. But if a parent method declares to return a reference type, its subtype can be returned. I.e. if parent returns Number an overridden method can provide Integer as a return type.
If parent method declares to throw any checked exceptions then the overridden method is allowed to declare the same exceptions or their subtypes, or can be implemented as safe (i.e. not throwing exceptions at all). It's not allowed to make the overridden method less safe than the method declared by the parent, i.e. to throw checked exceptions not declared by the parent method. Note, that there are no restrictions regarding runtime exceptions (unchecked), overridden methods are free to declare them even if they are not specified by the parent method.
This would be a valid example of method overriding:
static class Mammal{
void eat(Mammal m){
System.out.println("Mammal eats food");
}
}
public class Cattle extends Mammal{
#Override
void eat(Mammal c) {
System.out.println("Cattle eats hay");
}
}
public class Horse extends Cattle{
#Override
public void eat(Mammal h) throws RuntimeException {
System.out.println("Horse eats hay");
}
}
main()
public static void main(String[] args) {
Mammal h = new Horse();
Cattle c = new Horse();
c.eat(h);
}
Output:
Horse eats hay
In your example, method overloading occurs(same method name but different parameter type passed).
When you're calling c.eat(h), the compiler will know that you want to use the void eat(Mammal m) method since your h reference has the type Mammal.
If you would change the object reference to Horse or Cattle like so:
Horse h = new Horse();
The output will be:
Cattle eats hay
This happens because the compiler will use the most specific method, in this case void eat(Cattle c), based on the object reference type Horse.
You may also be interested in method overriding which uses runtime polymorphism.

How to access base class method after downcasting?

This is a Java Generics program that implements a custom interface with set(T t), get() and print(T t) methods.
The class that I use is called Animal. It takes a T argument (String in this case) and gives the animal a name.
My problem is that I can't access any of the Animal class methods in my print function.
Animal<String> a1 = new Animal();
a1.set("Mickey");
public void print(Object o) {
Animal oAnimal = (Animal) o; //Downcasting from Object to Animal.
System.out.println(o.get()); //not accessible, and I don't know how to make it accessible.
//I can only access the methods from Object, not my custom class called Animal.
}
You should use
oAnimal.get()
since that's the instance of Animal.
Remember you are not modifying o, so it will remain as an Object.
The problem is that you're still trying to call the method on o, which is still of type Object (in terms of the compile-time type of the variable, which is all the compiler cares about).
If you call the method on oAnimal instead, it will be fine:
System.out.println(oAnimal.get());
(You can't return the result of System.out.println though, as it's a void method. Nor can you specify a return value for your void method.)
Note that this has nothing to do with generics, really. The code in your question can be demonstrated simply using String:
Object o = "foo";
String text = (String) o;
System.out.println(o.length()); // Error; Object doesn't have a length() method
System.out.println(text.length()); // Prints 3
Your (edited) question does demonstrate a use of generics, but your cast to Animal is a cast to a raw type, so it's simpler just to leave generics out of the equation - the reason for the compilation failure has nothing to do with Animal being generic.

Different return value types in implementation of generic methods

Today I stumbled upon some working Java code I wouldn't even have expected to compile. Reduced to its bare minimum, it looks like this:
import java.util.List;
interface A {
<T> List<String> foo();
}
interface B {
<T> List<Integer> foo();
}
class C implements A, B {
#Override
public List<?> foo()
{
return null;
}
}
At first sight, the type parameter <T> of the foo methods in A and B look unnecessary since T is not used anywhere else. Anyway, I found out that this is playing a crucial role in allowing the conflicting return value types to coexist in the same implementation: if one or both of the <T>s are left out, the code doesn't compile. Here the non-working version:
import java.util.List;
interface A {
List<String> foo();
}
interface B {
List<Integer> foo();
}
class C implements A, B {
#Override
public List<?> foo()
{
return null;
}
}
I don't need to fix the code snippets above as those are just examples I made up to explain my point. I'm only curious to understand why the compiler is behaving differently with them. Can someone explain what rules exactly are making the difference here?
While the first example does compile, it will give an unchecked conversion warning:
// Type safety: The return type List<?> for foo() from the type C needs
// unchecked conversion to conform to List<String>
public List<?> foo()
{
return null;
}
What's happening here is that by declaring type parameters, A.foo() and B.foo() are generic methods. Then, the overriding C.foo() omits that type parameter. This is similar to using a raw type, essentially "opting out" of generic type checking for that method signature. That causes the compiler to use the inherited methods' erasures instead: List<String> foo() and List<Integer> foo() both become List foo(), which can therefore be implemented by C.foo().
You can see that by keeping the type parameter in the C.foo() declaration, there will be the expected compiler error instead:
// The return type is incompatible with A.foo()
public <T> List<?> foo()
{
return null;
}
Likewise, if either of the interface methods don't declare a type parameter, then omitting a type parameter from the override fails to "opt out" of generic type checking for that method, and the return type List<?> remains incompatible.
This behavior is covered in JLS §8.4.2:
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.
Angelika Langer's generics FAQ expands on this behavior in her section Can a non-generic method override a generic one?:
Now, let us explore an example where non-generic subtype methods
override generic supertype methods. Non-generic subtype methods are
considered overriding versions of the generic supertype methods if the
signatures' erasures are identical.
Example (of non-generic subtype methods overriding generic supertype
methods):
class Super {
public <T> void set( T arg) { ... }
public <T> T get() { ... }
}
class Sub extends Super {
public void set( Object arg) { ... } // overrides
public Object get() { ... } // overrides with unchecked warning
}
warning: get() in Sub overrides <T>get() in Super;
return type requires unchecked conversion
found : Object
required: T
public Object get() {
Here the subtype methods have signatures, namely set(Object) and get()
, that are identical to the erasures of the supertype methods. These
type-erased signatures are considered override-equivalent.
There is one blemish in the case of the get method: we receive an
unchecked warning because the return types are not really compatible.
The return type of the subtype method get is Object , the return type
of the supertype method get is an unbounded type parameter. The
subtype method's return type is neither identical to the supertype
method's return type nor is it a subtype thereof; in both situations
the compiler would happily accept the return types as compatible.
Instead, the subtype method's return type Object is convertible to the
supertype method's return type by means of an unchecked conversion.
An unchecked warning indicates that a type check is necessary that
neither the compiler nor the virtual machine can perform. In other
words, the unchecked operation is not type-safe. In case of the
convertible return types someone would have to make sure that the
subtype method's return value is type-compatible to the supertype
method's return type, but nobody except the programmer can ensure
this.

Override a method in Java generically

If I have a base class like this that I can't change:
public abstract class A {
public abstract Object get(int i);
}
and I try to extend it with a class B like this:
public class B extends A{
#Override
public String get(int i){
//impl
return "SomeString";
}
}
everything is OK. But my attempt to make it more generic fails if I try:
public class C extends A{
#Override
public <T extends Object> T get(int i){
//impl
return (T)someObj;
}
}
I can't think of any reason why this should be disallowed. In my understanding, the generic type T is bound to an Object—which is the requested return type of A. If I can put String or AnyObject as my return type inside B, why am I not allowed to put <T extends Object> T inside my C class?
Another strange behavior, from my point of view, is that an additional method like this:
public class D extends A{
#Override
public Object get(int i){
//impl
}
public <T extends Object> T get(int i){
//impl
}
}
is also not allowed, with the hint of a DuplicateMethod provided. This one, at least, confuses me, and I think Java should make a decision: if it is the same return type, why not allow overriding; and if it is not, why shouldn't I be able to add this method? To tell me it's the same, but not allow it to be overridden, is very weird, based on common sense.
JLS # 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.
As per above rule as your parent do not have an erasure and your child has one so it is not a valid overriding.
JLS#8.4.8.3. Requirements in Overriding and Hiding
Example 8.4.8.3-4. Erasure Affects Overriding
A class cannot have two member methods with the same name and type erasure:
class C<T> {
T id (T x) {...}
}
class D extends C<String> {
Object id(Object x) {...}
}
This is illegal since D.id(Object) is a member of D, C.id(String) is declared in a supertype of D, and:
The two methods have the same name, id
C.id(String) is accessible to D
The signature of D.id(Object) is not a subsignature of that of
C.id(String)
The two methods have the same erasure
Two different methods of a class may not override methods with the same erasure:
class C<T> {
T id(T x) {...}
}
interface I<T> {
T id(T x);
}
class D extends C<String> implements I<Integer> {
public String id(String x) {...}
public Integer id(Integer x) {...}
}
This is also illegal, since D.id(String) is a member of D, D.id(Integer) is declared in D, and:
The two methods have the same name, id
D.id(Integer) is accessible to D
The two methods have different signatures (and neither is a
subsignature of the other)
D.id(String) overrides C.id(String) and D.id(Integer)
overrides I.id(Integer) yet the two overridden methods have the same
erasure
Also It gives example of a case where it is allowed from super to child
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.
Consider the example:
class CollectionConverter {
List toList(Collection c) {...}
}
class Overrider extends CollectionConverter {
List toList(Collection c) {...}
}
Now, assume this code was written before the introduction of generics, and now the author of class CollectionConverter decides to generify the code, thus:
class CollectionConverter {
<T> List<T> toList(Collection<T> c) {...}
}
Without special dispensation, Overrider.toList would no longer override CollectionConverter.toList. Instead, the code would be illegal. This would significantly inhibit the use of generics, since library writers would hesitate to migrate existing code.
Well, for the first part, the answer would be that Java does not allow non-generic methods to be overridden by generic methods, even if the erasure is the same. It means that it wouldn't work even if you would just have the overriding method as:
public <T extends Object> Object get(int i)
I don't know why Java poses this limitation (gave it some thought), I just think it has to do with special cases implemented for sub-classing generic types.
Your second definition would essentially translate to:
public class D extends A{
#Override
public Object get(int i){
//impl
}
public Object get(int i){
//impl
}
}
which is obviously a problem.
From the JLS section 8.4.8.3 Overriding and hiding:
It is a compile-time error if a type declaration T has a member method m1 and there exists a method m2 declared in T or a supertype of T such that all of the following conditions hold:
m1 and m2 have the same name.
m2 is accessible from T.
The signature of m1 is not a subsignature (§8.4.2) of the signature of m2.
The signature of m1 or some method m1 overrides (directly or indirectly) has the same erasure as the signature of m2 or some method m2 overrides (directly or indirectly).
1 and 2 holds.
3 holds too because (quote from JLS section 8.4.2):
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.
And you are having the other way: a method with generic type overriding one without generic.
4 holds too because the erased signatures are the same: public Object get(int i)
Imagine the following invocation.
A a = new C();
a.get(0);
In effect you are calling a generic method, yet you're not passing in any type arguments. As things stand, this is not much of a problem. Those type arguments disappear during code generation anyways. Yet reification has never been taken off the table and the stewards of Java the language have tried and continue to try and keep that door open. If type arguments were reified, your invocation would not provide any to a method that requires one.
#RafaelT's original code results in this compilation error...
C.java:3: error: C is not abstract and does not override abstract method get(int) in A
public class C extends A {
^
C.java:5: error: name clash: <T>get(int) in C and get(int) in A have the same erasure, yet neither overrides the other
public <T extends Object> T get ( int i ){
^
where T is a type-variable:
T extends Object declared in method <T>get(int)
The simplest, most straightfoward solution to get #RafaelT's C subclass to compile successfully, is...
public abstract class A {
public abstract Object get(int i);
}
public class C<T> extends A {
#Override
public T get(int i){
//impl
return (T)someObj;
}
}
Although I'm sure other people meant well with their answers. Nevertheless, a few of the answers seem to have majorly misinterpreted the JLS.
The above change to only the class declaration, results in a successful compilation. That fact alone, means that #RafaelT's original signatures are indeed perfectly fine as subsignatures — contrary to what others have suggested.
I'm not going to make the same mistake that others who answered seem to have made, and try to pretend I fully grok the JLS generics documentation. I confess that I haven't figured out with 100% certainty, the root cause of the OP's original compilation failure.
But I suspect it has something to do with an unfortunate combination of the OP's use of Object as the return type on top of the typical confusing and quirky subtleties of Java's generics.
You should read up on erasure.
In your example:
public class D extends A{
#Override
public Object get(int i){
//impl
}
public <T extends Object> T get(int i){
//impl
}
}
The compiler generated byte code for your generic method will be identical to your non-generic method; that is, T will be replaced with the upper bound, that being Object. That's why you're getting the DuplicateMethod warning in your IDE.
Declaring method as <T extends Object> T get(int i) makes no sense without declaring T somewhere else - in the method's arguments or in a field of the enclosing class. In the latter case, just parameterize the whole class with the type T.
There's a conceptual problem. Suppose C#get() overrides A#get()
A a = new C();
Object obj = a.get(); // actually calling C#get()
but C#get() requires a T - what should T be? There is no way to determine.
You can protest that T is not required due to erasure. That is correct today. However erasure was considered a "temporary" workaround. The type system in most part does not assume erasure; it is actually carefully designed so that it can be made fully "reifiable", i.e. without erasure, in future version of java without breaking existing code.

Java calling subclass method when trying to use parent class method

If I have two classes, A and B,
public class A {
public int test() {
return 1;
}
}
public class B extends A{
public int test() {
return 2;
}
}
If I do: A a1 = new B(), then a1.test() returns 2 instead of 1 as desired.
Is this just a quirk of Java, or is there some reason for this behavior?
This is called polymorphism. At runtime the correct method will be called according to the "real" type of a1, which is B in this case.
As wikipedia puts it nicely:
The primary usage of polymorphism in industry (object-oriented
programming theory) is the ability of objects belonging to different
types to respond to method, field, or property calls of the same name,
each one according to an appropriate type-specific behavior. The
programmer (and the program) does not have to know the exact type of
the object in advance, and so the exact behavior is determined at
run-time (this is called late binding or dynamic binding).
No, that is correct (it is due to polymorphism). All method calls operate on object, not reference type.
Here your object is of type B, so test method of class B will be called.
This is polymorphism and more specifically in Java overriding. If you want to invoke Class A's test method from Class B then you need to use super to invoke the super classes method. e.g:
public class B extends A{
public int test() {
return super.test();
}
This is intended behavior. The method test() in class B is overriding the method test() of class A.
For
A a1 = new B();
a1 is pointing towards the object of B which is the real type at run-time. Hence value is printed from Object B.
A obj = new A();
obj.test()
will return 1
A obj = new B();
obj.test()
will return 2
B obj = new B();
obj.test()
will return 2
As stated in other answers this is how polymorphism works.
This post may make things a bit clearer
Java uses dynamic binding (or late binding), so the method of B is called, not A. This is the opposite of static binding. There is a nice example here.
You declare your object as A but your instance is B. So the method which will be called is from class B. B extends A(we can say that A is parent for B) if you will comment method test in B and then recall this method, in this case the method invoked will be test from A class and will return 1.

Categories

Resources