2

I'm fairly new to Java and would like to know how to accomplish the following task, and also, whether it is considered bad style, even if it is possible. Thank you.

Fish f;  // Fish is a superclass,
Tuna t = new Tuna();  // to which Tuna is a subclass.

f=t;  // the Fish object "f" now refers to the Tuna object "t".

// Both Fish and Tuna have an identical method (signature wise) called swim() ,
f.swim();  // and so Tuna's overridden swim() method is invoked here.

But can I now get Fish's swim() method to be invoked, using the same "f.swim()" syntax?

// I would now like Fish's swim() method to be invoked here,
// but is it bad style and/or am I missing some point about OOP?
f.swim();

Edit:

Re: answers, thanks people! Regarding SO user Rinke's answer below - he states that "You can assign your tuna instance to both tuna and fish typed variables, but it'll always be a tuna."

The last part of that sentence got my novice OOD brain wondering - why allow a "super object" to refer to a "sub object" anyway? What is the benefit of this flexibility? What benefit is there in allowing a Fish object the ability to "switch between" referring to either a fish or a tuna? Thank you.

Edit 2:

Here is some example code to illustrate the concept of SO user Rinke's "answer to edit" response, below.

Bear b = new Bear();
Fish f = getAnyFish();
b.eat(f);

Fish getAnyFish(){
    //To toggle the returned fish type, change true to false
    if (true) return new Tuna();
    else return new Salmon();
}
user2911290
  • 1,396
  • 1
  • 16
  • 26

5 Answers5

3

The short answer is "No". The confusion here comes from the difference between run-time types and declared types. You can assign your tuna instance to both tuna and fish typed variables, but it'll always be a tuna. Hence, if you call the swim method on that object the tuna will swim like a tuna (i.e. the overridden method will be called).

Note that you can call the swim method of a superclass from within the subclass by invoking super.swim().

Of course, if you don't override the swim method then tunas simply inherit the method from fish. In that case the fish-code will be run on the tuna instance.

Answer to edit:

You don't always control the code you use. Maybe you need to provide your tuna to someone else's API that accepts fish.

From the opposite perspective: maybe you're implementing a bear. Bears eat fish. You don't want to care if it's a tuna or a salmon. So you get void eat(Fish f), where mother nature (implemented by a piece of code outside of your control) provides fish to your bear.

To leave the funny fish example: look at Collections.sort(). You can sort any list. It doesn't matter if it's an ArrayList or a LinkedList.

Rinke
  • 6,095
  • 4
  • 38
  • 55
1

You cannot bypass Tuna.java's swim() method if it's overridden. But what you can do is, in overridden swim(), inside Tuna.java, you can make a call to super class' method.

Tuna.java

@Override
public void swim() {
   super.swim(); // This will call Fish.java's swim() method.
   // rest of the code
}

The another option is, change the signature of swim() method in Tuna.java in such a way, that it becomes the overloaded version of Fish.java's swim(), but not the overridden.

RAS
  • 8,100
  • 16
  • 64
  • 86
1

can I now get Fish's swim() method to be invoked, using the same "f.swim()" syntax?

No, you can't.

Bludzee
  • 2,733
  • 5
  • 38
  • 46
0

Although it is not possible. I am using @Deprecated to indicate that the specific method is unused.

smftr
  • 923
  • 3
  • 17
  • 31
-1

You can use a different approach to this if you really want to get the swim method of the parent class. I define an interface as Swimmable

public interface Swimmable {
    public void swim();
}

Then I make Fish implement this interface

public class Fish implements Swimmable {

@Override
public void swim() {
    System.out.println("Fish");
    }
}

And my Tuna class as

public class Tuna extends Fish {
//Anything I want the Tuna to have extra 
}

Now with your same code

Fish f;
Tuna t = new Tuna();
f=t;
f.swim(); //This will call the Fish's method
Saif Asif
  • 5,516
  • 3
  • 31
  • 48
  • Maybe I'm missing something, but if Tuna defines its own overriding `swim()`, won't that be what `f.swim()` calls? How does the interface change anything that happens? – Teepeemm Nov 28 '13 at 13:14
  • Yes correct. Thats why I didn't implement the interface in class Tuna mainly because of the poster's requirement. – Saif Asif Nov 28 '13 at 13:37
  • So your answer adds an interface, but doesn't do what OP asked? – Teepeemm Nov 28 '13 at 17:30
  • I suggest you try the code snippet and see what result it gives. – Saif Asif Nov 28 '13 at 17:33
  • I'll grant you that it works as advertised. My question is how adding an interface solves OP's problem of calling `Fish.swim()` when `Tuna` has also defined a `swim()` method. – Teepeemm Nov 29 '13 at 12:46
  • OP's requirement was to call the `swim()` of Fish. Yes there are other ways to achieve this like the accepted answer explains that we can have a call to `super.swim()` or we don't implement the method `swim()` in the Tuna method at all so that way `Tuna` will always inherit the `swim()` method of `Fish` (This is what I did). Now as far as the interface is concerned, whenever some property is to be associated with an object (Ball is Bounceable , Thread is Runnable or Service is Consumeable) its best practise to use interfaces to offer a layer of abstraction. – Saif Asif Nov 29 '13 at 17:18
  • The original post says both Tuna and Fish implement swim, so your answer really amounts to "don't have Tuna implement swim". This answer is really not useful. – Kevin Jul 15 '16 at 17:05