Related
This question already has answers here:
Is this an acceptable use of instanceof?
(2 answers)
Closed 7 years ago.
I'm new to Java and struggling with a design problem. I know use of instanceof may indicate a design flaw and I understand the often given Animal/Dog/Cat classes as example, replacing bark() and meow() with makenoise() etc.
My question is, what is a sensible design if I need to call methods which do not have a corresponding method depending on the type of subclass? For example, what if I want to call a new method biteleash() if the class is a Dog but do nothing at all if it's a Cat?
I did consider having biteleash() in Animal which does nothing, and overriding it in Dog, but there are methods many like this so it seems a clunky solution. In a similar vein, what if the caller needs to do something different depending on which subclass it has hold of, eg. terminate if subclass is a Cat? Is instanceof acceptable here, or is there a better way?
public class Animal {
String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void makeNoise() {
System.out.println("Some noise for a generic animal!");
}
}
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
#Override
public void makeNoise() {
System.out.println("Meow");
}
}
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
#Override
public void makeNoise() {
System.out.println("Woof");
}
public void biteLeash() {
System.out.println("Leash snapped!");
}
}
import java.util.Random;
public class CodeExample {
public static void main(String[] args) {
Animal animal = getSomeAnimal();
System.out.println("My pet is called " + animal.getName());
animal.makeNoise();
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.biteLeash();
// do lots of other things because animal is a dog
// eg. sign up for puppy training lessons
}
}
private static Animal getSomeAnimal() {
Animal animal;
Random randomGenerator = new Random();
int randomInt = randomGenerator.nextInt(100);
if (randomInt < 50) {
animal = new Dog("Rover");
}
else {
animal = new Cat("Tiddles");
}
return animal;
}
}
Composition will help you here, and is idiomatic in Java.
Design an interface called, say, Leashable. This is implemented by a Dog, but not a Cat.
Rather than using instanceof, you can attempt a reference cast to Leashable to see if it's implemented by your particular object.
In my opinion, you should continue in a similar vein: Build a NoisyAnimal interface too. Perhaps even just Noisy as why should noisiness be pertinent to only animals? Implementing that for a Parrot, say, will have technical challenges beyond a Cat or Dog. Good maintainable programs isolate areas of complexity and composition helps you achieve that.
You shouldn't use concrete classes. Instanceof itself isnt a problem. It exists for a reason. You should use interfaces for loose coupling i.e. your code shouldnt be dependent on concrete class implementations. I suggest you using interfaces wherever possible (i.e. IAnimal instead of Animal)
Instead of checking for Dog, you should use an interface like ILeashable (yeah a bit ridiculous for a name lol), then:
public interface ILeashable {
//add other methods which is connected to being on a leash
void biteLeash();
}
class Dog implements ILeashable {...}
Also there is no one way of doing this, there are certain patterns i.e. decorators or Dependency Inversion which might help you in this case.
Just so you know, this issue you're having is not something you'll generally be facing in the real world. If you have to have implementation-specific logic on some class that implements an interface or an abstract base class, it will usually be because at some higher level you need to get a derived property. This psuedocode to illustrate:
interface ISellable {
decimal getPrice();
}
class CaseItem : ISellable {
int numItemsInCase;
decimal pricePerUnit;
decimal getPrice() {
return numItemsInCase*pricePerUnit;
}
}
class IndividualItem : ISellable{
decimal pricePerUnit;
decimal getPrice() {
return pricePerUnit;
}
}
main() {
aCaseItem = new CaseItem { pricePerUnit = 2, numItemsInCase=5 }; //getPrice() returns 10
anIndividualItem = new IndividualItem { pricePerUnit = 5 }; //getPrice() returns 5
List<ISellable> order = new List<ISellable>();
order.Add(aCaseItem);
order.Add(anIndividualItem);
print getOrderTotal(order);
}
function getOrderTotal(List<ISellable> sellableItems) {
return sellableItems.Sum(i => i.getPrice());
}
Notice that I am using the interface to abstract away the concept of an item's price, but when I'm actually in the main method, I can easily create instances of the specific type in order to control the behaviors of the two classes.
However, when I need to get the price, I'm referencing the items as a list of ISellable, which only exposes their "getPrice()" method for my convenience.
Personally, I always believed the animal methaphor to be severely lacking. It doesn't explain this concept in a way that makes sense, and it doesn't clue you in on how to use it in the real world.
Think of it this way: What event causes the Dog to bite its leash? Or differently speaking, what is your motivation to make it perform this action?
In your example there is actually none. It just so happens that in your main method you decided to put in a check and if the animal you randomly created is a Dog, you make it do certain dog things. That's not how code in the real world works.
When you write code, you want to solve some problem. To stick to the animals example, let's pretend you write a game where you have pets that react to certain events like turning on the vacuum or getting a treat. From this sentence alone we can create a reasonable class hierarchy:
interface Animal {
void reactToVacuum();
void receiveTreat();
}
class Dog implements Animal {
public void biteLeash() {
System.out.println("Leash snapped!");
}
public void wiggleTail() {
System.out.println("Tail is wiggling!");
}
#Override
public void reactToVacuum() {
biteLeash();
}
#Override
public void receiveTreat() {
wiggleTail();
}
}
As you can see, the leash biting happens in response to an event, namely turning on the vacuum.
For a more realistic example, take Android's view hierarchy. A View is the base class for every control on the screen, e.g. a Button, an EditText and so on. View.onDraw() is defined for every view but depending on what View you have, something different will happen. EditText for example will do something like drawCursor() and drawText().
As you can see, the answer to the question "What event causes the EditText to draw the cursor" is "It needs to be drawn on the screen". No instanceof or condition checking necessary.
As in your example - some subclasses can have different methods.
This is typical scenario where you have to use instanceof.
If your subclasses are fixed then you can use animalType to avoid instanceof.
I prefer that u can use interface to check whether the feature is available with the subclass, but it is not feasible for large number of subclass dependent methods. ( solution given by user2710256).
Enum Type {
DOG,CAT ;
}
public abstract class Animal {
String name;
Type type;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void makeNoise() {
System.out.println("Some noise for a generic animal!");
}
abstract Type getType();
}
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
#Override
public void makeNoise() {
System.out.println("Meow");
}
public Type getType() {
return Type.CAT;
}
}
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
#Override
public void makeNoise() {
System.out.println("Woof");
}
public void biteLeash() {
System.out.println("Leash snapped!");
}
public Type getType(){
return Type.DOG;
}
}
import java.util.Random;
public class CodeExample {
public static void main(String[] args) {
Animal animal = getSomeAnimal();
System.out.println("My pet is called " + animal.getName());
animal.makeNoise();
switch(animal.getType())
{
case DOG:
{
Dog dog = (Dog) animal;
dog.biteLeash();
// do lots of other things because animal is a dog
// eg. sign up for puppy training lessons
}
case CAT:
{
// do cat stuff
}
default:
throw new Exception("Invalid Animal");
}
}
private static Animal getSomeAnimal() {
Animal animal;
Random randomGenerator = new Random();
int randomInt = randomGenerator.nextInt(100);
if (randomInt < 50) {
animal = new Dog("Rover");
}
else {
animal = new Cat("Tiddles");
}
return animal;
}
}
Of course having biteleash() in a Cat doesn't make sense, for you don't walk cats on a leash. So Animal shouldn't have biteleash(). Maybe you should put a method like playWith() in an Animal, in which Dogs would biteleash(). What I'm trying to say is you probably need to be more general. You shouldn't care if it is a dog to manually call biteleash(). Adding a Ferret to your Zoo would require adding the possibility that the animal is a Ferret, since they can also biteleash().
And maybe a method shouldTerminate(), which returns true in Cats. You will probably want to terminate also on a Tortoise in a while.
Generally, People consider it bad practice, if adding a new subclass would require changes in code using this class.
If I may, this is a highly impractical way to do this, I'm not sure what you are after but instanceof is going to be tedious, what you end up with is high coupling which is a no go when doing OOD.
Here is what I'd do:
First, get rid of class Animal and make it an interface as following
public interface Animal {
public String getName();
public void makeNoise();
public void performAggression();
}
then in dog:
public class Dog implements Animal {
private String name;
public Dog(String name) {
this.name = name;
}
#Override
public String getName() {
return name;
}
#Override
public void makeNoise() {
System.out.println("Woof");
}
#Override
public void performAggression(){
biteLeash();
}
private void biteLeash() {
System.out.println("Leash snapped!");
}
}
lastly, the cat:
public class Cat implements Animal {
private String name;
public cat(String name) {
this.name = name;
}
#Override
public String getName() {
return name;
}
#Override
public void makeNoise() {
System.out.println("Meow");
}
#Override
public void performAggression(){
hiss();
}
private void hiss() {
System.out.println("Hisssssss");
}
}
This way you can in you main class just do as following:
public class test{
public test(){
dog = new Dog("King");
cat = new Cat("MissPrincess");
}
public void performAggression(Animal animal){
animal.performAggression();
}
The bonus you get is, you can pass whatever class you want to a method, as long as they implements the same interface, as shown in the test class above in the method performAggression(Animal animal)
All the test class needs to know is those 3 methods, everything else can be done internally in the respective classes without test class needs to know anything about it, hence the "private" visibility on the biteLeash() and hiss() methods.
You end up with a very low coupling and easy to edit later on.
By doing this you effectively also achieve high cohesion because you don't have to get involved in mile long if/ifelse/ifelse...(so on) to determine what kind of class you are dealing with.
Operator instanceof tends to scale well only when applied to interfaces. The reason is that an interface partitions your domain in two: some objects are instances of classes which implement the interface, and the others are not. There is very likely no way that introducing a new class will break your current algorithms that rely on if (x instanceof ISomething) because the new class will either implement ISomething or not. If it does, the if body should cast x to ISomething and make good use of it; if it doesn't then the body of the if is probably of no interest to x.
This is different from the approach in which instanceof is applied to classes. For instance, seals do bark but they are not dogs: you cannot inherit Seal from Dog or viceversa. Hence, as you hinted, you are aware of the fact that if you use instanceof to check whether you can make x bark, you may end up with abominations like this:
if (x instanceof Dog) {
((Dog)x).bark();
}
else if (x instanceof Seal) {
((Seal)x).bark();
}
The solution is to have an interface ICanBark and test for it:
if (x instanceof ICanBark) {
((ICanBark)x).bark();
}
This scales well if you add more animals, whether they can bark or not. But it doesn't scale well if you want to add more noises, because you may be tempted to introduce more interfaces like ICanMeow and the like.
The solution is avoid to be in that situation; ICanBark and ICanMeow are obviously the same behavior IMakeNoise so that there is a single interface implemented by Dog, Cat and Seal.
I'm not a fan of the animal/dog/cat/noise example in the context of polymorphism. Instead I'll show you a real world example of a component system I was working on some time ago. In a component system, components are installed on entities to give them additional behavior. For instance, a monster in a videogame is an entity with some component installed (this stuff is inspired from the Unity 5 engine):
IAudioSource
IRenderer
IMovementAI
ILiving
The four classes that may implement that behaviours may well be something along the lines of:
ScaryGruntingSound
MeshOpenGLRender
StupidQuadrupedAI
Armorless
If you have a collection of entities then it is then totally acceptable (and it is going to scale well) if you instanceof for the interfaces:
for (Entity e : entities) {
for (Component c : e.getComponents()) {
if (c instanceof IAudioSource) {
((IAudioSource)c).play();
}
...
if (c instanceof IUserInput) {
((IUserInput)c).poll();
}
}
}
Since monsters are not controlled by the player, c instanceof IUserInput fails and everybody is happy. The reason why this use of instanceof rocks and the ICanBark/ICanMeow sucks is because IAudioSource/IRenderer/IMovementAI/ILiving are four totally unrelated aspects of what it means to be a monster, while ICanBark/ICanMeow are two manifestations of the same aspect (and should be instead handled by merging them into IMakeNoise).
Edit
I did consider having biteleash() in Animal which does nothing, and overriding it in Dog
It is a clunky solution and I believe it could only be motivated by performance reasons. If I'm not mistaken, Swing for Java uses such a pattern occasionally.
This question already has answers here:
Java - Method name collision in interface implementation
(7 answers)
Closed 8 years ago.
Shortly I came across an oddity, I can't explain to myself. The real-world problem is already worked around, I'm just curious if there is an satisfying answer I didn't find.
Imagine you have to write a class that implements the following interface from some framework you are using:
interface Interface1 {
String method();
}
So far so good. Now you introduce a second framework and it would be rather useful if your class would implement a second interface:
interface Interface2 {
Long method();
}
That's the point where the problem arises:
class ThatsTheProblem implements Interface1, Interface2 {
public ???? method() {
// ...
}
}
Any ideas?
Just for your information: The real-world problem is based on an abstract-dao-pattern where some entities had Long ids, others had UUID ids.
Short answer: you can't.
What you can do is provide a view that implements one or the other interface. For instance:
public class OnePossibleSolution { // no "implements"
private String interface1Method() {
return "whatever";
}
public Interface1 asInterface1() {
return new Interface1() {
#Override
String method() {
return interface1Method();
}
}
}
// ditto for Interface2...
This is probably the most Java-idiomatic way to solve the problem. It's what Map does when you want to iterate over its elements, for instance. Rather than try to solve the problem of being an Iterable<K>, Iterable<V> and Iterable<Map.Entry<K,V>>, it provides three views:
keySet()
values()
entrySet()
Each of those returns a respective collection, which implements the appropriate Iterable<...> interface.
Two of the components of a method declaration comprise the method signature—the method's name and the parameter types. These methods have the same signature, therefore cannot be implemented by one class.
Remember that in Java, you don't neccesary have to store the result of a method. If your ThatsTheProblem class compiled, and you had a class with this code, to which version of the method would invoke?
ThatsTheProblem ttp = new ThatsTheProblem();
ttp.method();
It is clearly impossible to create one object that implements two conflicting interfaces. However, it is possible for one object to provide two different facades, each implementing conflicting interfaces.
Note here that the two facades refer to common instance variables of the one object so they do, essentially, represent the same object.
public interface Interface1 {
String method();
}
public interface Interface2 {
Long method();
}
public class DiMorph {
String forInterface1 = "Number nine";
Long forInterface2 = 9L;
public Interface1 asInterface1() {
return new AsInterface1();
}
private class AsInterface1 implements Interface1 {
#Override
public String method() {
return forInterface1;
}
}
public Interface2 asInterface2() {
return new AsInterface2();
}
private class AsInterface2 implements Interface2 {
#Override
public Long method() {
return forInterface2;
}
}
}
public void testInterface1(Interface1 i1) {
}
public void testInterface2(Interface2 i2) {
}
public void test() {
DiMorph m = new DiMorph();
testInterface1 (m.asInterface1());
testInterface2 (m.asInterface2());
}
To quote #Andreas, this is simply impossible.
Imagine you have two workers, Alice and Bob, with two managers, Cathy and Dave. Cathy expects Alice to implement the Work() method and return a Java application. Dave, on the other hand, expects Bob to implement the Work() method and return a C++ library. What your question suggests is to introduce a new worker Eric who can do the Work() of Alice and Bob at the same time. What actually happens is that Eric is too overloaded to compile.
I would like to perform several operations based on the type of an object and without using instanceof. At first I was thinking of overloading methods based on types (as seen below), and thought that maybe Java would choose the method appropriately (based on most specific class of object).
import java.util.ArrayList;
import java.util.List;
public class TestA {
public static void main(String[] args)
{
List<Object> list = new ArrayList();
list.add(new A());
list.add(new B());
list.add(new C());
list.add(new Object());
TestA tester = new TestA();
for(Object o: list)
{
tester.print(o);
}
}
private void print(A o)
{
System.out.println("A");
}
private void print(B o)
{
System.out.println("B");
}
private void print(C o)
{
System.out.println("C");
}
private void print(Object o)
{
System.out.println("Object");
}
}
class A {
}
class B extends A {
}
class C {
}
The output is:
Object
Object
Object
Object
However the output I'm after is:
A
B
C
Object
Is there a way to make Java choose the method based on the most specific type of the parameter object?
If not, what alternatives can I look at for such functionality, without the aid of instanceof
I was actually trying to simulate the visitor pattern however it seems, what makes visitor pattern work is because of the double dispatch, which makes the parameter being "accepted" be in the correct type during function call, particularly, visitor.accept(this) in class A causes the function visitor.accept(A o) be called.
I'm honestly against instanceof because I've read using it is bad practice; in this case, would it still be bad practice?
Well my answer would be to make classes A,B and C implement a common interface.
And then each of them can have their own specific implementations of this interface.
This way, you can call the same method for all the objects(thus avoiding overloaded methods), and also ensure custom functionality based on the type of the object(i.e the class from which it was instantiated).
This answer considers that modifying given classes and their relationship is not an option.
Is there a way to make Java choose the method based on the most
specific type of the parameter object?
Java compiler cannot cast this for you because maybe that's not what you want (in your case that's what you want, but maybe other people don't want this behavior and they would be no solution for them). Since you're passing an Object reference to print(), the compiler will call print(Object).
If not, what alternatives can I look at for such functionality,
without the aid of instanceof
You can wrap your Object with its type in a wrapper class, e.g.:
public class ObjectWrapper {
private final Object object;
private final int type;
}
This way you can safely cast to the type of the Object without using instanceof. Although this IMHO is more complicated than simply using instanceof, and actually it only creates your own instanceof...
I'm honestly against instanceof because I've read using it is bad
practice; in this case, would it still be bad practice?
In programming, nothing is always a bad practice. Everything depends on the situation. In this situation I think you can use instanceof and do unsafe casting because the design requires so. And anyway, if instanceof operator exists in the language, is because it's used. If instanceof was always a bad practice, it wouldn't exist as part of the language. See this and this.
I was actually trying to simulate the visitor pattern however it
seems, what makes visitor pattern work is because of the double
dispatch, which makes the parameter being "accepted" be in the correct
type during function call, particularly, visitor.accept(this) in class
A causes the function visitor.accept(A o) be called.
Check my second link for cons on using the visitor pattern.
Method Overloading is a compile time polymorphism, in your for loop , you have declared o as Object and hence always print(Object o) will be called.
Solution:
Use Dynamic Polymorphism:
class A{
void print(){
System.out.println('in A');
}
}
class B{
void print(){
System.out.println('in B');
}
}
and the for loop
for(Object o: list){
o.print();
}
Consider Visitor design pattern http://en.wikipedia.org/wiki/Visitor_pattern. Though it will need changes to A,B,C otherwise there is no other way.
I would just use instanceof here. It's simple and clear.
It's not like there is a hard rule to not use instanceof. There are no hard rules :) Lots of use of instanceof may be a sign that you could change things to make the compiler do more work for you. Whether that is actually worth doing needs to be looked at case by case. In your case you mention you aren't able to change the classes in question, so it's not even an option.
package com.ank.says;
import java.util.ArrayList;
import java.util.List;
class Base{
public void print(){
System.out.println("Base");
}
}
class A extends Base{
#Override
public void print() {
System.out.println("A");
}
}
class B extends Base{
#Override
public void print(){
System.out.println("B");
}
}
class C extends Base{
#Override
public void print(){
System.out.println("C");
}
}
public class TestPlayGround {
public static void main(String[] args) throws ParseException {
List<Base> list = new ArrayList<Base>();
list.add(new A());
list.add(new B());
list.add(new C());
list.add(new Base());
TestPlayGround tester = new TestPlayGround();
for(Base o: list)
{
o.print();
}
}
}
Output : -
A
B
C
Base
After reading above answer
One solution which i can suggest would be to use check the object type by using o.getClass and continue
However many better solutions are posted. I totally agree with what #krisna kishor shetty said
What pops out of my mind without use instanceof now is:
Use a common interface for all of them to share a common method:
Code:
public interface YourInterface {
public void doStuff();
}
public class A implements YourInterface {
#Override
public doStuff() {
System.out.print("A");
}
}
public class B implements YourInterface {
#Override
public doStuff() {
System.out.print("A");
}
}
List<YourInterface> list = new ArrayList<YourInterface>();
list.add(new A());
list.add(new B());
for(YourInterface e: list)
{
e.doStuff();
}
Use an Enum declaring an abstract method tha will be implemented by every type you have:
Code:
public enum YourEnum {
TYPE1 {
#Override
public void doStuff() {
System.out.print("Type 1");
},
TYPE2 {
#Override
public void doStuff() {
System.out.print("Type 2");
};
public abstract void doStuff();
}
List<YourEnum> list = new ArrayList<YourEnum>();
list.add(YourEnum.TYPE1);
list.add(YourEnum.TYPE2);
for(YourEnum e: list)
{
e.doStuff();
}
From my point of view it's not the question whether or not use instanceof. The question is how to minimise the impact gained by this situation. So I would recommend instance adapter here in case there are several operations to deal with. That way you can at least avoid spreading that complexity all over the system:
public abstract class Adapter {
public abstract void print();
public static Adapter wrap(Object o) {
if (o instanceof A) {
return new AAdapter();
}
if (o instanceof B) {
return new BAdapter();
}
return new ObjectAdapter():
}
public class AAdapter {
public void print() {
System.out.printLn("A");
}
}
Then loop:
for (Object o: things) {
Adapter.wrap(o).print();
}
Of course our Adapter will have a reference to the wrapped object as the method name implies. That way you get a coding model close to direct modification of those classes.
The only examples of polymorphic method overriding I ever see involve methods that take no parameters, or at least have identical parameter lists. Consider the common Animal/Dog/Cat example:
public abstract class Animal
{
public abstract void makeSound();
}
public class Dog extends Animal
{
public void makeSound()
{
System.out.println("woof");
}
}
public class Cat extends Animal
{
public void makeSound()
{
System.out.println("meow");
}
}
public class ListenToAnimals
{
public static void main(String[] args)
{
AnimalFactory factory = new AnimalFactory();
Animal a = factory.getRandomAnimal(); // generate a dog or cat at random
a.makeSound();
}
}
In this case, everything works out just fine. Now let's add another method that gets partially implemented in the abstract class while getting the more specific behavior in the subclasses:
public abstract class Animal
{
public abstract void makeSound();
public void speak(String name)
{
System.out.println("My name is " + name);
}
}
public class Dog extends Animal
{
public void makeSound()
{
System.out.println("woof");
}
public void speak(String name)
{
super.speak(name);
System.out.println("I'm a dog");
}
}
public class Cat extends Animal
{
public void makeSound()
{
System.out.println("meow");
}
public void speak(String name, int lives)
{
super.speak(name);
System.out.println("I'm a cat and I have " + lives + " lives");
}
}
public class ListenToAnimals
{
public static void main(String[] args)
{
AnimalFactory factory = new AnimalFactory();
Animal a = factory.getRandomAnimal(); // generate a dog or cat at random
a.makeSound();
// a.speak(NOW WHAT?
}
}
In that last (commented) line of the main method, I don't know what to put there because I don't know what type of Animal I have. I didn't have to worry about this before because makeSound() didn't take any arguments. But speak() does, and the arguments depend on the type of Animal.
I've read that some languages, such as Objective-C, allow for variable argument lists, so an issue like this should never arise. Is anyone aware of a good way to implement this kind of thing in Java?
You are confusing method overriding and method overloading. In your example the Cat class has two methods:
public void speak(String name) // It gets this from its super class
public void speak(String name, int lives)
Overloading is a way to define methods with similar functions but different parameters. There would be no difference if you had named the method thusly:
public void speakWithLives(String name, int lives)
To avoid confusion the recommendation in java is to use the #Override annotation when you are attempting to override a method. Therefore:
// Compiles
#Override
public void speak(String name)
// Doesn't compile - no overriding occurs!
#Override
public void speak(String name, int lives)
EDIT: Other answers mention this but I am repeating it for emphasis. Adding the new method made the Cat class no longer able to be represented as an Animal in all cases, thus removing the advantage of polymorphism. To make use of the new method you would need to downcast it to the Cat type:
Animal mightBeACat = ...
if(mightBeACat instanceof Cat) {
Cat definitelyACat = (Cat) mightBeACat;
definitelyACat.speak("Whiskers", 9);
} else {
// Definitely not a cat!
mightBeACat.speak("Fred");
}
The code inspection tool in my IDE puts a warning on the instanceof as the keyword indicates possible polymorphic abstraction failure.
Your example Cat isn't polymorphic anymore, since you have to know it's a Cat to pass that parameter. Even if Java allowed it, how would you use it?
As far as I know java doesn't allow you to do that. speak(name, lives) is now just the Cat's function. Some languages do allow this type of flexibility. To force java to allow this, you can make the paramater an array of objects or some other collection.
However, consider that when you call speak, you now must know which parameters to pass in regardless, so the point is somewhat moot.
When you call a polymorphic method as:
a.speak("Gerorge");
You don't need to know what type of Animal has instantiated because this is the objective of polymorphism. Also since you have user the sentence:
super.speak(name);
Both Cat an Dog will have the behavior of Animal plus the own behavior.
You can do
public void speak(Map ... mappedData)
{
System.out.println("My name is " + mappedData.get("name")+ " and I have "+mappedData.get("lives");
}
However, I would advise making lives an instance variable of Cat and have your factory pass a default value (or have the constructor have a default parameter for it).
In this case best way is to use a DTO,
public class SpeakDTO
{
//use getters and setters when you actually implement this
String name;
int lives;
}
public class Dog extends Animal
{
public void speak(SpeakDTO dto)
{
super.speak(dto.name);
System.out.println("I'm a dog");
}
}
public class Cat extends Animal
{
public void speak(SpeakDTO dto)
{
super.speak(dto.name);
System.out.println("I'm a cat and I have " + dto.lives + " lives");
}
}
public class ListenToAnimals
{
public static void main(String[] args)
{
AnimalFactory factory = new AnimalFactory();
Animal a = factory.getRandomAnimal(); // generate a dog or cat at random
a.makeSound();
SpeakDTO dto = new SpeakDTO();
dto.name = "big cat";
dto.lives = 7;
a.speak(dto);
}
}
If you want to make a call like that, you could use reflection to get the class:
if (a.getclass() == Cat.class) {
// speak like a cat
} else if (a.getclass() == Dog.class) {
.
.
.
Of course this might not be the best design, and reflection should be used with care.
Java also has variable argument lists, but I'd argue that's not the "best" way to do it, at least not in all circumstances.
When subclasses have behavior that isn't defined by the interface, you don't have many options in Java that aren't verbose or a bit wonky.
You could have a speak () that takes a marker interface and delegate arg construction to a factory. You could pass a parameter map. You could use varargs.
Ultimately, you need to know what to pass to the method, no matter what language.
I agree with the comments about how you've really broken polymorphism if you must know the type of object before you can call the speak method. If you absolutely MUST have access to both speak methods, here is one way you could implement it.
public class Animal {
public void speak(String name) {
throw new UnsupportedOperationException("Speak without lives not implemented");
}
public void speak(String name, int lives) {
throw new UnsupportedOperationException("Speak with lives not implemented");
}
}
public class Dog extends Animal {
public void speak(String name) {
System.out.println("My name is " + name);
System.out.println("I'm a dog");
}
}
public class Cat extends Animal {
public void speak(String name, int lives) {
System.out.println("My name is " + name);
System.out.println("I'm a cat and I have " + lives + " lives");
}
}
Alternately you can put the UnsupportedOperationExceptions into the child classes (or you might want to used a checked exception). I'm not actually advocating either of these, but I think this is the closest way to implement what you requested, and I have actually seen systems that used something like this.
I read this question and thought that would easily be solved (not that it isn't solvable without) if one could write:
#Override
public String toString() {
return super.super.toString();
}
I'm not sure if it is useful in many cases, but I wonder why it isn't and if something like this exists in other languages.
What do you guys think?
EDIT:
To clarify: yes I know, that's impossible in Java and I don't really miss it. This is nothing I expected to work and was surprised getting a compiler error. I just had the idea and like to discuss it.
It violates encapsulation. You shouldn't be able to bypass the parent class's behaviour. It makes sense to sometimes be able to bypass your own class's behaviour (particularly from within the same method) but not your parent's. For example, suppose we have a base "collection of items", a subclass representing "a collection of red items" and a subclass of that representing "a collection of big red items". It makes sense to have:
public class Items
{
public void add(Item item) { ... }
}
public class RedItems extends Items
{
#Override
public void add(Item item)
{
if (!item.isRed())
{
throw new NotRedItemException();
}
super.add(item);
}
}
public class BigRedItems extends RedItems
{
#Override
public void add(Item item)
{
if (!item.isBig())
{
throw new NotBigItemException();
}
super.add(item);
}
}
That's fine - RedItems can always be confident that the items it contains are all red. Now suppose we were able to call super.super.add():
public class NaughtyItems extends RedItems
{
#Override
public void add(Item item)
{
// I don't care if it's red or not. Take that, RedItems!
super.super.add(item);
}
}
Now we could add whatever we like, and the invariant in RedItems is broken.
Does that make sense?
I think Jon Skeet has the correct answer. I'd just like to add that you can access shadowed variables from superclasses of superclasses by casting this:
interface I { int x = 0; }
class T1 implements I { int x = 1; }
class T2 extends T1 { int x = 2; }
class T3 extends T2 {
int x = 3;
void test() {
System.out.println("x=\t\t" + x);
System.out.println("super.x=\t\t" + super.x);
System.out.println("((T2)this).x=\t" + ((T2)this).x);
System.out.println("((T1)this).x=\t" + ((T1)this).x);
System.out.println("((I)this).x=\t" + ((I)this).x);
}
}
class Test {
public static void main(String[] args) {
new T3().test();
}
}
which produces the output:
x= 3
super.x= 2
((T2)this).x= 2
((T1)this).x= 1
((I)this).x= 0
(example from the JLS)
However, this doesn't work for method calls because method calls are determined based on the runtime type of the object.
I think the following code allow to use super.super...super.method() in most case.
(even if it's uggly to do that)
In short
create temporary instance of ancestor type
copy values of fields from original object to temporary one
invoke target method on temporary object
copy modified values back to original object
Usage :
public class A {
public void doThat() { ... }
}
public class B extends A {
public void doThat() { /* don't call super.doThat() */ }
}
public class C extends B {
public void doThat() {
Magic.exec(A.class, this, "doThat");
}
}
public class Magic {
public static <Type, ChieldType extends Type> void exec(Class<Type> oneSuperType, ChieldType instance,
String methodOfParentToExec) {
try {
Type type = oneSuperType.newInstance();
shareVars(oneSuperType, instance, type);
oneSuperType.getMethod(methodOfParentToExec).invoke(type);
shareVars(oneSuperType, type, instance);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static <Type, SourceType extends Type, TargetType extends Type> void shareVars(Class<Type> clazz,
SourceType source, TargetType target) throws IllegalArgumentException, IllegalAccessException {
Class<?> loop = clazz;
do {
for (Field f : loop.getDeclaredFields()) {
if (!f.isAccessible()) {
f.setAccessible(true);
}
f.set(target, f.get(source));
}
loop = loop.getSuperclass();
} while (loop != Object.class);
}
}
I don't have enough reputation to comment so I will add this to the other answers.
Jon Skeet answers excellently, with a beautiful example. Matt B has a point: not all superclasses have supers. Your code would break if you called a super of a super that had no super.
Object oriented programming (which Java is) is all about objects, not functions. If you want task oriented programming, choose C++ or something else. If your object doesn't fit in it's super class, then you need to add it to the "grandparent class", create a new class, or find another super it does fit into.
Personally, I have found this limitation to be one of Java's greatest strengths. Code is somewhat rigid compared to other languages I've used, but I always know what to expect. This helps with the "simple and familiar" goal of Java. In my mind, calling super.super is not simple or familiar. Perhaps the developers felt the same?
There's some good reasons to do this. You might have a subclass which has a method which is implemented incorrectly, but the parent method is implemented correctly. Because it belongs to a third party library, you might be unable/unwilling to change the source. In this case, you want to create a subclass but override one method to call the super.super method.
As shown by some other posters, it is possible to do this through reflection, but it should be possible to do something like
(SuperSuperClass this).theMethod();
I'm dealing with this problem right now - the quick fix is to copy and paste the superclass method into the subsubclass method :)
In addition to the very good points that others have made, I think there's another reason: what if the superclass does not have a superclass?
Since every class naturally extends (at least) Object, super.whatever() will always refer to a method in the superclass. But what if your class only extends Object - what would super.super refer to then? How should that behavior be handled - a compiler error, a NullPointer, etc?
I think the primary reason why this is not allowed is that it violates encapsulation, but this might be a small reason too.
I think if you overwrite a method and want to all the super-class version of it (like, say for equals), then you virtually always want to call the direct superclass version first, which one will call its superclass version in turn if it wants.
I think it only makes rarely sense (if at all. i can't think of a case where it does) to call some arbitrary superclass' version of a method. I don't know if that is possible at all in Java. It can be done in C++:
this->ReallyTheBase::foo();
At a guess, because it's not used that often. The only reason I could see using it is if your direct parent has overridden some functionality and you're trying to restore it back to the original.
Which seems to me to be against OO principles, since the class's direct parent should be more closely related to your class than the grandparent is.
Calling of super.super.method() make sense when you can't change code of base class. This often happens when you are extending an existing library.
Ask yourself first, why are you extending that class? If answer is "because I can't change it" then you can create exact package and class in your application, and rewrite naughty method or create delegate:
package com.company.application;
public class OneYouWantExtend extends OneThatContainsDesiredMethod {
// one way is to rewrite method() to call super.method() only or
// to doStuff() and then call super.method()
public void method() {
if (isDoStuff()) {
// do stuff
}
super.method();
}
protected abstract boolean isDoStuff();
// second way is to define methodDelegate() that will call hidden super.method()
public void methodDelegate() {
super.method();
}
...
}
public class OneThatContainsDesiredMethod {
public void method() {...}
...
}
For instance, you can create org.springframework.test.context.junit4.SpringJUnit4ClassRunner class in your application so this class should be loaded before the real one from jar. Then rewrite methods or constructors.
Attention: This is absolute hack, and it is highly NOT recommended to use but it's WORKING! Using of this approach is dangerous because of possible issues with class loaders. Also this may cause issues each time you will update library that contains overwritten class.
#Jon Skeet Nice explanation.
IMO if some one wants to call super.super method then one must be want to ignore the behavior of immediate parent, but want to access the grand parent behavior.
This can be achieved through instance Of. As below code
public class A {
protected void printClass() {
System.out.println("In A Class");
}
}
public class B extends A {
#Override
protected void printClass() {
if (!(this instanceof C)) {
System.out.println("In B Class");
}
super.printClass();
}
}
public class C extends B {
#Override
protected void printClass() {
System.out.println("In C Class");
super.printClass();
}
}
Here is driver class,
public class Driver {
public static void main(String[] args) {
C c = new C();
c.printClass();
}
}
Output of this will be
In C Class
In A Class
Class B printClass behavior will be ignored in this case.
I am not sure about is this a ideal or good practice to achieve super.super, but still it is working.
Look at this Github project, especially the objectHandle variable. This project shows how to actually and accurately call the grandparent method on a grandchild.
Just in case the link gets broken, here is the code:
import lombok.val;
import org.junit.Assert;
import org.junit.Test;
import java.lang.invoke.*;
/*
Your scientists were so preoccupied with whether or not they could, they didn’t stop to think if they should.
Please don't actually do this... :P
*/
public class ImplLookupTest {
private MethodHandles.Lookup getImplLookup() throws NoSuchFieldException, IllegalAccessException {
val field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
field.setAccessible(true);
return (MethodHandles.Lookup) field.get(null);
}
#Test
public void test() throws Throwable {
val lookup = getImplLookup();
val baseHandle = lookup.findSpecial(Base.class, "toString",
MethodType.methodType(String.class),
Sub.class);
val objectHandle = lookup.findSpecial(Object.class, "toString",
MethodType.methodType(String.class),
// Must use Base.class here for this reference to call Object's toString
Base.class);
val sub = new Sub();
Assert.assertEquals("Sub", sub.toString());
Assert.assertEquals("Base", baseHandle.invoke(sub));
Assert.assertEquals(toString(sub), objectHandle.invoke(sub));
}
private static String toString(Object o) {
return o.getClass().getName() + "#" + Integer.toHexString(o.hashCode());
}
public class Sub extends Base {
#Override
public String toString() {
return "Sub";
}
}
public class Base {
#Override
public String toString() {
return "Base";
}
}
}
Happy Coding!!!!
I would put the super.super method body in another method, if possible
class SuperSuperClass {
public String toString() {
return DescribeMe();
}
protected String DescribeMe() {
return "I am super super";
}
}
class SuperClass extends SuperSuperClass {
public String toString() {
return "I am super";
}
}
class ChildClass extends SuperClass {
public String toString() {
return DescribeMe();
}
}
Or if you cannot change the super-super class, you can try this:
class SuperSuperClass {
public String toString() {
return "I am super super";
}
}
class SuperClass extends SuperSuperClass {
public String toString() {
return DescribeMe(super.toString());
}
protected String DescribeMe(string fromSuper) {
return "I am super";
}
}
class ChildClass extends SuperClass {
protected String DescribeMe(string fromSuper) {
return fromSuper;
}
}
In both cases, the
new ChildClass().toString();
results to "I am super super"
It would seem to be possible to at least get the class of the superclass's superclass, though not necessarily the instance of it, using reflection; if this might be useful, please consider the Javadoc at http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass()
public class A {
#Override
public String toString() {
return "A";
}
}
public class B extends A {
#Override
public String toString() {
return "B";
}
}
public class C extends B {
#Override
public String toString() {
return "C";
}
}
public class D extends C {
#Override
public String toString() {
String result = "";
try {
result = this.getClass().getSuperclass().getSuperclass().getSuperclass().newInstance().toString();
} catch (InstantiationException ex) {
Logger.getLogger(D.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(D.class.getName()).log(Level.SEVERE, null, ex);
}
return result;
}
}
public class Main {
public static void main(String... args) {
D d = new D();
System.out.println(d);
}
}
run:
A
BUILD SUCCESSFUL (total time: 0 seconds)
I have had situations like these when the architecture is to build common functionality in a common CustomBaseClass which implements on behalf of several derived classes.
However, we need to circumvent common logic for specific method for a specific derived class. In such cases, we must use a super.super.methodX implementation.
We achieve this by introducing a boolean member in the CustomBaseClass, which can be used to selectively defer custom implementation and yield to default framework implementation where desirable.
...
FrameworkBaseClass (....) extends...
{
methodA(...){...}
methodB(...){...}
...
methodX(...)
...
methodN(...){...}
}
/* CustomBaseClass overrides default framework functionality for benefit of several derived classes.*/
CustomBaseClass(...) extends FrameworkBaseClass
{
private boolean skipMethodX=false;
/* implement accessors isSkipMethodX() and setSkipMethodX(boolean)*/
methodA(...){...}
methodB(...){...}
...
methodN(...){...}
methodX(...){
if (isSkipMethodX()) {
setSKipMethodX(false);
super.methodX(...);
return;
}
... //common method logic
}
}
DerivedClass1(...) extends CustomBaseClass
DerivedClass2(...) extends CustomBaseClass
...
DerivedClassN(...) extends CustomBaseClass...
DerivedClassX(...) extends CustomBaseClass...
{
methodX(...){
super.setSKipMethodX(true);
super.methodX(...);
}
}
However, with good architecture principles followed in framework as well as app, we could avoid such situations easily, by using hasA approach, instead of isA approach. But at all times it is not very practical to expect well designed architecture in place, and hence the need to get away from solid design principles and introduce hacks like this.
Just my 2 cents...
IMO, it's a clean way to achieve super.super.sayYourName() behavior in Java.
public class GrandMa {
public void sayYourName(){
System.out.println("Grandma Fedora");
}
}
public class Mama extends GrandMa {
public void sayYourName(boolean lie){
if(lie){
super.sayYourName();
}else {
System.out.println("Mama Stephanida");
}
}
}
public class Daughter extends Mama {
public void sayYourName(boolean lie){
if(lie){
super.sayYourName(lie);
}else {
System.out.println("Little girl Masha");
}
}
}
public class TestDaughter {
public static void main(String[] args){
Daughter d = new Daughter();
System.out.print("Request to lie: d.sayYourName(true) returns ");
d.sayYourName(true);
System.out.print("Request not to lie: d.sayYourName(false) returns ");
d.sayYourName(false);
}
}
Output:
Request to lie: d.sayYourName(true) returns Grandma Fedora
Request not to lie: d.sayYourName(false) returns Little girl Masha
I think this is a problem that breaks the inheritance agreement.
By extending a class you obey / agree its behavior, features
Whilst when calling super.super.method(), you want to break your own obedience agreement.
You just cannot cherry pick from the super class.
However, there may happen situations when you feel the need to call super.super.method() - usually a bad design sign, in your code or in the code you inherit !
If the super and super super classes cannot be refactored (some legacy code), then opt for composition over inheritance.
Encapsulation breaking is when you #Override some methods by breaking the encapsulated code.
The methods designed not to be overridden are marked
final.
In C# you can call a method of any ancestor like this:
public class A
internal virtual void foo()
...
public class B : A
public new void foo()
...
public class C : B
public new void foo() {
(this as A).foo();
}
Also you can do this in Delphi:
type
A=class
procedure foo;
...
B=class(A)
procedure foo; override;
...
C=class(B)
procedure foo; override;
...
A(objC).foo();
But in Java you can do such focus only by some gear. One possible way is:
class A {
int y=10;
void foo(Class X) throws Exception {
if(X!=A.class)
throw new Exception("Incorrect parameter of "+this.getClass().getName()+".foo("+X.getName()+")");
y++;
System.out.printf("A.foo(%s): y=%d\n",X.getName(),y);
}
void foo() throws Exception {
System.out.printf("A.foo()\n");
this.foo(this.getClass());
}
}
class B extends A {
int y=20;
#Override
void foo(Class X) throws Exception {
if(X==B.class) {
y++;
System.out.printf("B.foo(%s): y=%d\n",X.getName(),y);
} else {
System.out.printf("B.foo(%s) calls B.super.foo(%s)\n",X.getName(),X.getName());
super.foo(X);
}
}
}
class C extends B {
int y=30;
#Override
void foo(Class X) throws Exception {
if(X==C.class) {
y++;
System.out.printf("C.foo(%s): y=%d\n",X.getName(),y);
} else {
System.out.printf("C.foo(%s) calls C.super.foo(%s)\n",X.getName(),X.getName());
super.foo(X);
}
}
void DoIt() {
try {
System.out.printf("DoIt: foo():\n");
foo();
Show();
System.out.printf("DoIt: foo(B):\n");
foo(B.class);
Show();
System.out.printf("DoIt: foo(A):\n");
foo(A.class);
Show();
} catch(Exception e) {
//...
}
}
void Show() {
System.out.printf("Show: A.y=%d, B.y=%d, C.y=%d\n\n", ((A)this).y, ((B)this).y, ((C)this).y);
}
}
objC.DoIt() result output:
DoIt: foo():
A.foo()
C.foo(C): y=31
Show: A.y=10, B.y=20, C.y=31
DoIt: foo(B):
C.foo(B) calls C.super.foo(B)
B.foo(B): y=21
Show: A.y=10, B.y=21, C.y=31
DoIt: foo(A):
C.foo(A) calls C.super.foo(A)
B.foo(A) calls B.super.foo(A)
A.foo(A): y=11
Show: A.y=11, B.y=21, C.y=31
It is simply easy to do. For instance:
C subclass of B and B subclass of A. Both of three have method methodName() for example.
public abstract class A {
public void methodName() {
System.out.println("Class A");
}
}
public class B extends A {
public void methodName() {
super.methodName();
System.out.println("Class B");
}
// Will call the super methodName
public void hackSuper() {
super.methodName();
}
}
public class C extends B {
public static void main(String[] args) {
A a = new C();
a.methodName();
}
#Override
public void methodName() {
/*super.methodName();*/
hackSuper();
System.out.println("Class C");
}
}
Run class C Output will be:
Class A
Class C
Instead of output:
Class A
Class B
Class C
If you think you are going to be needing the superclass, you could reference it in a variable for that class. For example:
public class Foo
{
public int getNumber()
{
return 0;
}
}
public class SuperFoo extends Foo
{
public static Foo superClass = new Foo();
public int getNumber()
{
return 1;
}
}
public class UltraFoo extends Foo
{
public static void main(String[] args)
{
System.out.println(new UltraFoo.getNumber());
System.out.println(new SuperFoo().getNumber());
System.out.println(new SuperFoo().superClass.getNumber());
}
public int getNumber()
{
return 2;
}
}
Should print out:
2
1
0
public class SubSubClass extends SubClass {
#Override
public void print() {
super.superPrint();
}
public static void main(String[] args) {
new SubSubClass().print();
}
}
class SuperClass {
public void print() {
System.out.println("Printed in the GrandDad");
}
}
class SubClass extends SuperClass {
public void superPrint() {
super.print();
}
}
Output: Printed in the GrandDad
The keyword super is just a way to invoke the method in the superclass.
In the Java tutorial:https://docs.oracle.com/javase/tutorial/java/IandI/super.html
If your method overrides one of its superclass's methods, you can invoke the overridden method through the use of the keyword super.
Don't believe that it's a reference of the super object!!! No, it's just a keyword to invoke methods in the superclass.
Here is an example:
class Animal {
public void doSth() {
System.out.println(this); // It's a Cat! Not an animal!
System.out.println("Animal do sth.");
}
}
class Cat extends Animal {
public void doSth() {
System.out.println(this);
System.out.println("Cat do sth.");
super.doSth();
}
}
When you call cat.doSth(), the method doSth() in class Animal will print this and it is a cat.