Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating new object in abstract class in Java

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?

like image 804
stephbytes Avatar asked Sep 22 '12 18:09

stephbytes


People also ask

Can I create an object of an abstract class?

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.

Why we Cannot create the object of abstract class in Java?

We cannot instantiate an abstract class in Java because it is abstract, it is not complete, hence it cannot be used.

How many objects can be created from an abstract class in Java?

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.


1 Answers

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( ... ));
        // ...
    }
}
like image 163
Brian Avatar answered Oct 24 '22 10:10

Brian