Java - Avoiding cast using an array of superclass-objects - java

I have many sub-classes implementing the superclass Animal (Dog, Cat, Mouse, etc)
So I do:
Animal[] arrayOfAnimals = new Animal[100];
I put in it Dog,Cat etc objects.
When I get something from it I do
If(arrayOfAnimals[1] instanceof Dog) {
((Dog)(arrayOfAnimals[1])).speak();
}
else if(arrayOfAnimals[1] instanceof Cat) {
((Cat)(arrayOfAnimals[1])).speak();
}
Because I need to know if that Animal is a Cat or a Dog because,for example, each one speaks differently.
Now assuming I have many subclasses of Animals, I will consecutively get many "else if..."
My question is: Is there a way to avoid this? I have already tried using an interface (Animal -> interface, Dog,Cat etc implementing animal), but in my project an array has to be cloneable, and you can't clone an array "Animal [] arrayOfAnimals" if Animal is an interface (objects inside that array will not be cloned)

Because i need to know if that Animal is a Cat or a Dog because,for example, each one speaks differently.
That sounds like it's an implementation detail - if every animal can speak in some form, you should put the speak() method into Animal as an abstract method. Each subclass will then override it to provide the implementation. Then you can just use
arrayOfAnimals[1].speak();
... and polymorphism will take care of using the right implementation.
You can clone an array of an interface type, btw:
interface Foo {
}
class FooImpl implements Foo {
}
public class Test {
public static void main(String[] args) {
Foo[] foos = { new FooImpl() };
Foo[] clone = (Foo[]) foos.clone();
System.out.println(foos[0] == clone[0]); // true
}
}
Note that regardless of the type involved, calling clone() on array won't clone each element - the new array will contain the same references as the old array. It's a shallow copy. If you want to do that, you'll have to code it yourself (or find a third party library).

Why don't you move speak() to the superclass and let the subclasses override it?

Related

Superclass obj = new subclass(); meaning and casting

If I have super class (Animal) and a sub class (Cat).
What does the third point mean? And when we have to cast?
Cat obj = new Cat(); means creating an object from Cat class
Animal obj = new Animal(); means creating an object from Animal class
Animal obj = new Cat();
First lets understand Class, reference and Object. Suppose we have a class named SomeClass
SomeClass ref = new SomeClass();
Above we have an Object of SomeClass created in Heap and a reference variable refers to it. We have named the reference variable as ref. Object is present in heap and we can just access it using a reference. So Object type is of the actual class (on which new keyword has been applied). Reference variable type can be of actual class or its Parent class.
Now let us see the relationship of Inheritance. A class inheriting from another class share a Child-Parent relationship.
Child inherits the behaviour of its Parent and can then override some of the behaviour and also can add some additional behaviour. Hence Object of Child can be used at any place where Parent object is expected, as Child has all the behaviour of its Parent so invoking any behaviour present in the Parent will be handled by the Child.
Parent class do not know about the additional behaviour of its child class ( child class is written later in time.) Hence object of Parent can not be used at the places where Object of Child is expected (If additional behaviour of Child is invoked on Parent object then it will not be honoured).
Now let us assume we have classes ParentClass and ChildClass such that ChildClass inherits ParentClass
ParentClass reference = new ParentClass(); // Valid
ParentClass reference = new ChildClass(); //Valid
ChildClass reference = new ChildClass(); //Valid
ChildClass reference = new ParentClass();// Not Valid.
Note that
ParentClass reference = new ChildClass(); // Here Object is of type ChildClass and Reference is of type ParentClass.
Now when to cast. Any place expecting the object of ParentClass, there is no need to cast, both the objects (of ParentClass or of ChildClass) are fine.
Any place expecting the Object of type ChildClass but if we have a case like below then casting is needed.
public void someMethod(ChildClass expected){
//some implementation
}
ParentClass ref = new ChildClass();
someMethod(ref);//Invalid : Compilation Issue
someMethod((ChildClass)ref);// Valid
ParentClass anotherRef = new ParentClass();
someMethod(anotherRef); // Invalid : Compilation Issue
someMethod((ChildClass)ref); //Invalid, compiles but Runtime it will fail.
Thumb rule : Child is Child, Child is Parent, Parent is Parent , Parent is not Child.
Another example for understanding.
public abstract class List{
public abstract void add(int element);
public abstract void remove(int element);
public int size();
}
public class Application{
private List listReference;
public void setList(List ref){
listReference = ref;
}
}
//Now you may create sub classes as below
public class ArrayList extends List{
// all the abstract methods of List have been implemented
}
public class LinkedList extends List{
//all the abstract methods of List have been implemented
}
Now in main method you can pass ArrayList or LinkedList or any other implementation.
public class Init{
public static void main(String[] args){
Application app = new Application ();
app.setList(new LinkedList());
//or you can set it like this
List listRef = bew ArrayList();
app.setList(listRef);
//or you can set it like this
LinkedList linkedListRef = new LinkedLiet();
app.setList(linkedListRef);
}
}
Notice that the method setList() accepts List type of reference and we can provide any implementation of the List abstraction. This leads to a flexible design.
Classes should be dependent on the abstraction. Programming to interface is a Design Principle which leads to easy maintenance of the application code.
The reason why this is confusing on the face of it is that it is not something that you would typically do in real code, except in the case of a Factory.
As hinted at in Zabuza's comment, you can do this because a Cat 'is-a' kind of Animal and so you can assign an object of type Cat to an object of type Animal. But you can't do the assignment the other way of course, because an Animal is not a kind of Cat.
Now, there are some lurking issues that come with actually being able to create an instance of the the supertype as well as the subtype that mean you typically wouldn't actually do this in real code because it complicates a lot of things down the road. What you would more likely do is make Animal an interface and have a GenericAnimal class that implements it, along with having Cat implement it.
Say you have an object that represents a zoo, and most zoos typically have a collection of animals. The most obvious way to represent this would be this:
java.util.Collection<com.myproject.Animal> zooAnimals;
So now imagine the zoo builds a new habitat, and it's for a lion. For the sake of the story assume we have a very lazy data model and instead of having a specific com.myproject.animals.cats.Lion subtype we just said "lions are cats, close enough". So to update the data structure that tracks all the animals and their names and addresses and favorite foods and whatever else, we might do this:
com.myproject.Animal newArrival = new com.myproject.animals.Cat("Larry the Lion", "Africa Exhibit", "Gazelles");
zooAnimals.add(newArrival);
Now imagine that the zoo continues to grow, and gets an Ostrich in the Africa habitat. And the same lazy data model applies so we just call it a Bird.
com.myproject.Animal newArrival = new com.myproject.animals.Bird("Oliver the Ostrich", "Africa Exhibit", "Whatever Ostriches Eat");
zooAnimals.add(newArrival);
Now actually writing that exact code would normally only happen in very specific cases inside a factory object or something, and realistically type hierarchies like this have a tendency to not work very well in practice at all, contrary to what a lot of us learned in Object Oriented Programming class, but for the sake of the question that is an example situation where you might do what you are asking about.
Lastly, you also asked when you have to cast. You would have to do this if you had code that needed to know about any special methods or fields that the Cat or Bird types have that Animal does not have. For instance the Cat type might have a property called tailLength because cats typically have tails and for whatever reason the zoo likes to keep track of that. Similarly the Bird type might have a property called wingSpan because birds have wings and we want to keep track of how big they are. The Animal type doesn't have any of these properties so if we get the object for the lion or the ostrich out of the zooAnimals collection (and maybe we looked at the name or something to figure out it was the lion) we would have to cast back to the Cat type in order to access the tailLength property. Same thing for the ostrich and it's wingspan.
for( Animal theAnimal : zooAnimals ){
if( theAnimal.getName().equals("Larry the Lion") ){
Cat theCat = (Cat)theAnimal;
System.out.println("Larry's tail is " + theCat.getTailLength() + " inches long";
}
else if( theAnimal.getName().equals("Oliver the Ostrich") ){
Bird theBird = (Bird)theAnimal;
System.out.println("Oliver's wingspan is " + theBird.getWingSpan() + " inches";
}
}
Again you probably wouldn't actually do something like that in real code, but perhaps it helps to illustrate the example.

method chaining, returning an object from a list and getting values from it

what I have is a list of Dog objects, in the objects there contains a value that is a Boolean to show whether the dog as completed a training or not. What im trying to do is iterate over the list and only return Dog() objects that have completed training, for instance if their are 12 dogs, and only 3 have completed training, the loop should only print those objects.
else if (input == 1) {
for (int i = 0; i < 12; ++i) {
//Create a temporary value to hold the object.
Object tempHold = dogKennel.getAnimal(i);
//If animal has not graduated, skip, else print.
if (!(tempHold.getGraduation())) {
continue;
}
else {
System.out.println(dogKennel);
}
}
getAnimal(i) returns the object at int i
the method .getGraduation is defined and does return a Boolean however the compiler doesnt want to recognize temp value as is, and doesnt go beyond that value. the compiler keeps suggesting to cast tempHold, but even if I do, it doesnt work.
i feel like it would work if i could get it to compile, as the object that is returned would have a getGraduation() method (it is defined for the super class of the animal.)
however the compiler doesn't want to recognize temp value as is, ...the compiler keeps suggesting to cast tempHold, but even if I do, it doesn't work.
The compiler is telling you two things:
An Object is NOT a Dog (the opposite is true. A Dog is an Object).
class Object does not have method isGraduated() defined for them.
To fix this, you can cast Object to Dog:
Dog tempHold = (Dog)dogKennel.getAnimal(i);
Now that we have a Dog, we can safely invoke isGraduated() on it. But the problem is we canNOT be sure that we have a Dog. We may as well have a Cat if we get the Animal from another kennel. In that case, you will get a ClassCastException which tells you that Cats cannot be cast as Dogs.
To avoid getting run time exceptions, you can add a check:
Object tempHold = dogKennel.getAnimal(i);
if(tempHold instanceof Dog) {
Dog dog = (Dog)tempHold;
System.out.println(dog.isGraduated());
}
The instanceof check fixes the problem.
There are ways to avoid this run time check altogether. One would be to create an interface:
public interface CanGraduate {
default boolean isGraduated() {
return false;
};
}
Then make all Animals implement this interface:
public abstract class Animal implements CanGraduate {
//Behavior common among all animals
}
You can now freely add new animal types and be assured that you can safely invoke isGraduated() on them and get a false value as long as they inherit from the above Animal class.
For dogs, isGraduated() is supposed to be more meaningful. So you can override it in their case:
public class Dog extends Animal {
private boolean _graduated = true;
#Override
public boolean isGraduated() {
return _graduated; //or some complex logic that determines graduation
}
}
With this structure, you no longer need to worry about invoking the method on any kind of Animal.
As an example, let us see some driver code:
public class Main {
public static void main(String[] args) {
Dog dog1 = new Dog();
Dog dog2 = new Dog();
Cat cat1 = new Cat();
Cat cat2 = new Cat();
List<Animal> dogKennel = List.of(dog1, dog2);
List<Animal> catKennel = List.of(cat1, cat2);
for(Animal x : catKennel) {
System.out.println(x.isGraduated());
}
}
}
The program will simply output false since Cats can never graduate. If the kennel contained Dogs, it would output the actual graduation status of the dog.
Like the others have said, the getGraduation() method is only defined presumably in the Dog class. This means that the method can only be called on Objects with the type Dog. To define a variable with type Dog you can do Dog temphold = *whatever*. The reason it wants you to cast is because Object is a supertype of Dog. If you'd like to read more about casting you can here: https://javarevisited.blogspot.com/2012/12/what-is-type-casting-in-java-class-interface-example.html
Basically, all you have to do is a cast to convert the object
if (!(((Dog)tempHold).getGraduation()))
{
continue;
}
this casting tells the compiler that even though tempHold is an object of the Object class it also is an object of the Dog class and should have all of its properties
If you want to filter the list for just ones with a certain condition, the most common way to do that these days is with the Stream::filter method.
It would look like this:
List<Dog> completedTraining =
dogKennel
.stream()
.filter(
dog -> !dog.getGraduation()
)
.collect(
Collectors.toList()
)
;

Why downcasting is allowed in java?

class Animal{
public void findAnimal(){
System.out.println("Animal class");
}
public void sayBye(){
System.out.println("Good bye");
}
}
class Dog extends Animal{
public void findAnimal(){
System.out.println("Dog class");
}
}
Given the inheritance above ,it is understood that a reference of Animal can refer to an object of Dog
Animal animal=new Dog();
As a Dog object can perform everything an Animal can do like in above case a Dog also have sayBye and findAnimal methods.
But why it is allowed to downcast an Animal object to a Dog object which serves no purpose and fails at runtime.
Dog dog=(Dog)new Animal(); // fails at runtime but complies.
Dog dog=(Dog)animal;
The above statement look logical as the animal reference is pointing to a Dog object.
This sort of casting is allowed for situations when you get an object of a superclass from outside code, e.g. as a parameter to your method, and then you need to call methods specific to a subclass.
This is not a good practice, but in some rare situations you are forced to do things like that, so the language allows it:
void sound(Animal animal) {
if (animal instanceof Dog) {
Dog dog = (Dog)animal();
dog.bark();
}
if (animal instanceof Cat) {
Cat cat = (Cat)animal();
cat.meow();
}
}
why it is allowed to compile Dog dog=(Dog) new Animal()
Because compiler designers decided to not detect this error at compile time. They verified that the expression being cast to Dog is of type that is a superclass of Dog, and allowed the expression to compile. They could go further and check that the expression will always result in an exception, but that would require an additional effort for very little improvement in user experience with the language.
Because you need it sometimes.
Especially when Java did not yet have generics (Java 1.4 and older), you almost always needed to cast when you got for example an object out of a collection.
// No generics, you don't know what kinds of objects are in this list
List list = new ArrayList();
list.add(new Dog());
// Need to cast because the return type of list.get() is Object
Dog dog = (Dog)list.get(0);
Since we have generics since Java 5, the need for casting is greatly reduced.
You should try to avoid casting in your code as much as possible. A cast is a way to deliberately switch off the compiler's type checking - in general you don't want to do that, you want to make use of the compiler's checking instead of circumventing it. So, if you have code where you need to cast, think a bit further to see if you can write it without the cast.
You need that capability to access an earlier cast object as its original type.
For example, if you cast a Dog to an Animal to pass it to a generic processor, you may later need to cast it back to a Dog to perform specific methods.
The developer is responsible to make sure the type is compatible - and when it is there will be no error. Some pseudo code:
public void example(Animal foo){
if( ...condition... ) ((Dog)foo).bark();
else if( ...other condition... ) ((Cat)foo).meow();
}
Since the introduction of generics, this is less commonly used, but there are still cases for it. The developer is solely responsible for guaranteeing the type is right if you don't want an error.
case 1 -
Here we use loose coupling.
Animal animal = getSomeDog(),
Dog dog = (Dog) animal; // this is allowed because animal could reference a dog
case 2
Here we you use tight coupling.
Animal animal = new Animal();
Dog dog = (Dog) animal; // this will fail at runtime, because animal doesn't reference a Dog
We use Downcasting when there is possibility to succeed at run time
so case 1 has possibility to succeed at runtime over case 2
Down casting is considered as a bad Object Oriented practice. It must be avoided to as much extent as possible.
Java still has it and your question is a good question as why Java allows Down-casting.
Suppose a case below.
public interface List{
public boolean add(Object e);
public boolean remove(Object o);
}
public class ArrayList implements List{
// Extra method present in the ArrayList and not in the parent Interface
public Object[] toArray() {
// returns array of the objects
return Arrays.copyOf(elementData, size);
}
#Override
public boolean add(Object e){
// add e to the ArrayList Underlying array
}
#Override
public boolean remove(Object o){
// remove o from the ArrayList Underlying array
}
}
A good Object oriented practice is to Code for Interfaces. But often there are methods defined in the concrete implementations which we need to call. I read an comment from some one and I quote it in my words.
Know the Rules, in case you need to break them Do break them Knowingly and take care so as to prevent from any adverse effect.
Below is an example where we need to do the Down-casting. The example of down-casting in your question is to teach what is down-casting, below is real life example.
public void processList(List items){
items.add( new Object() );
items.add( new Object() );
processAsPerTypeOfList(items);
}
public void processAsPerTypeOfList( List items ){
if( items instanceof ArrayList){
Object[] itemArray = ((ArrayList)items).toArray();// DOWNCASTING
// Process itemArray
}
}
For more reference you can also see a related question : Why Java needs explicit downcasting?

Java: getting subclass reference using getClass

If i have a superclass called Animal, and subclasses called Cat, Dog, Bird.
If I read an array of Animals, and want to access a Cat specific method called meow(), how do i do this?
I know i can use getClass() to find out the Animal's subclass, but how do i use to create a reference to access meow()
If you are using an array of animals, you need to check whether the object you are working with is an instance of Cat class, this can be achieved by using the instanceof operator. Then we can use the downcasting operator to convert the Animal to a Cat and then call the meow() method.
if(animal instanceof Cat){
(Cat)animal.meow()
}
With an array
Animal [] animals = [];
foreach(Animal animal: animals){
//do something
if(animal instanceof Cat){
(Cat)animal.meow()
}
}
You can cast to Cat
if (animal.getClass().getName().equals('Cat')) {
((Cat)animal).meow();
}
Or you could use instanceof.
Both of those solutions are ugly, and Java was not designed to be used this way. Instead, you should create a .speak method for the animals that could call Cat.meow internally.
Like this ...
if (animal.getClass().getName().equals('Cat')) {
((Cat)animal).meow();
}
or
if (animal instanceof Cat) {
((Cat)animal).meow();
}
Once you found out the subclass you want to use, you can cast it. In your case it would be
((Cat)animals[index]).meow();

When should or shouldn't I use a more general variable type for referencing my object?

There are 2 classes A and B, B extends A. What is the difference between
A a = new B();
and
B b = new B()?
Both create the object of class B. What is the difference?
You are right that in both cases an object of class B is created. The difference between the two declarations is in the type of the variable.
It is very important to keep the distinction between variables and objects in mind. For example, the following code defines 3 variables but only 2 objects:
Circle c1 = new Circle(5);
Circle c2 = c1;
Circle c3 = new Circle(5);
When you say
Shape s = new Circle(5);
instead of
Circle s = new Circle(5);
assuming Circle extends Shape then, even though in both cases you did create a circle object, in the former case you can only call shape methods on the circle (through the variable s) whereas in the second case you can you all circle methods (because you will be calling them through the circle variable c). That is a call like s.getArea() will work in both cases but something like s.getRadius() will ONLY be allowed in the second (unless you use an ugly cast).
So why do we often do things like the first case? That is, why do we often define our variables of a more general type than necessary? Usually we do this because we want to restrict the interface for safety. Perhaps we only care about shapes, but in this case the particular shape just happens to be a circle. If you cared about circle specific properties, then we would have used a circle variable. But we should strive to be as general as possible. Coding to the most general interface allows our code to work with shapes other than circles without modification.
Of course, for this to really sink in, you have to experience it firsthand, but hopefully this explanation is a start. There are many books and blog posts and articles that explain this in more detail with useful real-life anecdotes I'm sure.
A a = new B();
has only the attributes and methods of A.
B b = new B();
has the the attributes and methods of B.
If you added some attributes or methods to B, you can't call them with a.
The advantage is
Fruit f = new Mango();
Suppose
consumeFruit(Fruit f);
now you can call
consumeFruit(new Mango());
consumeFruit(new Strawberry());
Note:
For this case you would be only able to call the methods declared in the reference type. and object type's version will get invoked . and you would be only accessing fields from the reference type's class
See Also
Liskov substitution principle
If you say
List a = new ArrayList();
then you reference ArrayList only in one place in your code. That makes it easier to change it later to something else, like LinkedList;
Of course, this does not work if you need methods specific to ArrayList.
In general, you should use the most general type applicable.
This question is on Polymorphism. Following is an extract from Kathy Siera:
public class TestAnimals {
public static void main (String [] args) {
Animal a = new Animal();
Animal b = new Horse(); //Animal ref, but a Horse object
a.eat(); // Runs the Animal version of eat()
b.eat(); // Runs the Horse version of eat()
}
}
class Animal {
public void eat() {
System.out.println("Generic Animal Eating Generically");
}
}
class Horse extends Animal {
private void eat() { // whoa! - it's private!
System.out.println("Horse eating hay, oats, "
+ "and horse treats");
}
}
If this code compiled (which it doesn't), the following would fail at runtime:
Animal b = new Horse(); // Animal ref, but a Horse
// object , so far so good
b.eat(); // Meltdown at runtime!
Suppose this example:
We have class an animal:
public class Animal {
public void eat() {
// each animal can eat
}
}
Now we have another class dog:
public class Dog extends Animal {
public void bark() {
// dogs can bark
}
}
Now we can write this code:
Animal pet = new Dog();
Now we know, that pet can eat, but nothing more. But if we write
Dog pet = new Dog();
Then we know, that our pet can eat and bark.
Also there is safe and unsafe casting. Safe casting is from Dog to an Animal because each dog is animal (extends it)
Dog pet = new Dog();
Animal animal = pet;
But if we want to cast Animal to Dog we have to test if the instance of animal is really dog, because it doesn't have to be.
Animal pet = new Dog();
Dog myDog = null;
if (pet instanceof Dog) {
myDog = (Dog) pet;
}
Usually, declaring a parent class and assigning it an inherited class is useful when the parent class variable may be assigned different objects. For example
Pet p;
if (favoritePet == Pets.CAT) {
p = new Cat();
} else {
p = new Dog();
}
System.out.println(p.someMethodFromPet());

Categories