base class has a data-member which is an array of object A[] and an accessor method for that. I want to be able to over-ride the accessor to return a B[], where B is subclass of A.
In Java 5.0 on it will allow me to do that because arrays are co-variant, but I get a
ClassCastException when I try to something like the following:
class Business {
A[] clients;
A[] getClientList() { return clients; }
}
class DoctorBusiness extends Business {
B[] getClientList(){
return super.clients;
//this line thwoes a classcastexception
}
}
where Client corresponds to A and Patient corresponds to B and Patient extends Client.
How do I get round this ? I know that all the objects in the array are going to be of type B and would like to avoid having to cast down to Patient every-time I access array elements of clients
What about just
class A{}
class B extends A{}
public class Test<T extends A> {
T[] t;
public T[] get()
{
return t;
}
public static void main(String args[])
{
Test<B> t2 = new Test<B>();
B[] b = t2.get();
}
}
impossible.
you can use List<A>, cast it to List<B>, or have a generic List<T>. The performance should be very close to array.
See the comment I posted in your question. But if I am correct in understanding your question then the following applies:
A is not a sub type of B. That is why you are getting the exception. Based on what you are trying to do, it will not work.
I thought of a solution that will allow what you want. Enters the beautiful concept of the Interface!!! =D
public interface ICommon
{}
public class B extends A
{
protected B[] b;
public ICommon[] Get()
{
return b;
}
public ICommon[] GetAncestor()
{
return a;
}
}
public class A implements ICommon
{
protected A[] a;
public ICommon[] Get()
{
return a;
}
}
Now since they share a common interface. This will work as you wanted.
You will need to either expose methods that will allow you to use them by that type OR, you have to resort to casting when using them. That is the drawback
If you can change the super class, you might wish to retrofit it with generics as Steve B. suggests, or at least make the array creation overridable by the subclass:
class Super {
private A[] as;
protected A[] newDataArray(int length) {
return new A[length];
}
public A[] get() {
return as;
}
}
class Sub {
#Override protected B[] newDataArray(int length) {
return new B[length];
}
#Override public B[] get() {
return (B[]) super.get(); // we know it's a B[] because we created it
}
}
If you can't change the superclass, you can only do:
class Sub extends Super {
#Override public B[] get() {
A[] as = super.get();
return Arrays.copyOf(as, as.length, B[].class);
}
}
copyOf will fail with an ArrayStoreException should as contains something not assignable to B.
Covariance does not hold good for arrays and generics in Java because it kills static type safety. The only way to get around this design problem is to use separate lists in classes Business and DoctorBusiness.
Check out the "Arrays in C# and Java" section in this wikipedia page on Covariance
In boarding a plane you can upgrade/downgrade your class, but in Java or any usual object-oriented language you cannot downgrade a Fruit to be perceived as an Apple even though you can upgrade the view of an Apple as being viewed as a Fruit.
Fruit is a super class of apple and orange.
Fruit f;
Apple, Orange extend Fruit;
Apple a;
Orange b;
By common world sense, if you assigned f to apple,
f = apple;
you cannot return f as orange;
However,
If you had assigned a:
a = apple;
you would be able to return Fruit
Fruit get(){
return a;
}
You can return an apple as a Fruit, but not a Fruit as an apple, because what if f had been already assigned as an orange?
However, you may say, "Well B extends A is a one-to-one relationship, so I should have no worries about an instance of A being assigned to any other class other than a B." That is not how object-oriented language compilers see it. OO compilers do not have a relational model to enable it to inspect and restrict class extensions to 1-to-1.
Therefore, back to the question of OO principles. OO programming is an attitude. When you get your attitude right, you will not encounter such a dilemma because you would not even consider it.
Pardon me for saying this, that your encountering this issue signals that you are probably a visual basic ( or php or perl programmer) trying fit the linear programming attitude (as with all vb programmers) into the dimensionality of C# or Java. It is indeed frustrating both for the c#/java programmer and the vb programmer when both of them meet.
As an OO programmer, your visualization of the object hierarchy will spontaneously (some linguistically less discerning people would use the word "automatically") dictate your programming style. Just as your view of the fruit hierarchy would not even let you think of paying for apples when you actually have oranges in your cart.
Therefore, in the below example, you may set an instance of A to an instance of B and then return an instance of A.
But you cannot return an instance of A as an instance of B;
class A{}
class B extends A{}
public class Test {
A[] a;
B[] b;
public A[] get()
{
return a;
}
public void set(A[] a){
this.a = a;
}
// Illegal
public B[] getB(){
return a;
}
public static void main(String args[])
{
Test t2 = new Test();
B[] b = new B[0];
t2.set(b);
A[] a = t2.get();
}
}
If you do insist on returning B from an A instance, then both your concept of OO and your world view is broken.
Therefore, messr Cox's suggestion is correct. You have to use an interface as the contract declaration. You have to understand and have a spontaneous mental design of the program you are writing and the flow of contracts across your application. Just as you would have a spontaneous flow of contracts of fruit, vegetables, condiments, etc with the supermarket when you get your groceries.
You need to cease and desist attempting to get an instance B from its superclass instance A and redesign your attitude and mental process to spontaneously design your application that you need an interface.
interface Edible{};
class Fruit implements Edible{...}
class Apple extends Fruit {...}
Interface FoodAisle{
Edible get();
void set(Edible e)throws WrongFoodException;
}
class FruitSection implements FoodAisle{
Edible e;
public Edible get(){
}
}
class AppleBucket extends FruitSection{
Apple a;
public Apple get(){
return a;
}
public set(Edible e)
throws WrongFoodException{
if (!(e instanceof Apple)) throw WrongFoodException
e = e;
}
}
In designing a cross-food extension world view, you need to picture yourself as being able to ask the question - "what if they put a bunch oranges in the apple bucket in the fruit section?" Your worldview would jump up spontaneously to yell "I will make an exception complaint to the manager for misrepresenting oranges and being sold as apples". Similarly, whatever you are doing, if you persist in attempting to get a B from an A instance, it means you need to gain understanding of the business and processes for which you are programming, just as the manager need to have an understanding of food hierarchies.
It is imperative for programmers and data schema designers to have an expert knowledge of the processes and business for which they are programming.
You could also succumb to Steve B's suggestion of genericising your classes. If you choose to use generics, it means that
once you instantiate an aisle as for apples, you cannot attempt to get oranges from that aisle.
you are using generics because you wish to share routines among fruit buckets but you are not attempting the impossible miracle of turning oranges into apples.
.
class FruitSection<E extends Edible>{
E[] e;
public Edible get(){
}
void set(E e){
}
}
FruitSection<Fruit> fsect = new FruitSection<Fruit>();
Fruit[] ff = { .....};
fsect.set(ff);
AppleBucket<Apple> abuck = new FruitSection<Apple>();
Apple[] aa = { /* commalist of apples */};
abuck.set(aa);
placing apples into Fruit section is OK.
fsect.set(aa);
But placing any old Fruit in the apple bucket is not acceptable:
abuck.set(ff);
As usual, my typing too fast may yield some typos and misalignment. If so, pardon me.
Related
Consider class A
class A {
int i;
int j;
int k;
}
and here is the class B
class B {
int a;
int b;
int c;
}
I was wondering if java has any such ting which allows to write/define our own custom casting logic.
For e.g.
to cast class B's object into class A's object where
i -> a // i pointing to value of a
j -> b // j pointing to value of b
k -> c // k pointing to value of c
(I can customize the logic to whatever i wish)
I have a few heavy weight objects to "cast" into some other classes to use and i do not want to write a converter method for this.
(casting operates only on the object in consideration and does not create another object)
any thoughts/suggestions for this ?
Thanks in Anticipation !
You can use the frameworks like ModelMapper (documentation) to define your maping logic and use it to convert object from one type to object of another type. E.g. this is how the configuration would be:
//Model Classes
class A{
int a;
}
class B{
int d;
}
//Mappings
PropertyMap<A, B> map = new PropertyMap<A, B>() {
protected void configure() {
map(source.a, destination.d);
}
};
//Test Program
public static void main(String[] args) throws Exception {
ModelMapper mapper = new ModelMapper();
PropertyMap<A, B> map = new PropertyMap<A, B>() {
protected void configure() {
map(source.a, destination.d);
}
};
mapper.addMappings(map);
A a = new A();
a.a = 10;
B b = mapper.map(a, B.class);
System.out.println(b.d);
}
This defeats the safety purposes of Java for two reasons.
Let's consider an updated version of your class code.
class A {
int i;
int j;
int k;
int l;
}
class B {
int a;
int b;
int c;
}
Now imagine what would happen if you did something like this, assuming the classes were written right above: (Warning:code will not compile)
public static void main(String[] args)
{
B classTwo = new B();
A classOne = (A) classTwo;
classOne.l = 3; // <-- what would happen?
}
As you can see, it won't work, because creating an instance of B will not allocate the variabls properly. This is why Java does not permit casting like that.
What Java does permit is converting between superclasses and subclasses.
For example:
class Fruit {
int i;
}
class Apple extends Fruit {
int j;
}
And now inside the main function:
Fruit f = new Fruit();
Apple a = (Apple)f; // this compiles, but will raise a ClassCastException
You'll ask, why does it raise a ClassCastException? Apple extends Fruit.
Yes, Apple extends Fruit. But, Fruit does not allocate memory for the j variable.
What is allowed is the other way around, casting an Apple to a Fruit, because all Apples have properties of Fruits (even in real life).
If you want to use your idea of casting, you could try an interface.
interface C {
public int getVarOne();
public int getVarTwo();
// NO variables here, only functions
}
Any class which implements (not extends) an interface must also implement all of the methods defined in it.
Once you've implemented the interface, the behavior is similar to casting to a superclass. There are also other uses for interfaces, but that is beyond the scope of this question.
No. There's no such thing as unions known from C. You cannot modify the memory directly in JVM. That's the point of Java. It sacrifices some potential for tricks, but in the end the code tends to be less buggy and easier to maintain than the code written in C.
If your concern is memory consumption caused by copying, you can convert A and B into interfaces. The interfaces should expose getters and setters. For example: int getI() and int getA(). Then you can introduce a class implementing both of them.
The indirection caused by the interface calls will have some performance cost, but in many cases, it won't be noticable.
If class a extends class b, and class b extends class c, does a inherit from both c and b? If so, in case of conflict between the 2, is there an error or does one override another (and if so, which one)?
Please rename the question if it is unsuitably titled.
EDIT: what I mean by conflict is something like the following:
class c {
int foo;
//Stuff
}
class b extends c {
String foo;
//Stuff
}
class a extends b {
//Stuff
}
Is a.foo a string or an int?
Another edit: So from what I gather, inheritance here is a bit like CSS - the closer the rule is set, the larger priority it has (e.g. inline styles override stylesheets). Is that a good way of considering this, or is it significantly different?
If something exists in both b and c, a will inherit whichever one b uses.
Yes, a inherits from b and c. I don't see how there can be a conflict in this situation since b's method overrides will be valid for a. You may be thinking of the diamond problem that comes from conflicts from multiple inheritance, but that's when you have two different parents, not two parents with one parent being the parent of the other.
You can run into a "soft" diamond problem with interfaces, where two methods have the same signature, but the rules for one method don't match those of another. Since neither interface has an implementation for their methods, there is no compilation problem (that I know of), just a logical problem.
Edit Ah, I've seen your edit regarding variables, and I agree with Jimpanzee's response to it. It's certainly easy to test:
public class Test3 {
public static void main(String[] args) {
MyA myA = new MyA();
System.out.println("foo := " + myA.foo);
}
}
class MyC {
public int foo = 3;
//Stuff
}
class MyB extends MyC {
public String foo = "foo";
//Stuff
}
class MyA extends MyB {
}
well, the rule is as follows.
Any subclass will inherit nearest up its hierarchy. so a will get everything from b. Because everything which is on inheritance stack will be available till b. as b had inherited already everything from its inheritance hierarchy.
Secondly, if b over-rides anything(instance variable/method), then a will see over-ridden version. So in your case a will get String foo.
This answer has a much better example, and points out that doing this sort of thing is considered bad practice. (Eclipse will give you a warning, for example.) Extending your code a bit:
class c {
int foo = 42;
//Stuff
}
class b extends c {
String foo = "foostr";
//Stuff
}
class a extends b {
//Stuff
}
class Main{
public static void main(String[] args){
a mya = new a();
System.out.println(mya.foo);
}
}
Running java Main prints foostr.
In Java only methods are subject to overriding. Everything else is just inherited and there is only the issue of a namespace clash, but everything is still accessible. In your example both foos are accessible in A (I've corrected the class names to make them conform to the strong Java naming conventions):
class C {
int foo;
//Stuff
}
class B extends C {
String foo;
//Stuff
}
class A extends B {
String x = ((B)this).foo;
int i = ((C)this).foo;
}
Yes, it inherits from both c and b.
In order to prevent/avoid conflicts, Java support a single hierarchy model (differently from other OOP languages like C++ which allow multiple-class inheritance model).
I have a kind of specific problem, let's say, that I have
public interface A {
}
//------------------------------
public class B implements A {
static int countx = 0;
}
//----------------------------------
public class C implements A {
static int county = 0;
}
//----------------------------------
public class Arc {
public A from;
public A to;
//========================================
and now I have an object a (which is an instance of Arc) and I want to find out whether it is an instance of B or C and get to the atributes countX or countY (stg like a.from.countX)
any ideas? :)
I think you could use instanceof to solve this issue
as in
if(a instanceof B) return a.countx
if(a instanceof C) return a.county
Your current design is not good from the OOP standpoint. You need some encapsulation and polymorphism. In an OOP language, you don't explicitly check for the type of an object, you arrange for that to happen automatically via dynamic dispatch. So whatever data you need from both B and C, add a method to the interface A that will get that data and then implement the method in B and C accordingly. Also, don't use public instance fields, that breaks encapuslation.
Use instanceof and a typecast:
if (a.from instanceof B) {
B b = (B)a.from;
b.countx;
}
Edit: But you should really not need such a thing! If you do, you can probably redesign it to not produce ugly code like this.
For example you could let your interface A have a method getCount() and let your classes B and C implement these, by returning countx or county.
Edit2: I just noticed that your countx and county members are static! Why would you do that? static means, that they don't "act" upon instances of your class but on your class object (they are "class members"). This means that you can access and modify these variables everywhere by accessing them through A.countx or B.county; you most probably don't want this, because multiple instances of class A will share the same countx!
If you have an object that is an instance of Arc, then how is it also an instance of B or C? I feel like your code is flawed and needs restructuring. For example, as Tudor pointed out, "There is no relation between the classes Arc and A in your hierarchy."
If you simply want to have information about the classes :
getClass().getSuperclass()
Regards,
Erwald
Think about it like this :
What makes me want to discriminate between a B and a C ? Is it an operation? If so, just implement those operations appropriately in B vs C and let dynamic dispatch take care of the rest.
interface Operation {
public Result operate(String[] args);
}
class A implements Operation {
#Override
public Result operate(String[] args) {
//I need to do some special calculations for an A...
for(String arg : args) {
}
.
.
.
}
}
class B implements Operation {
#Override
public Result operate(String[] args) {
//i know this does nothing so return the empty result
return Result.EMPTY;
}
}
Resist the tempation to use instanceof. In most cases you don't need it - and its not OO.
G'day people,
I am feeling embarrass by asking such a naive question. But I can't understand one thing,
I have Inheritance structure like this,
B extends A, code I have wrote is as below,
Class A
public class A{
private int pos = 0;
public A(){
this.pos = 12;
}
public int getPos(){
return this.pos;
}
}
Class B
public class B extends A{
int spec = 15;
public B(){
super();
}
public int getSpec(){
return this.spec;
}
}
And I have one more class to test, Which will get us to my question.
Class Test
import java.util.*;
public class Test{
public static void main(String[] args){
B a = new B();
ArrayList<A> c = new ArrayList<A>();
c.add(a);
System.out.println(c.get(0).getPos());
System.out.println(c.get(0).getSpec());
}
}
Question : Now I am creating an instance of B, Which means I can access to my parent class's method getPos() and B's own method getSpec(). But if I create ArrayList with type A(...B is type A too, as it extends A...) and add my B's instance it losses it's ability to access it's own method. What am I doing wrong? Does ArrayList implementation is casting my B to A internally?
Note : My basic understanding of inheritance is parent cannot access
child's method except they are protected. But Child can access their
parent class's method.
There's no casting involved. What you're doing is no different from this:
A bAsA = new B():
While the object referred by bAsA is truly a B object, it is held by an A variable and thus only A methods are available (unless you explicitly cast it as a B variable).
Since your ArrayList is an ArrayList of A, each item in the ArrayList is treated as an A variable and only A methods are available.
Does ArrayList implementation is casting my B to A internally?
No. There is no "internal casting." You, the programmer, have told the compiler it's a list of A.
You have declared the List as List<A>, which you can read as "a list of A". Since all B are A, you can add any B to a List<A>. On retrieval, however, you're only guaranteed to get back an A, not a B — because it's a List<A>, remember — so the compiler treats everything that comes out of the list as an A, even if (at runtime) it's an instance of B.
In addition to the answers provided by #Matt Ball and #Hovercraft Full Of Eels, you can avoid having to explicitly cast by declaring methods implemented by the subclass as abstract methods in the superclass.
public abstract class A{
.
.
public abstract int getSpec();
}
EDIT-
As mentioned by #Kublai Khan, it is necessary to then make the superclass an abstract class.
I give lessons on the fundamentals of the Java programming language, to students who study this subject in college.
Today one of them got me really confused with her question, so I told her to give me just a day to think about the problem, and I'll give her as accurate of an answer as I can.
She told me that the teacher got really angry when she used the keyword instanceof in her exam.
Also, she said that the teacher said that there is not a way to prove how polymorphism worked if she used that word.
I thought a lot to try to find a way to prove that in some occasions we need to use instanceof, and also that even if we use it, there still some polymorphism in that approach.
So this is the example I made:
public interface Animal
{
public void talk();
}
class Dog implements Animal {
public void talk() {
System.out.println("Woof!");
}
}
public class Cat implements Animal
{
public void talk() {
System.out.println("Meow!");
}
public void climbToATree() {
System.out.println("Hop, the cat just cimbed to the tree");
}
}
class Hippopotamus implements Animal {
public void talk() {
System.out.println("Roar!");
}
}
public class Main {
public static void main(String[] args) {
//APPROACH 1
makeItTalk(new Cat());
makeItTalk(new Dog());
makeItTalk(new Hippopotamus());
//APPROACH 2
makeItClimbToATree(new Cat());
makeItClimbToATree(new Hippopotamus());
}
public static void makeItTalk(Animal animal) {
animal.talk();
}
public static void makeItClimbToATree(Animal animal) {
if(animal instanceof Cat) {
((Cat)animal).climbToATree();
}
else {
System.err.println("That animal cannot climb to a tree");
}
}
}
My conclusions are the following:
The first approach (APPROACH 1) is a simple demo of how to program to an interface, not a realization. I think that the polymorphism is clearly visible, in the parameters of the method makeItTalk(Animal animal), and also in the way the method talk is called, by using the animal object.(This part is ok)
The second part is the one that makes me confused. She used instanceof at some point in her exam (I don't know how their exam looked like), and that was not accepted correctly because the teacher said, you are not proving polymorphism.
To help her understand when she can use instanceof, I thought about telling her, that she can use it, when the method she needs to call is not in the interface, but it is just in one of the implementing classes.
As you can see, only cats can climb to trees, and it would not be logical to make a Hippopotamus or a Dog climb to a tree. I think that could be an example of when to use instanceof
But what about polymorphism in approach 2?
How many uses of polymorphism do you see there (only approach 2)?
Do you think this line has some type of polymorphism in it?
((Cat)animal).climbToATree();
I think it does, because in order to achieve a Casting of this type, the objects need to have an IS-A relationship, an in some way that is polymorphism.
What do you think, is it correct?
If yes, how would you explain with your own words, that casting relies on polymorphism?
The reason the instanceof method is seen as bad is simple. Cats aren't the only Animal that might be able to climb a tree.
What happens if down the road you need to add a Koala class. Then your simple if becomes a not so simple or. Then, what happens when you add another class? and another one. And another one. That's the prime reason why instanceof is seen as bad. Because it couples the implementation to a concrete class, rather than opening it for the callee to determine what to do.
Simply implement the makeItClimbToATree() method to throw a CantClimbTreesException if called on an animal that can't climb. That way you have the best of both worlds. Easy to implement, and easy to extend.
IMHO, instanceof has only 1 truly valid use: In a test case to test the returned instance from a method matches the expected return type (in non-type safe languages).
Basically any other use can more than likely be refactored away or designed differently to negate the need for its use.
Another way to look at it is this: Polymorphism allows you to eliminate almost all conditional statements from your code. The only conditionals that you can't get rid of (at least all of them) are in object creational methods (such as in a factory where it must choose the class based upon a runtime argument). Just about any other conditional can be replaced by polymorphism. Therefore, anything that does conditional execution is by definition anti-polymorphic. That's not to say it's bad (there's a huge difference between Good and Good Enough), But in an academic discussion, it's not polymorphic...
Never forget the 60/60 rule. 60% of your total development time will be spent maintaining the code you wrote, and 60% of that time will be spent adding new features. Make maintaining easier, and your life will be easier as well. That's why instanceof is bad. It makes the initial design easier, but complicates the long term maintenance (which is more expensive anyway)...
In your above example, there is no need to call
makeItClimbToATree (new Hippopotamus ());
It could be easily avoided, if makeItClimbToATree wouldn't expect an animal, but something more specific, which is really able to climb a tree. The necessity to allow animals, and therefore to use instanceof, isn't visible. If you manage the animals in a List of animals, it will be more obvious.
While ircmaxells explanation starts great, while introducing the Koala and other TreeClimbers, he doesn't see a second extension which is hiding in a sea anemone: different capabilities of animals like seaAnemoneHider, winterSleeping, blueEyed, bugEating, and so on, and so on. You would end up with boolean over boolean, constantly recompiling the base class, as well as breaking extending customer classes, which would need recompilation again, and wouldn't be able to introduce their own possibilities in a similar manner.
Customer A would need Customer B to declare a NotBugEatingException, to get your behaviour into the base class.
Introducing your own interfaces, combined with instanceof, is a much cleaner approach, and more flexible. Customer A might define divingLikeAPenguin and customer B trumpeting, both not knowing of each other, both not affecting the Animal class and not provoking useless recompilations.
import java.util.*;
interface Animal {
public void talk ();
}
interface TreeClimbing {
public void climbToATree ();
}
class Dog implements Animal {
public void talk () { System.out.println("Woof!"); }
}
class Cat implements Animal, TreeClimbing {
public void talk () { System.out.println("Meow!"); }
public void climbToATree () { System.out.println ("on top!"); }
}
public class TreeCriterion {
public static void main(String[] args) {
List <Animal> animals = new ArrayList <Animal> ();
animals.add (new Cat ());
animals.add (new Dog ());
discuss (animals);
upTheTree (animals);
}
public static void discuss (List <Animal> animals) {
for (Animal a : animals)
a.talk ();
}
public static void upTheTree (List <Animal> animals) {
for (Animal a : animals) {
if (a instanceof TreeClimbing)
((TreeClimbing) a).climbToATree ();
}
}
}
We don't need a third animal, dog and cat are enough. I made them default visible instead of public, to make the whole example fit into a single file.
Do you think this line has some type of polymorphism in it?
((Cat)animal).climbToATree();
No. Especially, since Cat is a leaf class in the example.
I think it does, because in order to achieve a Casting of this type, the objects need to have an IS-A relationship, an in some way that is polymorphism.
Polymorphism requires the IS-A relationship, but not the other way round.
Polymorphism is when you dispatch to (potentially) different methods based on an abstract interface. If you don't have that dispatching, then it is not using polymorphism. In your example, using instanceof to cast to a class with no subclasses, you are removing the need for dispatching.
(Of course, there is more than one way to "do polymorphism" in Java. You can implement it using interfaces, using abstract classes, or using concrete classes with subclasses ... or hypothetical subclasses that may be written in the future. Interfaces (and dispatching based on an interface) are generally the best way because they give a clean separation of the API from the identity of class.)
And on a separate note, using instanceof like that is typically a sign of poor design and / or poor modelling. Specifically, it hard-wires the assumption that only cats can climb, which is trivially falsified if we include other animals into the model / program. If that happens, your code breaks.
Maybe I'm missing the point and don't get the context of the exam question, but whether an Animal can climb a tree should be a part of the class that implements Animal. For example, if Animal is an interface, you could have a method boolean isCapableOfClimbing() and then each implementing class would be able to indicate its capability.
A method that attempted to make the animal climb could then use that. It doesn't make sense for a method that's trying to make the animal climb a tree check whether it's an instance of a particular class, since then that method is specifying something that should be specified in the implementing class. A simple method should not provide behaviour for a class that it's using.
As for your question of when to use instanceof, once place where it will almost always be used is if overriding the equals() method of a class, since it only accepts an Object and you typically have to ensure it is of the same type so it can be cast and then meaningfully compared.
What about something like the code below? It solves the generality problem by separating the tree-climbing as another interface you can implement or not on your animals. It fits the problem better: climbing trees is not an intrinsic property of all animals, only of a subset of them. At least to me it looks much clearer and elegant than throwing NotImplementedExceptions.
public interface Animal {
public void talk();
}
public interface AnimalCanClimbTrees extends Animal {
public void climbToATree();
}
public class Dog implements Animal {
public void talk() {
System.out.println("Woof!");
}
}
/* Animal is probably not needed, but being explicit is never bad */
public class Cat implements Animal, AnimalCanClimbTrees
{
public void talk() {
System.out.println("Meow!");
}
public void climbToATree() {
System.out.println("Hop, the cat just cimbed to the tree");
}
}
class Hippopotamus implements Animal {
public void talk() {
System.out.println("Roar!");
}
}
public class Main {
public static void main(String[] args) {
//APPROACH 1
makeItTalk(new Cat());
makeItTalk(new Dog());
makeItTalk(new Hippopotamus());
//APPROACH 2
makeItClimbToATree(new Cat());
makeItClimbToATree(new Hippopotamus());
}
public static void makeItTalk(Animal animal) {
animal.talk();
}
public static void makeItClimbToATree(Animal animal) {
if(animal instanceof AnimalCanClimbTrees) {
((AnimalCanClimbTrees)animal).climbToATree();
}
else {
System.err.println("That animal cannot climb to a tree");
}
}
}
The instanceof operator has nothing to do with polymorphism. It is simply used to see whether or not an object is an instance of a particular class. You see this operator being used a lot in the equals() method, because the method takes a generic Object as a parameter:
public class Cat implements Animal{
#Override
public boolean equals(Object obj){
if (obj == null || !obj instanceof Cat){
//obj is null or not a "Cat", so can't be equal
return false;
}
if (this == obj){
//it's the same instance so it must be equal
return true;
}
Cat catObj = (Cat)obj; //cast to "Cat"
return this.getName().equals(catObj.getName()); //compare the two objects
}
}
If a class does not implement a method, then it should throw an exception. I believe the "official" exception you are supposed to throw is UnsupportedOperationException. To be "correct", I think the Animal interface should have a public void climbToATree(); method. The climbToATree() methods in the Dog and Hippo classes should throw an UnsupportedOperationException because they cannot implement this method. But if you are throwing this exception very often, then there may be something wrong with your object model, as this is not a common thing to do I don't think.
Also note that it's helpful (but not required) to use the #Override annotation with polymorphic programming in Java. This will cause a compilation error to be thrown if a method with this annotation does not override a parent method, implement an abstract method, or (in Java 6) implement an interface method. This can help catch any mistakes you make in the method signature. For example:
public String tostring(){
return "foobar";
}
Without the annotation, the program would compile and run successfully. But this was not your intention! You wanted to override toString(), but you accidentally spelled the name wrong!!
I'm surprised no one wrote anything about Late Binding. Polymorphism in Java = Late Binding. The method being called will be be attached to the object when we finally know its type. In your example:
if(animal instanceof Cat) {
((Cat)animal).climbToATree();
}
You are calling climbToATree() on a Cat object so the compiler accepts it. At run time, there is no need to check the type of the calling object since climbToATree() belongs to Cat only. And so there is no polymorphism in these lines of code.
About casting being related to Polymorphism, it isn't. Casting just limits the fields that are shared in both objects, if the cast is legal. You could do this:
class A {
int getInt() {}
}
class B extends A {
int getInt() {}
}
// in main
A a = new B();
A b = (A)a;
b.getInt(); // This would still call class B's getInt();
The cast itself added no value, getInt() was bound at run time to the runtime type of a, which was class B.
A polymorphic and OOP approach would be to place the method makeItClimbToATree on the Animal interface:
public interface Animal{
public void talk();
public void makeItClimbToATree();
}
Then the implementors of Animal would provide the behavior for the method, which for all other than Cat could be to throw an exception. This is polymorphic because you operate on different implementations of Animal through a single method.
The function which uses the instanceOf operator is considered "bad" OOP because it requires knowledge of all the implementation types to determine the behavior of the method.