I have a class hierarchy which looks somewhat like this:
class Parent { }
class Child1 extends Parent {}
class Child2 extends Parent {}
class Child3 extends Parent {}
In another class I have methods looking like this:
void doSomething(Parent p) { //default }
void doSomething(Child1 c) { //implementation for Child 1 }
void doSomething(Child2 c) { //implementation for Child 2 }
Currently, when I have something like this
Parent p = new Child2();
doSomething(p);
the first method, doSomething(Parent) is called instead of doSomething(Child2)
Let's assume I have a list of items with the static type of Parent and a dynamic type of ChildN. How can I assure the method, provided for the dynamic type is called, without casting. Only for Child3 (no specific doSomething method) I want to call the default implementation.
What you are looking for is called "multi dispatch or "dynamic dispatch" - and doesn't exist in Java.
In Java, the compiler decides which method to pick in case of overloading. (and that is what happens when you have three methods with the same name but different parameter types). This happens at compile time, and if your "runtime" Parent object happens to be a Child1 object; that doesn't matter. Because the compiler fixed the method to call - as said: java doesn't support dynamic dispatch.
In that sense, the correct Java solution would be to put a method "doSomething()" on your Parent class; and have each child override that method to the specific thing.
In case "doSomething()" doesn't really "fit" into this class; you can have a look into the visitor pattern. Another option would be to use instanceof ... but then you should "hide" the corresponding if/else chain ... again using polymorphism, like:
interface DoIt { void doSomething() }
class ParentDoIt implements DoIt ...
same for Childs
class DoItFactory {
DoIt getDoIt(Parent p) {
if (p instanceof Child1) return new Child1DoIt(p)
...
A solution could be that the doSomething method uses logic from the parameter:
class Parent {
public void neededMethod() {//default}
}
class Child1 {
public void neededMethod() {//implementation for Child 1}
}
Then in your code:
void doSomething(Parent p) {
//more code
p.neededMethod();
// code
}
If this solution does not fit you because you need some kind of a dispatcher, then you will have to use instanceof and then call the proper method:
void doSomething (Parent p) {
if (p instanceof Child1) doSomethingWithChild1(p);
else if (p instanceof Child2) doSomethingWithChild2(p);
...
else defaultSomething(p);
}
I would do it like this.
interface SomeAction { void doSomething(); }
class Parent implements SomeAction { //override doSomething here }
class Child1 extends Parent {//override doSomething here }
class Child2 extends Parent {//override doSomething here }
class Child3 extends Parent { // no need to override here}
Now
In another class I have methods looking like this
void doSomething(SomeAction p) { //default }
Parent p = new Child2();
doSomething(p);
p.doSomething(); // would call Child 2
Related
Imagine this scenario:
public class A {
...
}
class B extends A {
public foo getFoo() {
returns _foo;
}
}
there also exist other classes children of A having the same method
class C extends A {
...
public foo getFoo() { returns _foo; }
...
}
So, the method `foo` doesn't exist in parent class, however, it exists in all children classes.
Is there a way in Java to not directly specify which child class will be called however use a generic way (I believe in Scala it's [T < A]).
So that I can use it like this:
void Bar(`[some child class of A]` childOfA){
childOfA.getFoo(); // Now this would return either getFoo() of A or B
}
That won't be possible with current setup because there is no guarantee that the method will be present in subclasses until unless it's mandated.
Now, what you can do, change parent class, and add abstract method there. That will insure, the method is always present in child class or it's further child classes (in case of child class is abstract).
abstract class A {
public abstract Foo getFoo();
}
class C extends A {
public Foo getFoo(){
// your code
}
}
Now, you can have your generic method with an upper bound.
void <T extends A> bar(T childOfA){
childOfA.getFoo();
}
Here, <T extends A> will make sure, your argument should be subclass of A.
I have a List defined as
List<ParentClass> parentClassList;
Parent class is abstract, so when I add elements to the List I do something like
parentClassList.add(new ChildClassOne(...));
parentClassList.add(new ChildClassTwo(...));
and so on... I actually have 5 child classes right now.
What I'd like to do is to call a method in another Class, overwriting its arguments, so:
public void doSomething(ChildClassOne arg) {...}
public void doSomething(ChildClassTwo arg) {...}
But if the type of the List is the parent Class I can't do
doSomething(parentClassList.get(0));
Basically I need to perform different actions based on the child's type and I need access to all the methods inside a specific child. Different childs have different methods, they have only one methods in common.
Define an abstract emthod doSomthing() in ParentClass, and in each sub class you implement it like this:
class ChildClassOne {
void doSomething() {
instanceOfSomeOtherClass.doSomething(this); // will call the correct method
}
}
and SomeOtherClass will have methods for each sub class:
class SomeOtherClass {
void doSomething(ChildClassOne o) {};
void doSomething(ChildClassTwo o) {};
void doSomething(ChildClassThree o) {};
...
}
You can read about this approach in regards to the Visitor Pattern
It might be even simpler if you moved the code from SomeOtherClass into the ChildClasses, though.
In this situation a double dispatch technique called Visitor Pattern becomes very handy:
interface Visitor {
void visitChildOne(ChildOne child);
void visitChildTwo(ChildTwo child);
void visitChildThree(ChildThree child);
}
abstract class ParentClass {
public abstract void accept(Visitor v);
...
}
class ChildClassOne extends ParentClass {
#Override
public void accept(Visitor v) { v.visitChildOne(this); }
}
class ChildClassTwo extends ParentClass {
#Override
public void accept(Visitor v) { v.visitChildTwo(this); }
}
class ChildClassThree extends ParentClass {
#Override
public void accept(Visitor v) { v.visitChildThree(this); }
}
When you need to perform some task that does different things depending on the type of a child, provide an implementation of the Visitor interface, and pass it to accept of each of the children that you wish to process:
Visitor v = new Visitor() {
#Override
public void visitChildOne(ChildOne child) {
System.out.println("Visiting child type 1");
String someProperty = child.getPropertySpecificToChildOne();
}
#Override
public void visitChildTwo(ChildTwo child) {
System.out.println("Visiting child type 2");
int someProperty = child.getPropertySpecificToChildTwo();
}
#Override
public void visitChildThree(ChildThree child) {
System.out.println("Visiting child type 3");
}
};
for (Parent p: parentClassList) {
p.accept(v);
}
Basically I need to perform different actions based on the child's type and I need access to all the methods inside a specific child.
In this case the behavior you want to implement belongs into this specialized classes.
You might add another (abstract) method signature to the base class which you implement in the child classes providing the type depended behavior.
I have an abstract class where I want to create a method that can be passed either of the child instances that extend it.
For example:
abstract class base
{
public void doSomething(Child1 or Child2){
}
}
class Child1 extends base
{
public void somefunc(){
doSomething(Child1);
}
}
class Child2 extends base
{
public void somefunc(){
doSomething(Child2);
}
}
I feel like there are multiple ways to get around it. Is it possible to get an idea of what are the possible ways? I definitely dont want to create the same function in all the child classes.
I'm not sure if the parameter passed to doSomething is supposed to be this, or a separate object of the same type. In the first case, peter.petrov's answer is what you want. In the second case, the standard way around this is to make Base generic and to use a recursive bound.
abstract class Base<T extends Base<T>> {
public void doSomething(T t) {}
}
class Child1 extends Base<Child1> {
public void someFunc() {
Child1 child1 = new Child1();
doSomething(child1);
}
}
class Child2 extends Base<Child2> {
public void someFunc() {
Child2 child2 = new Child2();
doSomething(child2);
}
}
Seems like this is what you're looking for.
abstract class base
{
public void doSomething(base obj){
}
}
class Child1 extends base
{
public void somefunc(){
doSomething(this);
}
}
class Child2 extends base
{
public void somefunc(){
doSomething(this);
}
}
Then, if you want override doSomething in your child classes.
In fact, you don't even need the base parameter and to pass this, you already have an implicit reference to this.
One of the ideas behind inheritance is to share behaviour amongst classes of the same abstract type.
So if you want the same behaviour for all subtypes of your base class, implement the method in your base class. You don't need to pass the object reference, use the this keyword.
If you want different behaviours in your sub classes, declare the method abstract in your base class and implement each of the behaviours in the various sub classes.
public class Parent {
....
}
public class Child1 extends Parent {
....
public void foo() {
....
}
}
public class Child2 extends Parent {
....
public void foo() {
....
}
}
Here method foo() only exists in the Child classes and CAN NOT be added to the Parent class (not even abstract method). In this situation when I want to call the foo() method on obj which is Parent class's reference then I need to use intanceof with multiple if..else which I want to avoid.
Parent obj = ...// Object of one of the child classes
obj.foo();
EDIT: I Need to use type of obj as Parent only. Else I will not be able to call methods on obj which exists in Parent class.
My Solution: The approach that I am thinking is to define an interface say FooInterface with foo() method and let all the child classes implement it, then I could just type cast the obj to that interface and call foo() method like this:
if(obj instanceof FooInterface){
((FooInterface)obj).foo();
}
Is there a better approach ? Or any improvement to this one?
You can't do it with parent object reference until an unless method is declared in parent class/interface itself.
You have to downcast it to child class because parent class/interface doesn't have any knowledge about the child class other than the contract defined between them.
Here contract means abstract methods.
you can try in this way where there is no need to put a check it.
FooInterface sc =new Child1();
sc.foo();
...
interface FooInterface{
void foo();
}
public class Parent {
}
public class Child1 extends Parent implements FooInterface{
public void foo() {
}
}
public class Child2 extends Parent implements FooInterface{
public void foo() {
}
}
The approach that I am finally taking is to define an interface say FooInterface with foo() method and let all the child classes implement it, then I could just type cast the obj to that interface and call foo() method like this:
Parent obj = ...// Object of one of the child classes
.....
if(obj instanceof FooInterface){
((FooInterface)obj).foo();
}
The polymorphism is applied on object reference, not a type. When you call
FooInterface obj = ...// Object of one of the child classes
obj.foo();
the child class method foo() is called.
If you want to typecast only then there is no need of adding interface. You can typecast it to your desired class and call the method. Example
public class HelloWorld {
public static void main(String args[]) throws FileNotFoundException {
SuperClass sc =new Child1();
if(sc instanceof Child1)//Do same for Child2
((Child1)sc).foo();
}
}
class SuperClass {
}
class Child1 extends SuperClass{
public void foo(){
System.out.println("From child1");
}
}
class Child2 extends SuperClass{
public void foo(){
System.out.println("From child2");
}
}
Output :
From child1
You could implement an AbstractChild inheriting from Parent and then extend this class instead of Parent:
public class Parent {
....
}
public abstract class AbstractChild extends Parent{
public abstract void foo();
}
public class Child1 extends AbstractChild {
....
public void foo() {
....
}
}
public class Child2 extends AbstractChild {
....
public void foo() {
....
}
}
So you need to only check if your instance is instanceof AbstractChild.
I have a Parent.java class and 4 child classes as Child1.java, Child2.java and so on.
There are two methods
m1()
m2()
and one field
f1
Field f1 has different values based on the child class.
Method m1 has the common implementation so I have put it in Parent.java class. It also refers method m2.
Method m2 has common implemtation but it process field f1 which is different for all the child classes.
So my questions are as follows:
Q1. Should I place the field f1 in the parent class and let all the child classes inherit them and initialize them in their own constructors or Should I make a field f1 for all the child classes.
Q2. As the method m2 has common implementation but process field f1 which doesn't have same value for every child class, so should I place it in parent class or child class.
Q3. If I should place the method m2 in parent class, the there is one problem that method m1 (which have common implementation) refer method m2, so would it create any problem?
Place m2 and f1 in the parent class if m2's implementation is the same for all classes. If there's a specific part for each child class that can be run after the common part - separate it and place it in the child classes while calling super.m2(). Set f1 in each child class's constructor.
The result will look something like this:
public abstract class parent {
private int field = 0;
public parent(int f) {
field = f;
}
public void m1() { /* m1's implementation */ }
public void m2() { /* m2's common implementation */ }
}
public class child1 {
public child1() {
super(1);
}
#Override
public void m2() { super.m2() /* m2's child1 implementation */ }
}
public class child2 {
public child2() {
super(2);
}
#Override
public void m2() { super.m2() /* m2's child2 implementation */ }
}
This should allow you to push the maximum amount of code as far back in the hierarchy as it can go. Least code duplication.
Edited to fix trying to access a private member from a child class. Changed to setting it using the constructor.
In my opinion:
f1 should be in the parent class and initialized in the child constructor. This way, the get and set methods are only written once.
m2 should be in the parent class.
m1 should be also be in the parent class. Don't forget that you can also make methods abstract if they do not have a common implementation but exist in all child classes. This would allow you to call it from other methods in the parent class despite not being defined there. Also keep in mind that the parent class would also need to be abstract in this case.
From what you described, I don't see any problem with this implementation:
public class Parent {
private int f1;
public Parent(int f1) {
this.f1 = f1;
}
public void m1() { }
public void m2() {
// do something with f1
System.out.println(f1);
}
}
public class Child1 extends Parent {
private final int DEFAULT_FIELD_VALUE = 1;
public Child1() {
super(DEFAULT_FIELD_VALUE);
}
}
public class Child2 extends Parent {
public Child2(int value) {
super(value);
}
}
{...}
What you are trying to do sound like Template Method design pattern: http://en.wikipedia.org/wiki/Template_method_pattern
I suggest putting f1 in the parent class and declaring m2 abstract in the parent class (which will make the class abstract itself).
If the child classes differ only in the value of f1 then there is no point in even creating subclasses, you should just pass f1 in a constructor or use static factory methods to create instances for the different cases. For example:
public class Parent {
private Value f1;
private Parent(Value f1) {
this.f1 = f1;
}
public static Parent makeChild1() {
return new Parent(valueOfF1ForChild1);
}
public static Parent makeChild2() {
return new Parent(valueOfF1ForChild2);
}
}
Also, you might want to check out if an enumeration is suitable for your case.