Java Parametric Polymorphism example - java

I have a question about Parametric Polymorphism. How do I determine the actual type and avoid casting If I have a collection with a mix of child types. For example
class Animal{
}
class Bird extends Animal{
void fly(){}
}
class Dog extends Animal{
void bark(){}
}
ArrayList<Animal> list = new ArrayList<Animal>();
The problem is how do I know which one is which when I iterating through the Animal collection. Do I need to use instanceof to check the actual type every time?
for(Animal animal : list){
if(animal instanceof Dog){
((Dog) animal).bark();
}
else ((Bird) animal).fly();
}

If you need to do this, that means that's a common action. You usually would have this :
abstract class Animal {
abstract void act();
}
class Bird extends Animal{
void fly(){}
void act(){
fly();
}
}
class Dog extends Animal{
void bark(){}
void act(){
bark();
}
}
and in your loop you would simply call the act method :
for(Animal animal : list){
animal.act();
}

You should not have list like that. Otheriwse instanceof (or .getClass()), followed by a downcast is the only option.

Using instanceof would defeat the purpose of Generics. The point of generics is to define behavior so that you don't care what the types are. Example:
public interface Animal {
void speak();
void fly();
}
public class Dog implements Animal {
public void speak() {
System.out.println("Woof!");
}
// Do nothing!
public void fly() { }
}
public class Bird implements Animal {
public void speak() {
System.out.println("Tweet!");
}
public void fly() {
System.out.println("I'm flying!!");
}
}
public static void main (String[] args) {
// list populating removed
for(Animal animal : list) {
animal.speak();
animal.fly();
}
}
See? You don't actually care about what type the animal is at runtime. You let the objects do what they're supposed to.
By the way, if you did want only Bird to have a fly() method, then you wouldn't try to call the fly() method on all instances of Animal... you would have a different List<Bird>

Related

Class inheritance and generic types

I'm currently working on inheritance in Java. I would like to discuss the following case with you.
In my example, I have numerous animal and enclosure classes. All animals are derived from BaseAnimal. All enclosure are derived from BaseEnclosure. Both base classes provide various concrete methods - but also some abstract methods.
Now, when implementing a CatEnclosure, I want to specify that when CatEnclosure.resettleTo(Enclosure) is called, only one cat enclosure can be passed. In my current code, a cat could also be placed with a dog.
To my understanding, I would have to define the class of the future (derived) class when creating the abstract method resettleTo in the BaseEnclosure class.
My idea was to use a second generic. So BaseEnclosure<A> becomes BaseEnclosure<E, A>. But now I would also have to specify that E must be derived from BaseEnclosure. In addition, of course, A should also be of the BaseAnimal type.
So I get: BaseEnclosure<E extends BaseEnclosure, A extends BaseAnimal>
My IDE now complains that BaseEnclosure and BaseAnimal are raw types. If I write BaseEnclosure<E extends BaseEnclosure<?,?>, A extends BaseAnimal<?,?>>, it works. However, I don't know whether all of this makes sense in terms of design.
I look forward to your suggestions.
Enclosed you get the example code.
public abstract class BaseAnimal<E> {
protected E enclosure;
public void setEnclosure(E enclosure) {
this.enclosure = enclosure;
}
public E getEnclosure() {
return enclosure;
}
public abstract String getNoise();
}
public abstract class BaseEnclosure<A> {
protected List<A> animals = new ArrayList<A>();
// some methods...
public List<A> getAnimals() {
return animals;
}
public abstract void resettleTo(BaseEnclosure other);
}
public class Cat extends BaseAnimal<CatEnclosure> {
#Override
public String getNoise() {
return "miiiaaauu";
}
}
public class CatEnclosure extends BaseEnclosure<Cat>{
#Override
public void resettleTo(BaseEnclosure other) {
// hm...
}
}
public class Dog extends BaseAnimal<DogEnclosure> {
#Override
public String getNoise() {
return "wuff";
}
}
public class DogEnclosure extends BaseEnclosure<Dog>{
// some methods...
#Override
public void resettleTo(BaseEnclosure other) {
// hm...
}
}
public class Main {
public static void main(String[] args) {
DogEnclosure doghouse = new DogEnclosure();
Dog dog = new Dog();
// later: JPA
doghouse.getAnimals().add(dog);
dog.setEnclosure(doghouse);
CatEnclosure catbox = new CatEnclosure();
Cat cat = new Cat();
// later: JPA
catbox.getAnimals().add(cat);
cat.setEnclosure(catbox);
// OHOHOH!!!
doghouse.resettleTo(catbox);
}
}
I want to specify that when CatEnclosure.resettleTo(Enclosure) is called, only one Cat Enclosure can be passed. In my current code, a cat could also be placed with a dog.
Assuming here, you dont want CatEnclosure to resettleTo DogEnclosure.
Your scenario is a typical case of circular reference in generics. Based on this post, you need to redefine your base classes as follows:
public abstract class BaseAnimal<A extends BaseAnimal<A, E>, E extends BaseEnclosure<E, A>> {...}
public abstract class BaseEnclosure<E extends BaseEnclosure<E, A>, A extends BaseAnimal<A, E>> {...}
class Dog extends BaseAnimal<Dog, DogEnclosure> {...}
class DogEnclosure extends BaseEnclosure<DogEnclosure, Dog> {...}
// Similarly Cat and CatEnclosure
Now, to prevent cat enclosure resettling to dog enclosure, you need to change the resettleTo method signature as below:
public abstract void resettleTo(BaseEnclosure<E,A> other);
You will not be allowed to compile the below code:
CatEnclosure catEnclosure = new CatEnclosure();
Cat c = new Cat();
c.setEnclosure(catEnclosure);
DogEnclosure dogEnclosure = new DogEnclosure();
Dog d = new Dog();
d.setEnclosure(dogEnclosure);
catEnclosure.resettleTo(dogEnclosure); // Error type mismatch

Pass an implementation of an object without casting

I apologize ahead of time for the title.
I am trying to pass an object Cat that implements Animal to an interface called Groom. In my Groom that handles grooming of Cat implementation, I have to downcast my object to understand what I am grooming, because the Groom interface accepts Animal as the parameter.
public interface Groom {
void groom(Animal animal);
}
public class CatGroomer implements Groom {
void groom(Animal animal) {
Cat cat = (Cat) animal; // <---- how can i avoid this downcast
}
}
public interface Animal {
void do();
void animal();
void things();
}
public class Cat implements Animal {
...
}
Groom could be made generic like this:
interface Groom<T extends Animal> {
void groom(T t);
}
public class CatGroomer implements Groom<Cat> {
void groom(Cat animal) {
}
}

How do I call specific interfaces that are implemented by some objects in a List? Java

Lets say I have a basic animal class
abstract class Animal {
// basic animal code
}
and now I have 2 different animals...
public class Dog extends Animal{
// dog code
}
and
public class Bird extends Animal implements Flyable{
// bird code
#Override
public void fly() {
System.out.println("flap flap");
}
}
Flyable is a simple interface that holds a single method:
public void fly();
if i have a list of animals and i want to loop through it, telling the birds to fly but leaving the dogs alone, how might I achieve this this?
public class Test {
public static List<Animal> animals = new ArrayList<Animal>();
public static void main(String[] args) {
animals.add(new Bird("flop"));
animals.add(new Dog("plop"));
for(Fly f : animals) { // exception here because of mismatch of types
f.flap();
}
}
}
The only option I have found so far is using instanceof to determine whether a class implements the Flyable interface, but a quick google search suggests this is bad for business.
Sources such as:
https://www.quora.com/Is-using-instanceof-in-Java-consider-bad-practice-Any-alternative-to-using-this-keyword
dismiss the use of instanceof as bad design.
I feel like there is an intuitive way of doing this that I have seen before, but cannot find a good solution.
Flyable is a simple interface that holds a single method:
public void fly();
I suppose that was a typo, since the method you call is named flap and not fly.
You can solve the issue by using the instanceof keyword to check if a class is-a superclass.
for(Animal animal : animals) { // loop through all animals
if(animal instanceof Flyable) { // if that animal IS-A Flyable (so it can fly)
((Flyable) animal).flap(); // cast to Flyable and let it fly!
}
}
The only option I have found so far is using instanceof to determine whether a class implements the Flyable interface, but a quick google search suggests this is bad for business
It's not bad at all in my opinion. And it's the only way to accomplish your task.
When you implement the Flyable interface that contains a fly() method declaration in the Animal class, you simply define that each and every subclass of animal has a flying ability.
In my opinion, using instanceof is a bad practice due to the fact that it makes the code pretty confusing: In one hand Dog has a fly() implementation (it indirectly implements the Flyable interface via Animal class), and on the other hand, you don't invoke it when you call fly() on the interface instance.
You have at least 2 ways to prevent Dog from having a flying ability, these are my two favorites:
You can create 2 classes, FlyingAnimal and NonFlyingAnimal which both extend the Animal class while the FlyingAnimal class implements the Flyable interface and the NonFlyingAnimal doesn't.
The Bird will extend the FlyingAnimal class while the Dog will extend the NonFlyingAnimal class.
In this way, you can create a FlyingAnimal list, iterate it, and invoke the fly() method on each and every one of its flying members (the dog isn't one of them).
Use the Strategy Design pattern:
public interface Flyable {
String fly();
}
class ItFlys implements Flyable {
public String fly() {
return "I can fly";
}
}
class CantFly implements Flyable {
public String fly() {
return "I can't fly";
}
}
public class Animal {
private String name;
private double height;
private int weight;
private String favFood;
private double speed;
private String sound;
public Flyable flyingType;
public String tryToFly() {
return flyingType.fly();
}
public void setFlyingAbility(Flyable newFlyType) {
flyingType = newFlyType;
}
}
public class Bird extends Animal{
public Bird() {
super();
flyingType = new ItFlys();
}
}
public class Dog extends Animal{
public Dog() {
super();
flyingType = new CantFly();
}
}
In this way, you set a flying type to each and every subclass of Animal.
When you invoke the fly() method on a Dog class, you will get a "non-flying animal" behavior.
One alternative is to organize your objects such that you don't have to inspect each one in order to determine what to do with it. For example, you might maintain a Kingdom class with various collections of Animal, including a Flyable collection. Iterating over the Flyable collection wouldn't require testing whether each instance was Flyable. If you have other classes that operate on only Flyable objects, they, too, would not have to test each member, leading to cleaner code with less work.
There's a couple of possibilites you can use:
Put fly() in the base class as an abstract method. Make Dog's implementation throw a CannotFlyException, or otherwise implement some "non-flying" behavior. Then iterate over your List<Animal> using
try {
animal.fly();
catch (CannotFlyException() cfe) {
System.out.println("grounded!");
}
Give your Animal() class an abstract method that lists supported operations, then test every member to see if it implements the fly() method:
public abstract class Animal {
private Set<String> behaviors;
public Animal() {
behaviors = new HashSet<String>();
}
public Set<String> getBehaviors() {
return behaviors;
}
}
public class Dog extends Animal {
public Dog() {
super();
behaviors.add("fetch");
}
public String fetch(String fetched) {
return "Dog fetched " + fetched;
}
}
public class Bird extends Animal implements Flyable {
public Dog() {
super();
behaviors.add("fly");
}
#Override
public String fly() {
return "flap flap";
}
}
....
List<Animal> animals = MagicalAnimalListCreator.MakeAnimalList();
for (Animal animal : animals) {
if (animal.getBehaviors().contains("fly")) {
animal.fly();
}
}
You can do it the way you've currently got it, but then try casting every member of your list to Bird and catching a ClassCastException before trying to fly. If the cast succeeds, you've got a Bird and can fly.

How to return Generic type from same method for parent and child classes

Here is my scenario
I've 3 classes.
class Animal {
public getWeight(){ ..... }
public getHeight(){ ..... }
}
class Dog extends Animal {
public getDogType() { ...}
}
class Cat extends Animal {
public getCatType(){....}
}
And there is a different method which returns an Animal type taking an Object as a parameter
public Animal translate(CustomObject o){
... so many calculations here
}
Here translate method returns Animal Object, but I need to use the same method to return Dog and Cat types too without typecasting. I know I have to use Generics here but how can I edit translate method to support Generics, so that I can pass the Class type to its parameter and it returns Cat object if called using Cat parameter and Animal object if called using Animal parameter and Dog object if called using Dog parameter.
eg:- Cat newCat = translate(object, Cat.class); //should return cat object and not animal obj
instead of
Cat newCat = (Cat)translate(object, Cat.class)
Thanks.
You need a self referencing bound:
class Animal<T extends Animal<T>> {
public getWeight(){ ..... }
public getHeight(){ ..... }
public T translate(CustomObject o){
//... so many calculations here
}
}
class Dog extends Animal<Dog> {
//
}
class Cat extends Animal<Cat> {
//
}
You may consider making translate() abstract, allowing subclasses to handle their own implementations.
Try public <T extends Animal> translate(CustomObject o, Class<T> clazz).

How to return generic type from a method in java

I'm new to generics. Here are my classes.
public interface Animal {
void eat();
}
public class Dog implements Animal {
public void eat() {
System.out.println("Dog eats biscuits");
}
}
public class Cat implements Animal {
public void eat() {
System.out.println("Cat drinks milk");
}
}
Now I want these classes to be used in a generic way.
public class GenericExample {
public <T extends Animal> T method1() {
//I want to return anything that extends Animal from this method
//using generics, how can I do that
}
public <T extends Animal> T method2(T animal) {
//I want to return anything that extends Animal from this method
//using generics, how can I do that
}
public static void main(String[] args) {
Dog dog = method1(); //Returns a Dog
Cat cat = method2(new Cat()); //Returns a Cat
}
}
How can I return the generic type (may be a Cat or Dog) from the methods "method1" and "method2". I've several such methods that returns "T extends Animal", so is it better to declare the generic type in a method level or class level.
You cannot have a method returning a generic type, and expect to be able to access that type in the caller of the method without a cast, unless that type can be deduced from the arguments to the method. So the examples in your main won't work.
So you either go without generics, and either cast the return type manually
public Animal method1()
Dog dog = (Dog)method1()
or have the method return the subclass type to start with.
public Dog method1()
Dog dog = method1()
Or you can go with generics, and either specify the type when calling the method
public <T extends Animal> T method1()
Dog dog = <Dog>method1()
or pass some argument from which the type can be deduced (which the second method already satisfies):
public <T extends Animal> T method1(Class<T> classOfreturnedType)
Dog dog = method1(Dog.class)
Also nituce that you only can call method1 from static main if it is static itself.
The method1 simply says it returns an Animal. Return any instance of Animal, and the code will compile:
return new Dog();
The second method says that it returns an animal which is of the same type than the animal given as argument. So you could return the argument itself, and it would compile. You've said which type the method must return, but you haven't said what the method must do and return, so it's impossible to implement it. All I can say is that return animal; would compile.

Categories