Class inheritance and generic types - java

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

Related

How to use a type bounded parameter interface using generics

I have the class Test, which has an instance variable animalWithProps of type T (this variable should be of a type that implements AnimalProperty). However, when I try this with a class that implements this interface (Dog), I get an error for invalid types: Dog cannot be converted to T
interface AnimalProperty {
String sound();
}
class Dog implements AnimalProperty {
public String sound() {
return "bark";
}
}
class Test<T extends AnimalProperty> {
T animalWithProp;
public Test() {
this.animalWithProp = new Dog();
System.out.println(animalWithProp.sound());
}
}
When I try doing AnimalProperty prop = new Dog(), it works. Why can't I have this type bounded parameter?
In your example, T is a sibling of Dog in the inheritance tree. For example, it could be Cat. Would it make sense to do Cat c = new Dog()? Of course it wouldn't. Here's what you want:
class Test {
AnimalProperty animalWithProp;
public Test() {
this.animalWithProp = new Dog();
System.out.println(animalWithProp.sound());
}
}

How to write a method in superclass whose parameter type is restricted to another object belonging to the same subclass of the calling object

I'm new to Java programming. Please consider the following code snippet.
public class Animal {
public void mate( /*what should I put here?*/ anotherAnimal ) {
}
}
public class Cat extends Animal {
}
public class Dog extends Animal {
}
I want to write the method Animal.mate() in such a way that, when the method is called from a subclass object, the argument fed to the method must be an object of the same subclass, otherwise a compiler error is triggered. For instance:
Cat cat = new Cat();
Dog dog = new Dog();
Animal randomAnimal = new Animal();
Cat trueLove = new Cat();
cat.mate( dog ); // raises a compiler error
cat.mate( randomAnimal ); //compiler error
cat.mate( trueLove ); //passes compiler check
Is what I'm asking possible? I have a vague feeling that it might be possible to do it using generics.
There's no way to make the compiler prevent all bad calls. Even if you parameterize Animal, it would still be possible for something like cat.mate(dog) to be executed at runtime.
If this is required by your business logic, then your best bet is to validate, with something like:
public class Animal {
public final void mate(Animal anotherAnimal ) {
if(!this.getClass().equals(anotherAnimal.getClass())) {
throw new IllegalArgumentException();
}
}
}
If you're doing this mainly to improve compile-time type checking, then you can use generics, knowing the limitations:
class Animal<T extends Animal<T>> {
public final void mate(T anotherAnimal) {
}
}
This will work if your API users use the subclasses rather than the Animal type, and they don't use raw types.
Cat c = new Cat();
c.mate(new Cat());
c.mate(new Dog());//fails
Animal animal = c; //raw type
animal.mate(new Dog()); //only a warning
your problem is about to Polymorphism.
use super class as parameter type in mate method.super class is Animal.
this is the code:
public class Animal {
public void mate(Animal animal) {
System.out.println("Animals mating");
}
#Override
public String toString() {
return "Animal";
}
public class Dog extends Animal {
#Override
public String toString() {
return "Dog";
}
public class Cat extends Animal {
#Override
public void mate(Animal obj) {
System.out.println("cat mating with " + obj );
}
#Override
public String toString() {
return "cat";
}}
and run your code in main method. errors have gone and this is the answer:
cat mating with Dog.
cat mating with Animal.
cat mating with cat.
for better answer instead of saying cat or dog , you can define a name field in Animal class.

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).

Categories