0

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);
        }
}
1
  • There is no question asked here. If you can post complete, working code that you're looking to improve, you can try codereview.stackexchange.com Commented Oct 20, 2020 at 22:46

1 Answer 1

1

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
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.