简体   繁体   中英

Java invoke child method from parent object

I've got next situation:

There is an abstract class

public abstract class SuperClass {
    public abstract void getString();
    public abstract void method2();
}

public class InheritClass1 extends SuperClass {
    @Override
    public void getString(){...};
    @Override
    public void method2(){...};
}

public class InheritClass2 extends SuperClass {
    @Override
    public void getString{...};
    @Override
    public void method2(){...};

    public void customMethod(){...};
}

There is another class that has a method that accepts SuperClass object as an argument. Depending on what kind of String is returned from getString I perform different actions. My case is that I am trying to call a child method while the object is of parent class:

public class Processor {
    public String method(SuperClass type) {
         switch (type.getString()) {
             case "1":
               return "OK"
             case "2":
               return ((InheritClass2) type).customMethod()
         }
 }

I do understand that this is BAD DESIGN, could you please help me with finding the best solution for this problem. Maybe generics are suitable in this case somehow. Also the thing is that customMethod() should be a part of not all classes.

Depending on your design you could apply:

if (type instanceof InheritClass2.class) return type.customMethod();

or

if (type.getClass() == InheritClass2.class) return type.customMethod();

Since only some (sub)classes implements customMethod , I would suggest to create an interface that contains this method:

public interface CustomInterface {
    public String customMethod();
}

Your SuperClass can then remain just as it is. Only the subclasses/child classes that have customMethod , would then extend your SuperClass as well as implement this CustomInterface . This way, the child classes that do not implement CustomMethod (does not have the method in their class, such as InheritClass1 in your example), also remain just as they are.

Only child classes that have CustomMethod , such as InheritClass2 would then need to change slightly by saying it implements this new interface:

public class InheritClass2 extends SuperClass implements CustomInteface {
    // the rest stays the same
}

Then in the section where you want to do the casting, you rather do the following:

public class Processor {
    public String method(SuperClass type) {
        switch (type.getString()) {
            case "1":
                return "OK"
            case "2":
                String s = "";
                if (type instance of CustomInterface) {
                    s = (CustomInterface type).customMethod();
                }
                return s;
        }
    }
}

Using the interface in this way will help that you can implement all child classes and not just one as implementing the CustomInterface , and thus, all child classes will work with using instanceof and casting to the interface to call customMethod() - you won't have to handle each child that needs this method separately.


NOTE: Your code is clearly simplified example, it is unclear if the getString() method is just returning an identifier of the child classes in order for you to know which ones you can cast and then call custom Method on... If this is the purpose of your switch and getString methods - to identify which types implement the customMethod() and to call that method, and for any child class that does not have that method to return just "OK" - then you could instead do the following:

public class SubClass1 extends SuperClass implements CustomInterface {
    // other mehtods...
    public String CustomMethod() { return "SomeString1"; }
}

public class SubClass2 extends SuperClass {
    // other methods...
    // this subclass does not have the CustomMethod()
}

public class SubClass3 extends SuperClass implements CustomInterface {
    // other methods...
    public String CustomMethod() { return "SomeString3"; }
}

Then your Processor could look like this:

public class Processor {
    public String method(SuperClass type) {
        return (type instanceof CustomInterface) ? ((CustomInterface) type).CustomMethod() : "OK";
    }

    public static void main(String[] args) {
        Processor p = new Processor();
        SuperClass obj1 = new SubClass1();
        SuperClass obj2 = new SubClass2();
        SuperClass obj3 = new SubClass3();

        System.out.println(p.method(obj1)); // prints: "SomeString1"
        System.out.println(p.method(obj2)); // prints: "OK"
        System.out.println(p.method(obj3)); // prints: "SomeString3"
    }
}

If you don't understand the ternary operator then you can read about it here That's the condition ? exprTrue : exprFalse condition ? exprTrue : exprFalse syntax. It's a short if else statement basically.

You can create an interface, with default custom method implementation, like:

interface A {
    default String customMethod() {
        return "";
    }
}

And abstract class will implement this interface:

public abstract class SupperClass implements A {
    public abstract String getString();
    public abstract void method2();
}

Bad design will cause you to get bad answers. If you don't want to cast your object to a child object. You could use reflection.

import java.lang.reflect.Method;

public class Processor {
    public String method(SuperClass type) {
        Method[] methods = type.getClass().getMethods();
        for (Method m : methods) {
            if (m.getName().equals("customMethod")) {
                try {
                    return m.invoke(type);
                } catch (Exception ex) {
                    // throw
                } 
            }
        }
        return "OK";
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM