I have two objects which use really similar methods, save for one line. For example:
public class Cat extends Animal
public class Dog extends Animal
And they both use a breed
method in the abstract class Animal
. One calls new Dog()
, and the other new Cat()
. Right now I just have it declared as abstract public void breed();
in Animal, but is there a way I can generalize it so I don't have to make it an abstract method to be overridden?
You can't create an object of an abstract class type. However, you can use pointers and references to abstract class types. You create an abstract class by declaring at least one pure virtual member function.
We cannot instantiate an abstract class in Java because it is abstract, it is not complete, hence it cannot be used.
Abstract base class may be used only as framework from which other class will be derived, while the individual objects of this class will never be instantiated. Talking in terms of java, an abstract class can have any number of instances but can't have any object.
There are many ways to do this, assuming by breed
you mean "create children of me."
Reflection
First is to use reflection. If you have a no-args constructor for your classes, this is as easy as calling Class.newInstance:
public Animal breed() {
try {
return (Animal) getClass().newInstance();
} catch (Exception ex) {
// TODO Log me
return null;
}
}
If you don't have a no-args constructor in all your subclasses, you'll have to have a uniform constructor across all your subclasses. For example, if you have Cat(int, String)
and Dog(int, String)
, then you need to get the constructor via Class.getConstructor
and invoke newInstance
on that:
return (Animal) getClass().getConstructor(int.class, String.class).newInstance(0, "Unnamed");
int
and String
here may be age and name, for example. This is how you do this with reflection.
Providers
Another way is to use this simple interface:
public interface Provider<T> {
T create();
}
Then have your abstract class take an instance of this in its constructor:
public abstract class Animal {
private final Provider<Animal> animalProvider;
protected Animal( ... , Provider<Animal> animalProvider) {
// ...
this.animalProvider = animalProvider;
}
public Animal breed() {
return animalProvider.create();
}
}
Then your subclasses will pass a Provider<Animal>
to the superclass which will create new instances of the subclass:
public class Dog extends Animal {
public Dog( ... ) {
super( ... , new DogProvider());
// ...
}
private static class DogProvider implements Provider<Animal> {
public Animal create() {
return new Dog( ... );
}
}
}
Do the same for other subclasses as well.
Note: if by breed
you mean "get the type of me," then you should edit your question to say so. If this is what you meant, then this is a viable solution:
public abstract class Animal {
protected final Breed breed;
protected Animal( ... , Breed breed) {
// ...
this.breed = breed;
}
public Breed getBreed() {
return breed;
}
}
I recommend following the get
/set
conventions for data container methods. Java has bean classes designed to handle these naming conventions, and it's more or less a standard across many platforms. For your subclasses:
public class Dog extends Animal {
public Dog( ... ) {
super( ... , new Breed( ... ));
// ...
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With