Implementing abstract methods in a subclass in Java - java

I've made my code as generic as possible to try and help people in the future. My abstract class has a method of the type class and and an input of the type class. In the class that extends the abstract, I try to implement that method to no avail. What am I doing wrong?
public abstract class A {
public abstract A method1(A arg);
}
public class B extends A {
#Override
public B method1(B arg) { "...insert code here"} // Error: The method method1(B) must override or implement a supertype method
}

To achieve what you want : associating the type of the argument to the declared class, you could use generics.
abstract class :
public abstract class A <T extends A<T>> {
public abstract T method1(T arg);
}
concrete class :
public class B extends A<B> {
#Override
public B method1(B arg) {
...
return ...
}
}

Think about the Liskov substitution principle: in order to be indistinguishable from a superclass, the subclass must accept all of the same parameters that the superclass would; and return something that the superclass might.
Another way to put this is that the subclass method can:
Return a more specific type that the superclass method (since this is a value that the superclass might return); for example, if the superclass returns Object, the subclass can return a String, because all Strings are Objects.
This is called a covariant return type, and is permitted in Java. Subclasses can not only return more specific return types, they can also throw more specific checked exceptions than the superclass; but they can also not declare that they throw the checked exceptions thrown by the superclass method.
Accept a more general type than the superclass method (since this allows the subclass to accept all parameters that the superclass would).
This would be called a contravariant parameter type; but it is not permitted in Java. The reason is to do with the way that overloads are selected in Java: unfortunately, the method signatures (which includes the parameter types, but not the return type) have to be identical.
The relevant section of the language spec is JLS Sec 8.4.8.3.
Your problem is making the parameter type B: this is more specific than A, so an instance of B is not substitutable for an instance of A, because A.method1 accepts a parameter A, whereas B.method1 does not.
Make B.method1 take a parameter of type A.

The type and no of parameter should remain. The return type, if it is of primitive type, should remain same, but if it is of reference type then it can be of subclass type.
In your case change this public B method1(B arg) { "...insert code here"} to public B method1(A arg) { "...insert code here"}

Every thing you have written is right except overidden method argument type,you can't change the signature of superclass abstract method while overiding in subclass.
public abstract class A {
public abstract A method1(A arg);
}
public class B extends A {
#Override
public B method1(A arg) { "...insert code here"} // Error: The method method1(B) must override or implement a supertype method
}

The contract of A.method1 means that every object that is an A must have a method1 which can take any A object.
In the case of B.method1, it can take a B object, but it cannot take another A.

Related

Override a method in Java by providing a Subtype as a Parameter

I want to override a method in Java by passing a concrete subtype of the parameter type that is specified in the super class. See the following example. Is there a way to get this working in Java?
interface A {
<T> T f(V<T> v);
}
interface V<T> {
T v();
}
class B implements A {
#Override // Here it gives error: Method does not override method from its superclass
public <T> T f(V1<T> v) {
return v.v1();
}
}
interface V1<T> extends V<T> {
T v1();
}
I have also tried this version for A but doesn't work:
interface A {
<T, U extends V<T>> T f(U v);
}
You can get close to what you want by taking multiple generic arguments at the interface level and none at the function level.
interface A<T, S extends V<T>> {
public T f(S v);
}
class B<T> extends A<T, V1<T>> {
#Override // Here it gives error: Method does not override method from its superclass
public T f(V1<T> v) {
return v.v1();
}
}
Note that this isn't quite the guarantee you were looking for, as someone could come along and write some class C extends A<Integer, V1<Integer>> that only works for integers and no other type. But to do that, you'd need something called higher-kinded polymorphism which is not supported in Java.
The definition of the method f in the subclass violates the Liskov substitution principle, which says that should be able to use a child instance whenever the parent is expected.
public <T> T f(V1<T> v)
Method f in the parent class expects V<T> as an argument. And V is a super type of V1 which means that the method declared by the child expects a more narrow type. I.e. the instance of a child is not able to handle all subtypes of V and hence can't substitute its parent.
And from the practical point of view, it's clearly not a valid method overriding (at least in Java). Method signatures should match exactly, otherwise it's a method overloading, which is the case here.
And you're getting a compilation error because you've applied #Override annotation and the compiler fails to find a method with matching signature in the parent class, and also because the contract defined by the interface A hasn't been't implemented.
The only exception related to the overriding of generic methods that we have is the possibility to override a method that expects a generic parameter like Collection<T> to be overridden by a non generified method that expects a Collection of row type (it was done in order to facilitate transition to generics when they were introduced in the language).

EnumSet as a parameter in generic Interface

I've a use case :
inteface A{
get(EnumSet<?> fetchModes);
}
class B implements A{
//Here FetchMode is an enum
get(EnumSet<FetchMode> fetchMode){
//Some logic here
}
}
But it's throwing compile time error :
Method get of class B has the same erasure as get(EnumSet fetchMode) of type A but doesn't override it.
I had read that Enums cannot be generic but is there any way to implement this usecase ?
(Basically want the EnumSet to be generic and different implementations can pass different Enums)
A method can override another if the argument types match exactly, but yours doesn't. Eventhough EnumSet<FetchMode> is a subtype of EnumSet<?>, they are not exactly the same. You are not overriding the super class method get(EnumSet<?> fetchModes); in your subclass, rather you are overloading it with a different parameter type. Both of these has the same signature due to erasure when you inspect or decompile the bytecode which is get(EnumSet fetchModes) and your compiler starts complaining.
This is covered in JLS §8.4.8.1:
A class cannot have two member methods with the same name and type
erasure
A naive attempt at fixing the problem is to change the parameter type such that it is compatible with that of the super class, overriding the method properly in your sub class.
#Override
public void get(EnumSet<?> fetchModes) {
}
Though this fixes the compiler error after a fashion, it is still not elegant since it allows your EnumSet to store any Object. But ideally you may want it to store only some subtype of Enum. This idiom supports that.
What you have to do is declare a generic interface with bounded type parameter and then implement it by overriding the method properly as shown below.
public interface A<E extends Enum<E>> {
void get(EnumSet<E> fetchModes);
}
public class B implements A<FetchMode> {
#Override
public void get(EnumSet<FetchMode> fetchModes) {
}
}
try this you have to make the generic type extends Enum:
public class B implements A<FetchMode> {
//Here FetchMode is an enum
public void get(EnumSet<FetchMode> fetchMode){
//Some logic here
}
}
}
interface A<T extends Enum<T>> {
void get(EnumSet<T> fetchModes);
}

What does it mean "return a type that is compatible"?

I am newby to Java, so I am reading Java Head First. I have seen that when you have an abstract class with abstract methods, you should override these abstract methods in a concrete class which means "create a non-abstract method in your class with the same method signature (name and arguments) and a return type that is compatible with the declared return type of the abstract method."
I can clearly understand the first part about having the same signature (name and arguments), but I would like to have a clear explanation about a return type that is compatible with the declared return type of the abstract method.
What exactly means a compatible type? Could somebody please provide an example? Is it like the return type should be the class or a subclass of the return type defined in the abstract method?
The type returned by the overriding method must be the same, or must be a subclass or subinterface of the type returned in the base method.
In short: it must respect the contract of the base method. If the base method says: "I return a Fruit", then the overriding method can say "I return a Fruit", but it can also say "I return a Banana".
That's fine because a Banana is a Fruit. Anyone calling the method and getting a Banana is happy: a fruit was expected, and a fruit was received.
Returning a Car isn't correct though, because when you ask for a Fruit, getting a Car is not acceptable.
The technical term for this is a covariant return type. Note that this rule is true even if the base class/method is not abstract.
If your return type is A, then you can also return objects of any class B derived from A. All of these are compatible types.
Your return type can also be an interface. In this case, you can return any object that implements this interface.
Consider the example below. The return type of the abstract function model() is int.
abstract class Bike{
abstract short model();
}
When you redefine this method in a concrete class which extends the abstract class Bike. The concrete class should have a method model() with the same method signature and a compatible return type.
One return type is compatible with another, if it doesn't lead to loss
of precision.
One return type compatible with short is int.
class Honda4 extends Bike{
int model()
//long is compatible with int since there is no loss of precision
{
return 1234;
}
public static void main(String args[]){
Bike obj = new Honda4();
System.out.println(obj.model());
}
}
Can you name a return type which is not compatible with int ?
short. It may lead to loss of precision.
This means the your implementation of the abstract method must return the same or derivated class of the object defined in the Abstract class
example:
you have an abstractClass with abstract method
abstract class AbstractTest{
abstract Date getInitialTime();
}
then you have a test class.
class Test extends AbstractTest{
...
Date getInitialTime(){
return new Date();
}
}
you override the getInitialTime method and the return of that method must be an object of the class date or of a superclass of that
if you return something else, then you are breaking the contract between what the method of your class returns and what the method os the parent class returns...

Can overridden methods differ in return type?

Can overridden methods have different return types?
Java supports* covariant return types for overridden methods. This means an overridden method may have a more specific return type. That is, as long as the new return type is assignable to the return type of the method you are overriding, it's allowed.
For example:
class ShapeBuilder {
...
public Shape build() {
....
}
class CircleBuilder extends ShapeBuilder{
...
#Override
public Circle build() {
....
}
This is specified in section 8.4.5 of the Java Language Specification:
Return types may vary among methods that override each other if the return types are reference types. The notion of return-type-substitutability supports covariant returns, that is, the specialization of the return type to a subtype.
A method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return type R2, if and only if the following conditions hold:
If R1 is void then R2 is void.
If R1 is a primitive type, then R2 is identical to R1.
If R1 is a reference type then:
R1 is either a subtype of R2 or R1 can be converted to a subtype of R2 by unchecked conversion (§5.1.9), or
R1 = |R2|
("|R2|" refers to the erasure of R2, as defined in §4.6 of the JLS.)
* Prior to Java 5, Java had invariant return types, which meant the return type of a method override needed to exactly match the method being overridden.
Yes it may differ but there are some limitations.
Before Java 5.0, when you override a method, both parameters and return type must match exactly. Java 5.0 it introduces a new facility called covariant return type. You can override a method with the same signature but return a subclass of the object returned.
In another words, a method in a subclass can return an object whose type is a subclass of the type returned by the method with the same signature in the superclass.
Yes, if they return a subtype. Here's an example:
package com.sandbox;
public class Sandbox {
private static class Parent {
public ParentReturnType run() {
return new ParentReturnType();
}
}
private static class ParentReturnType {
}
private static class Child extends Parent {
#Override
public ChildReturnType run() {
return new ChildReturnType();
}
}
private static class ChildReturnType extends ParentReturnType {
}
}
This code compiles and runs.
Broadly speaking yes return type of overriding method can be different. But it's not straight forward as there are some cases involved in this.
Case 1: If the return type is a primitive data type or void.
Output: If the return type is void or primitive then the data type of parent class method and overriding method should be the same.
e.g. if the return type is int, float, string then it should be same
Case 2: If the return type is derived data type:
Output: If the return type of the parent class method is derived type then the return type of the overriding method is the same derived data type of subclass to the derived data type.
e.g. Suppose I have a class A, B is a subclass to A, C is a subclass to B and D is a subclass to C; then if the super class is returning type A then the overriding method in subclass can return either A, or B/C/D type i.e. its sub types. This is also called as covariance.
yes It is possible.. returns type can be different only if parent class method return type is
a super type of child class method return type..
means
class ParentClass {
public Circle() method1() {
return new Cirlce();
}
}
class ChildClass extends ParentClass {
public Square method1() {
return new Square();
}
}
Class Circle {
}
class Square extends Circle {
}
If this is the then different return type can be allowed...
The other answers are all correct, but surprisingly all leaving out the theoretical aspect here: return types can be different, but they can only restrict the type used in the super class because of the Liskov Substitution Principle.
It is super simple: when you have "client" code that calls some method:
int foo = someBar.bar();
then the above has to work (and return something that is an int no matter which implementation of bar() is invoked).
Meaning: if there is a Bar subclass that overrides bar() then you still have to return something that doesn't break "caller code".
In other words: assume that the base bar() is supposed to return int. Then a subclass could return short - but not long because callers will be fine dealing with a short value, but not a long!
well, the answer is yes... AND NO.
depends on the question. everybody here answered regarding Java >= 5, and some mentioned that Java < 5 does not feature covariant return types.
actually, the Java language spec >= 5 supports it, but the Java runtime does not. in particular, the JVM was not updated to support covariant return types.
in what was seen then as a "clever" move but ended up being one of the worst design decisions in Java's history, Java 5 implemented a bunch of new language features without modifying the JVM or the classfile spec at all. instead all features were implemented with trickery in javac: the compiler generates/uses plain classes for nested/inner classes, type erasure and casts for generics, synthetic accessors for nested/inner class private "friendship", synthetic instance fields for outer 'this' pointers, synthetic static fields for '.class' literals, etc, etc.
and covariant return types is yet more syntactic sugar added by javac.
for example, when compiling this:
class Base {
Object get() { return null; }
}
class Derived extends Base {
#Override
#SomeAnnotation
Integer get() { return null; }
}
javac will output two get methods in the Derived class:
Integer Integer:Derived:get() { return null; }
synthetic bridge Object Object:Derived:get() { return Integer:Derived:get(); }
the generated bridge method (marked synthetic and bridge in bytecode) is what actually overrides Object:Base:get() because, to the JVM, methods with different return types are completely independent and cannot override each other. to provide the expected behavior, the bridge simply calls your "real" method. in the example above, javac will annotate both bridge and real methods in Derived with #SomeAnnotation.
note that you cannot hand-code this solution in Java < 5, because bridge and real methods only differ in return type and thus they cannot coexist in a Java program. but in the JVM world, method return types are part of the method signature (just like their arguments) and so the two methods named the same and taking the same arguments are nonetheless seen as completely independent by the JVM due to their differing return types, and can coexist.
(BTW, the types of fields are similarly part of the field signature in bytecode, so it is legal to have several fields of different types but named the same within a single bytecode class.)
so to answer your question fully: the JVM does not support covariant return types, but javac >= 5 fakes it at compile time with a coating of sweet syntactic sugar.
The return type must be the same as, or a subtype of, the return type declared
in the original overridden method in the superclass.
Overriding and Return Types, and Covariant Returns the subclass must define a method that matches the inherited version exactly. Or, as of Java 5, you're allowed to change the return type in the sample code
class Alpha {
Alpha doStuff(char c) {
return new Alpha();
}
}
class Beta extends Alpha {
Beta doStuff(char c) { // legal override in Java 1.5
return new Beta();
}
} } As of Java 5, this code will compile. If you were to attempt to compile this code with a 1.4 compiler will say attempting to use incompatible return type – sandeep1987 1 min ago
class Phone {
public Phone getMsg() {
System.out.println("phone...");
return new Phone();
}
}
class Samsung extends Phone{
#Override
public Samsung getMsg() {
System.out.println("samsung...");
return new Samsung();
}
public static void main(String[] args) {
Phone p=new Samsung();
p.getMsg();
}
}
YES it can be possible
class base {
base show(){
System.out.println("base class");
return new base();
}
}
class sub extends base{
sub show(){
System.out.println("sub class");
return new sub();
}
}
class inheritance{
public static void main(String []args) {
sub obj=new sub();
obj.show();
}
}
Yes. It is possible for overridden methods to have different return type .
But the limitations are that the overridden method must have a return type that is more specific type of the return type of the actual method.
All the answers have given examples of the overridden method to have a return type which is a subclass of the return type of the actual method.
For example :
public class Foo{
//method which returns Foo
Foo getFoo(){
//your code
}
}
public class subFoo extends Foo{
//Overridden method which returns subclass of Foo
#Override
subFoo getFoo(){
//your code
}
}
But this is not only limited to subclass.Even classes that implement an interface are a specific type of the interface and thus can be a return type where the interface is expected.
For example :
public interface Foo{
//method which returns Foo
Foo getFoo();
}
public class Fizz implements Foo{
//Overridden method which returns Fizz(as it implements Foo)
#Override
Fizz getFoo(){
//your code
}
}

How to use an object of type class from an generic class as a parameter? - generics and reflection combined

I have two classes:
public abstract class MyAbstractSuperClass<A, B> {
public MyAbstractSuperClass(Class<A> a, Class<B> b) {
...
}
...
}
public class MyClass<A> extends MyAbstractSuperClass<A, MyOtherClass<A>> {
public MyClass(Class<A> a) {
super(a, MyOtherClass.class));
...
}
...
}
Now you see, the subclass has to call the superclass's constructor. At that line I get the following error:
The constructor MySuperClass<A, MyOtherClass<A>>(Class<A>, Class<MyOtherClass>) is undefined
So how do I get an object of type Class<MyOtherClass<A>>?
And how do I do it in the super constructor call, where I can't execute much?
Thanks in advance.
The constructor is expecting a Class<MyOtherClass<A>>, not a Class<MyOtherClass>. The only way I can think to satisfy the compiler is through an ugly series of casts:
#SuppressWarnings("unchecked")
public MyClass(Class<A> a) {
super(a, (Class<MyOtherClass<A>>)(Class<?>)MyOtherClass.class);
}
It is type safe as seen through inspection, since the class literal for the raw type MyOtherClass is the same as for the parameterized MyOtherClass<A>. But that doesn't stop an unchecked warning from being generated, which can be suppressed as above, or simply ignored.
Remove the type parameter of MyOtherClass in the MyClass definition. You're apparently not interested in this anywhere in MyClass' body.
public class MyClass<A> extends MyAbstractSuperClass<A, MyOtherClass> {
public MyClass(Class<A> a) {
super(a, MyOtherClass.class);
}
}
Add a #SuppressWarnings("rawtypes") if the warning bothers you.
You must add a second argument to the MyClass constructor:
public MyClass(Class<A> a, Class<MyOtherClass<A>> bClass) {
super(a, bclass));
}
#Bert F: This does "pass the buck" in some sense, but it passes the buck to someone who can actually provide a class literal of the appropriate type. The caller knows the actual value of the type variable A, and so can provide a class literal of the correct type. Due to erasure, MyClass can't do that.

Categories

Resources