Hi I am facing a design problem which I think it should be quite common:
public abstract class Parent
{
...
public boolean itsOk()
{
return true;
}
public void execute()
{
if (itsOk()){
System.out.println("done");
}
}
}
I need to be able to override itsOK() function in any subclass inherited from 'Parent' even if arguments are different.
public class Example extends Parent
{
public boolean itsOK(int a)
{
if (a==1) return true;
else return false;
}
}
Then when I call execute, I want the subclass' itsOk() method to be invoked.
public static void main(String[] args) {
Example e=new Example();
e.execute();
}
This works ok if the subclass' itsOk() method has no arguments (like the 'Parent's method), so it's an overriding case, but how can I make it when arguments are different?
Call super.itsOk(); in your subclass' itsOk method.
That is, I'm assuming what you mean is you want to have an overload of itsOk defined in your subclass which does something new but also invokes the parent class' default implementation of itsOk.
As an aside, note the terminology: you're not overriding: to do that, the itsOk in your subclass must have the same method signature as in the parent class. Instead you're overloading creating a brand new method that just happens to have the same name.
You can use generics:
public abstract class Parent
{
...
public <T> boolean itsOk(T t)
{
return true;
}
public void execute()
{
if (itsOk()){
System.out.println("done");
}
}
}
public class Example extends Parent<Integer>
{
public boolean itsOK(Integer a)
{
if (a==1) return true;
else return false;
}
}
In such a case I would rather try to have the same method signature in the parent and the child class, ie. a real overwriting and not an overloading. Then, your parameter a could be a member of the class Example which would avoid the need for a parameter. Of course it strongly depends on the rest of the code.
The itsOk(int a) method in class Example is not overriding the itsOk() method in class Parent - it is an entirely separate method that doesn't have anything to do with the method in class Parent.
With what value of a do you want itsOk(int a) in Example to be called when you call itsOk() in Parent?
You could ofcourse add an itsOk(int a) method to class Parent; then the version in Example would be overriding that version, and in the execute() method you could call it:
public abstract class Parent {
public boolean itsOk() {
return true;
}
public abstract boolean itsOk(int a);
public void execute() {
if (itsOk(0)) {
System.out.println("done");
}
}
}
Without declaring an itsOk(int a) method in class Parent, you cannot call that method on a Parent object (or on an Example object, if the type of the variable referring to the object is Parent).
I don't think this is a common design problem.
When arguments are different it no longer is a case of Overriding. It is called Overloading which basically means that you have two distinct methods to call.
Related
I want to be able to determine if a base class method has been overridden by a subclass specifically because expensive setup is needed before invoking it and most subclasses in our system do not override it. Can it be tested by using reflection provided method handles? Or is there some other way to test if a class method is overridden?
e.g.
class BaseClass {
void aMethod() { // don nothing }
protected boolean aMethodHasBeenOverridden() {
return( // determine if aMethod has been overridden by a subclass);
}
}
You can do it with reflection by examining the declaring class of your method:
class Base {
public void foo() {}
public void bar() {}
}
class Derived extends Base {
#Override
public void bar() {}
}
...
Method mfoo = Derived.class.getMethod("foo");
boolean ovrFoo = mfoo.getDeclaringClass() != Base.class;
Method mbar = Derived.class.getMethod("bar");
boolean ovrBar = mbar.getDeclaringClass() != Base.class;
System.out.println("Have override for foo: "+ovrFoo);
System.out.println("Have override for bar: "+ovrBar);
Prints
Have override for foo: false
Have override for bar: true
Demo.
This can be done calling getClass().getDeclaredMethod("aMethod"), which returns something only if the class of this declared it.
Here's an implementation of your method:
/**
* #return true if the instance's class overrode aMethod
*/
protected boolean aMethodHasBeenOverridden() {
try {
return getClass() != A.class && getClass().getDeclaredMethod("aMethod") != null;
} catch (NoSuchMethodException | SecurityException e) {
return false;
}
}
The approach I'd take is to only make this method exist if the subclass needs it by overriding method that calls it in an abstract intermediate class. Here's what that would look like:
public abstract class MovingThing {
public void move() {
// walk a few feet
}
}
Now a few of your moving things teleport, but that requires charging the flux capacitors and other expensive things, so separate that out:
public abstract class TeleportingThing extends MovingThing {
#Override
public void move() {
fluxCapacitor.charge();
stardate.calculate();
doTeleport();
}
protected abstract void doTeleport();
}
Your classes that need the expensive setup derive from the second class that includes it, while the ones that don't can derive from the first class. This pattern is a sort of Decorator and is used, for example, in the Servlet API, where most servlets override something like doGet() and leave the parsing to service().
I have an abstract super class A with a method doSomething(). A sub-class of A must implement doSomething(), but there is also some common code that should be called every time a subclass calls doSomething(). I know this could be achieved thus:
public class A {
public void doSomething() {
// Things that every sub-class should do
}
}
public class B extends A {
public void doSomething() {
super.doSomething();
// Doing class-B-specific stuff here
...
}
}
There seem to be three issues with this, though:
The method signatures have to match, but I might want to return something in the sub-class methods only, but not in the super-class
If I make A.doSomething() abstract, I can't provide a (common) implementation in A. If I don't make it abstract, I can't force sub-class to implement it.
If I use a different method to provide the common functionality, I can't enforce that B.doSomething() calls that common method.
Any ideas how the methods should be implemented?
What about the following?
public abstract class A {
protected abstract void __doSomething();
public void doSomething() {
// Things that every sub-class should do
__doSomething();
}
}
public class B extends A {
protected void __doSomething() {
// Doing class-B-specific stuff here
...
}
}
The first bullet point however is not so clear. The signature can't match if you want to return something different.
add call back to doSomething()
public class A {
public void doSomething() {
// Things that every sub-class should do
doSomethingMore()
}
}
protected abstract void doSomethingMore()
so all subclusses will have to ipmelment doSomethingMore() with additional actions but external classes will call public doSomething()
For first point alone - you can consider the below answer and for enforcing subclass implementation it can be abstract but calling common code functionality can happen if the base class has some implementation.
Return type can be Object in Base Class and returning null. In SubClass the specific return type can be put as given below.
public class InheritanceTutorial {
static class Base{
public Object doSomething(){
System.out.println("parent dosomething");
return null;
}
}
static class SubClass extends Base{
public Integer doSomething(){
super.doSomething();
System.out.println("child dosomething");
return 0;
}
}
/**
* #param args
*/
public static void main(String[] args) {
SubClass subClass = new SubClass();
subClass.doSomething();
}
}
Since the subclass is not constructed yet, is it unsafe to call an abstract method in a super class constructor?
However, if the method's behaviour does not depend on the constrction of subclass, e.g. just return a constant with regard to the subclass, is it still unsafe or will it work reliably?
Moreover, if it works, how to do it if I do not want to make the super class abstract?
Update: for last question
public class SuperClass {
public SuperClass() {
System.out.println(getValue());
}
public String getValue() {
return "superclass";
}
public static void main(String[] args) {
new SubClass();
}
}
class SubClass extends SuperClass {
public SubClass() {
super(); // Comment out this or not will not affect the result
}
public String getValue() {
return "subclass";
}
}
I wrote a test, and figure it out: the result is : subclass
Thanks to #Tim Pote's example.
It is generally (though not necessarily) considered unsafe. As you said, the superclass may not be fully constructed, and therefore won't be ready to handle all of the calls a subclass might make in its overridden method.
However, in the case that all subclasses simply return a constant that isn't dependent on any other method, then it should be fine. The only downside is that you can't guarantee that a subclass will override that method in an appropriate manner.
In regards to your last question: this isn't an issue of an abstract vs. concrete superclass. This is an issue with calling overridable methods in a constructor. Abstract vs. concrete is beside the point.
Edit in response to the OP's comment
I'm not certain what you mean by "polymorphiscly". Calling a virtual method always invokes the sub-most implementation. The only time a superclasses implementation is invoked is via the super keyword. For example:
public class SuperClass {
public SuperClass() {
System.out.println(getValue());
}
public String getValue() {
return "superclass";
}
public static void main(String[] args) {
new SubClass();
}
public static class SubClass extends SuperClass {
public String getValue() {
return "subclass";
}
}
}
prints subclass.
And this:
public class SuperClass {
public SuperClass() {
System.out.println(getValue());
}
public String getValue() {
return "superclass";
}
public static void main(String[] args) {
new SubClass();
}
public static class SubClass extends SuperClass {
public String getValue() {
return super.getValue() + " subclass";
}
}
}
prints superclass subclass
As others have explained there is an inherent risk in calling abstract methods in super class constructor.
The one exception I have found is when the subclass provides some "constant" information, e.g getId(), getHandledMessages() and suchlike.
I'm learning java. I was trying to run the code, where I got this error: return type is incompatible.
Part of code where it showed me error.
class A {
public void eat() { }
}
class B extends A {
public boolean eat() { }
}
Why it is happening?
This is because we cannot have two methods in classes that has the same name but different return types.
The sub class cannot declare a method with the same name of an already existing method in the super class with a different return type.
However, the subclass can declare a method with the same signature as in super class.
We call this "Overriding".
You need to have this,
class A {
public void eat() { }
}
class B extends A {
public void eat() { }
}
OR
class A {
public boolean eat() {
// return something...
}
}
class B extends A {
public boolean eat() {
// return something...
}
}
A good practice is marking overwritten methods by annotation #Override:
class A {
public void eat() { }
}
class B extends A {
#Override
public void eat() { }
}
if B extends A then you can override methods (like eat), but you can't change their signatures. So, your B class must be
class B extends A {
public void eat() { }
}
B extends A should be interpreted as B is a A.
If A's method doesn't return anything, B should do the same.
When a method in subclass has same name and arguments (their types, number, and order) as the method in superclass then the method in subclass overrides the one in superclass.
Now for the overriding to be allowed the return type of the method in subclass must comply with that of the method in superclass. This is possible only if the return type of the method in subclass is covariant with that of the method in superclass.
Since, boolean </: void (read: boolean isn't subtype of void), compiler raises the "return type incompatible" error.
This is neither overloading nor overriding. We cannot overload on the return type and we cannot override with different different return types ( unless they are covariant returns wef Java 1.5 ).
This shows error , because we can not create two same methods but different return type in same class. If in parent class contain any method, we can't create same method name with changing the return type in sub class. Now the question arise why we can't create this. we should discuss about following code.
class A {
public void eat() { }
}
class B extends A {
public boolean eat() { }
}
Class MainClass{
public static void main(String[] args){
A a = new B();
a.eat();
}
}
It will shows an error, because a.eat(); will be confused which method JVM should call. and it will return a runtime error. Thats why to overcome runtime error, it returns a compile time error.
interface I
{
void show();
}
class A implements I
{
void show()
{
System.out.println("class A");
}
public static void main(String s[])
{
I i=new A();
i.show();
i.toString();
}
}
Q> As interface I does not contain the abstract method toString() but still The following code gets compiled. How?
when super class variable is used to refer sub class obj then compiler first searches the similar method in the super class if not found gives error.
here Interface does not contain the method toString().
ex=>
class A
{
void show()
{
System.out.println("show");
}
}
class B
{
void show()
{
System.out.println("show B");
}
void display()
{
System.out.println("display B");
}
public static void main(String s[])
{
A a=new B();
a.show(); //will execute
a.display(); //give error
}
All classes inherit from Object. Object has a toString.
To use any interface it must be backed by a actual class. So the Java compiler knows that it can use any method defined in java.lang.Object when dealing with an Interface.
To put it a slightly different way:
interface I { ... }
has an "magic"
interface I extends Object { ... }
So you can use Objects methods when detail with I. However you can not use any methods in the concrete class that do not appear in the interface. So to combine you two examples:
interface Car {
void drive();
}
class Convertible implements Car {
void drive() {}
void openRoof() {}
public static void main() {
Car porscheBoxster = new Convertible();
porscheBoxster.drive(); // OK - exists in interface
porscheBoxster.toString(); // OK - exists in java.lang.Object.
porscheBoxster.openRoof(); // Error. All we know is the porscheBoxster is of type Car.
// We don't know if it is a Convertible or not.
}
}
Every class in Java is an Object, thus, they are always able to run the following methods:
clone()
equals(Object)
finalize()
getClass()
hashCode()
notify()
notifyAll()
toString()
wait()
wait(long)
wait(long, int)
Because 'toString()' is in the class Object which every non-primitive data is derived from. So every object has this method.
In Java, every class you construct, inherits from the base class Object.
This means that your class by default will have a lot of useful methods, amongst others toString().