2

Say I have the following classes

public abstract class Parent {

    public Parent() {
    
        //stuff here
    
    }

}

public class Child extends Parent {

    public Child() {
    
        //stuff here
    
    }

    public void doSomething() {
    
    }

}

Then I get an object from an array of Parents

public Parent[] parents = new Parent[5];

Parent tempParent = parents[0]

If this object is of the child class, I want to cast the tempParent into the child class in order to use "doSomething" without having to create a new object

if(tempParent.getClass == Child.class) {

    tempParent = (Child) tempParent;

    tempParent.doSomething();

}

This, however, does not work. I still get an error telling me that doSomething is not a function in the Parent class. Is there a way to do what I'm trying to do?

Andreas Sandberg
  • 241
  • 1
  • 3
  • 10
  • You can't simply cast a parent into a Child but rather, consider giving Child a copy constructor, and create a new instance with the Parent item in the array. – Hovercraft Full Of Eels Aug 04 '21 at 12:56
  • NB: @HovercraftFullOfEels 's comment is not useful; it is misunderstanding the question. – rzwitserloot Aug 04 '21 at 12:59
  • 1
    I appreciate the quick accept! But yes, make sure to also read the other answers. I gave the "technically correct" solution, but yes: using an abstract class, and *overriding* `doSomething()` as shown in the other answers is the **conceptually** better way! – GhostCat Aug 04 '21 at 13:17
  • @GhostCat Why is that? My reasoning for not doing that is since I have a class in my program called "GameObject", and lots of classes extends this class in order to make every object able to render and update among other things, yet every class does not need a "shoot" function or similar, so I only wrote those functions in the children that required them for convenience sake. What is the benefit of instead writing every function in the parent class and then overriding? – Andreas Sandberg Aug 04 '21 at 13:27
  • If you really want to write it like this, it should be `if (tempParent instanceof Child)` instead of `if (tempParent.getClass == Child.class)`. – Jesper Aug 04 '21 at 13:38
  • @AndreasSandberg Because good OOP suggests that you do NOT constantly ask "are you of this class or of that class". You strive to create a model where you dont care about specific types as much as possible. You simple go and invoke some method on some object, and ideally, if you need different behaviour for different classes, you solve that by polymorphism. Doing an `instanceof` check is very often just the result of a poor design. Remember: nothing in programming is just black or white. But there are certain goals you strive to get to. Deviation isnt always wrong ... – GhostCat Aug 06 '21 at 04:05
  • but especially when you are in the learning phase it is important to understand that "hey, there all multiple ways of going about this" ... and to then figure out which pros and cons each way has. And as said: checking objects "what exact type do you have" is *very often* not a good approach: you do NOT want that your "client" code that uses these objects really has to know about such details. And base classes (or interfaces!) that allow child classes to implement/override the same method in different ways is one option to avoid that. – GhostCat Aug 06 '21 at 04:07
  • @GhostCat I've learned to program myself, so I am kind of new to this. Thanks for the explanation. I'll try to use overriding as well as look into what interfaces are since you among others have mentioned it. – Andreas Sandberg Aug 07 '21 at 13:01

3 Answers3

6

You need to use the correct TYPE on the LEFT hand side:

Child someChild = (Child) tempParent;

Note: this does not create a new Object.

There is no way of having

Parent whatever = (Child) tempParent;

do what you want to do (invoke a Child class method)!

You see, the compiler only cares about the "defined" type of your reference, it does not take into account that you most likely, at runtime, just "put" something into that reference that in deed is a Child instance!

to do what you want to do.

And note: do not compare objects using ==. You should prefer to call equals() instead. For Class objects == should work (most of the time), but still: get used to check for equality using equals().

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • Oh, I thought that what you did would create a new object, but it appears I was mistaken. Out of curiosity, what is the difference between == and equals()? I've never ran into any problems using == – Andreas Sandberg Aug 04 '21 at 13:11
  • Then you havent written code yet that compares strings I guess. See https://stackoverflow.com/questions/513832/how-do-i-compare-strings-in-java for example. – GhostCat Aug 04 '21 at 13:18
3

I think you're trying to solve the issue from the wrong side. Technically speaking you should do it like this.

public abstract class Parent {

    public Parent() {
    
        //stuff here
    
    }

    public abstract void doSomething();

}

public class Child extends Parent {

    public Child() {
    
        //stuff here
    
    }

    @Override
    public void doSomething() {
        // Write the code of doSomething specific to child.
    }

} 

A bit off topic but you might want to consider the following:

I think that the class representation of your code is bad.

I think that you should have 2 concrete classes Parent and Child that are composed or either inherit from a common interface. Even better use composition over inheritance.

https://en.wikipedia.org/wiki/Composition_over_inheritance

Omegaspard
  • 1,828
  • 2
  • 24
  • 52
0

if you are able to modify the parent class, I would recommend that you make doSomething an abstract method and have the child class override it. that way, there is no need to cast in order to invoke it.

https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

mre
  • 43,520
  • 33
  • 120
  • 170