简体   繁体   English

Java:静态父/子变量和方法

[英]Java: Static Parent/Child variables and methods

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. 我试图在Java中创建一个父类,该类将静态变量传递给它的每个子类,以便每个子类都有自己的副本。

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. 我想我可以用<T>做到这一点,就像他们处理List<T> ...但是我对此并不甚了解,甚至被称为什么。

Any help would be great. 任何帮助都会很棒。

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: 假设我们正在谈论“现实世界”的OO设计和最佳实践-那么问题中显示的代码将为数小时的“为什么不这样做OO”讨论提供材料:

static is more of an abnormality in good OOP. 静态在良好的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. OOP中的关键是多态性-通过子类化和覆盖方法改变行为的能力。 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. 然后提出一个遵循良好OOP惯例的设计-而不是否定它们。

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... 您会看到,真正的“业务逻辑对象”应该有非常不同的用途。您创建类,并实例化这些类的对象,因为它在您的模型中是有意义的。并且您的模型是“现实世界”对象的模型来自那里:一只狗或猫知道其他的狗或猫吗?不是真的。您的代码也应该如此。如果您有充分的理由保留“实例化对象列表”,则使用一个特定的类来表示。为了使动物成为动物管理者列表,并且为了实现对使用静态的需求,您可以使用工厂来创建对象,而该工厂可以利用该对象ListKeeper实现。仅作记录:您了解仅将引用保存在这样的列表中会导致内存泄漏吗?因为这些对象永远不会变成垃圾,因此您只需添加新对象...

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. 因此,再次:您不需要或不需要该静态继承列表-因为在一个好的OO模型中,您将拥有一个单独的类来管理此类事情。

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. 这意味着您必须更新Dog类-尽管“在不同列表中组织Dog”与Dog类本身无关

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". 您不只是将钱包放在桌子上并告诉孩子们:“现在就去随便使用我的信用卡”。

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 输出:狗狗狗狗猫猫猫

You can use a map in Animal 您可以在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: main您将拥有:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM