0

I am trying to create a parent class in Java that passes static variables to each of it's child classes so that each of the child classes has its own copy.

Here is an example of the code:

import java.util.*;

public class JavaFiddle {
    public static void main(String[] args) {
        Animal rex = new Dog("Rex", 3.2, 'M');
        Animal luna = new Dog("Luna", 1.2, 'M');
        Animal sadie = new Dog("Sadie", 0.1, 'F');
        Animal daisy = new Dog("Daisy", 5.9, 'F');
        Animal snowball = new Cat("Snowball", 3.8, 'M');
        Animal tiger = new Cat("Tiger", 9.8, 'M');

        System.out.println(Dog.getCount()); // output => 4
        System.out.println(Cat.getCount()); // output => 2
    }
}

class Animal {
    protected static final List<Animal> list = new ArrayList<>(); // Each child class should get it's own static list

    String name;
    double age;
    char gender;


    Animal (String name, double age, char gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;

        list.add(this); // This should add the child object to the the static list in the child class
    }

    public static int getCount() { // This should return the size of the static list for the child class
        return list.size();
    }
}

class Dog extends Animal {
    protected static final List<Dog> list = new ArrayList<>(); // I don't want to have to add this for each child class. It should just get a copy from the parrent.

    Dog (String name, double age, char gender) {
        super(name, age, gender);

        list.add(this); // I don't want to have to add this for each child class. It should just be added from the parrent.
        // other stuff
    }

    public static int getCount() { // I don't want to have to add this for each child class. It should just get a copy from the parrent.
        return list.size();
    }
}

class Cat extends Animal {
    protected static final List<Cat> list = new ArrayList<>(); // I don't want to have to add this for each child class. It should just get a copy from the parrent.

    Cat (String name, double age, char gender) {
    super(name, age, gender);

        list.add(this); // I don't want to have to add this for each child class. It should just be added from the parrent.
        // other stuff
    }

    public static int getCount() { // I don't want to have to add this for each child class. It should just get a copy from the parrent.
        return list.size();
    }
}

I don't want to have to recreate each of these classes and variables inside of each of the child classes. That would kind of defeat the purpose of having the parent.

Is this even possible or am I going to have to build it for each one? I think I might be able to do it with the <T> thing like the way they do the List<T> ... but I don't know enough about it or even what that is called.

Any help would be great.

3
  • Why does it have to be static? It seems to be at odds with the function of the list. Commented Jan 26, 2018 at 19:14
  • 1
    What problem do you want to solve with this approach? Might be an xy problem. Why does a cat need to hold a list of cats? Commented Jan 26, 2018 at 19:15
  • The <T> thing are generics Commented Jan 26, 2018 at 19:26

3 Answers 3

1

The technical solution how to do that is outlined in the other answer.

But beyond that, I have a distinct non-answer here: don't do this!

Assuming that we are talking about "real world" OO design and best practices - then the code shown in the question would give material for hours of extensive "why to not do OO like this" discussions:

static is more of an abnormality in good OOP. So is the idea of exposing fields to subclasses. The key thing in OOP is polymorphism - the ability to change behaviour by subclassing and overriding methods. As soon as you start using static say goodbye to polymorphism. And then: fields are an implementation detail - they should not be used by other classes.

If you ignore these basic rules you end up with code that is tightly coupled all over the place. The idea of using different classes is to build independent units that can work in isolation as much as possible.

Your approach boils down to the exact opposite of that. Chances are that you will be unable to make single changes in one place - as you most likely will have to change other places most of the time.

In that sense: step back and look again at the problem you intend to solve. And then come up with a design that follows good OOP practices - instead of negating them.

To give some more actual suggestions: on a first glance, it might look very convenient to have a static list inside your classes that count the number of instances. But this is a direct violation of the Single Responsibility Principle. You see, real "business logic objects should have a very distinct purpose. You create classes, and instantiate objects of these classes because it makes sense in your model. And your model, is well, a model of the "real world" thing you intend to represent. Coming from there: does a dog or cat know about other dogs or cats? Not really. And so should be your code. If you have good reasons to keep "lists of instantiated objects" - then use a specific class for that. You are trying to make Animals also a List-of-Animals-manager. And in order to implement that you have zero need for using static anyway. You could use a factory to create objects, and that factory could make use of that ListKeeper implementation. And just for the record: you understand that simply keeping references in a list like this causes a memory leak? Because these objects can never turn into garbage, therefore you just keep adding new objects...

So, again: you don't need or want that static inherited list - because in a good OO model, you would have a distinct class responsible for managing such things.

Imagine for example that at one point that single list doesn't work any more. Maybe you want to organize different dogs in different lists? That means you have to update the Dog class - although "organizing Dogs in different lists" has nothing to do with the Dog class itself.

And then you want your classes to be open for extension but closed for modification. In your case, that would rather look like this:

public abstract class Animal {
  private final String name;

  public Animal(String name) { 
    this.name = Objects.requireNonNull(name, "name must not be null"); }

  private final String getName() { return name; }

  public abstract foo();
  public abstract String getEnhancedName();

In other words: you only use protected and "field inheritance" if there are good reasons to do so. Because, as said: fields are implementation details - and no other class (either your children) should know about such things. Or do you make your credit card available to your children? No - if at all you provide a "getter" for that which allows you to keep a certain amount of control. You don't just put your wallet on the table and tell your kids: "now go and use my credit card as you want to".

Sign up to request clarification or add additional context in comments.

4 Comments

I disgree completely. Static is not an abnormality whatsoever, static is simply stating that the field in question does not require an instance of that object to be used, and that the field's value is shared by all objects of that type and subtypes. With that being said this is incredibly useful and used all the time.
Also exposing fields to subclasses does the opposite creating "tightly coupled code". Lets say he decides that Animals no longer have a "name" and instead they should have an "id". With your logic he would have to go into every single class and change "name" field to "id" instead of just the changing the field in the parent class. Makes no sense.
@RobOhRob You might be correct when we talk about a small programming exercise. But in the real world, your comments do not apply. In the real world, you are super careful about using static for business logic code, and the same goes for making fields protected. If you don't adhere to such rules, working with dozens or 100s of people on the same code will quickly turn into a nightmare.
@RobOhRob Of course static is used often for utility code. Like the Collections methods, or stuff within java.lang.Objects. But here we are talking about the business logic of a design. And there using static is almost a no-go.
0
import java.util.*;

public class Animal {

    protected static final List<Animal> list = new ArrayList<>(); // Each child class should get it's own static list

    String name;
    double age;
    char gender;

    Animal(String name, double age, char gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;

        list.add(this); // This should add the child object to the the static list in the child class
    }

    public static int getCount() { // This should return the size of the static list for the child class
        return list.size();
    }
}

class Dog extends Animal {
    Dog(String name, double age, char gender) {
        super(name, age, gender);

    }
}

class Cat extends Animal {   
    Cat(String name, double age, char gender) {
        super(name, age, gender);
    }

    public static void main(String[] args) {
        Animal rex = new Dog("Rex", 3.2, 'M');
        Animal luna = new Dog("Luna", 1.2, 'M');
        Animal sadie = new Dog("Sadie", 0.1, 'F');
        Animal daisy = new Dog("Daisy", 5.9, 'F');
        Animal snowball = new Cat("Snowball", 3.8, 'M');
        Animal tiger = new Cat("Tiger", 9.8, 'M');

        for(Animal anim : Animal.list){
            if(anim instanceof Dog){
                System.out.println("Dog");
            }else if(anim instanceof Cat){
                System.out.println("Cat");
            }
        }
    }
}

This outputs: Dog Dog Dog Dog Cat Cat

Comments

0

You can use a map in Animal

public class Animal {
  private static final Map<Class, List<Animal>> map = new HashMap<>();

  Animal (String name, double age, char gender) {
    //...
    map.computeIfAbsent(this.getClass(), key -> new ArrayList<>()).add(this);
  }

  public static int getCount(Class clazz) {
    return map.get(clazz).size();
  }
}

public class Dog extends Animal {
   Dog(String name, double age, char gender) {
      super(name, age, gender);
   }
   //optional
   public static int getCount() {
     return Animal.getCount(Dog.class);
  }
}

And in main you'll have:

System.out.println(Animal.getCount(Dog.class)); // output => 4
System.out.println(Animal.getCount(Cat.class)); // output => 2

//or
System.out.println(Dog.getCount()); // output => 4
System.out.println(Cat.getCount()); // output => 2

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.