Проблема с корректным обновлением статической переменной во всех объектах

#java #object #static-variables

#java #объект #статические переменные

Вопрос:

Я хочу иметь переменную, которая подсчитывает все количество сотрудников во всех созданных объектах в main. Вот как далеко я продвинулся:

 public class test {

    public static void main(String[] args) {
        Department dep1 = new Department();
        Department dep2 = new Department("CSTI", 30);
        dep1.setEmp(20);
        dep2.setEmp(40);
        System.out.println(dep1.totalNumEmp);
        // Outputs 60
        dep1 = dep2; // here is where I get lost
        dep1.setEmp(10);
        System.out.println(dep1.numEmp   " "   dep2.numEmp);// outputs 10 10
        System.out.println(dep1.totalNumEmp);// Outputs 30. When it needs to output 20, because dep1 and dep2 are now
                                                // both 10
    }
}

class Department {

    String name;
    int numEmp;

    public static int totalNumEmp;

    Department() {
    }

    Department(String newName, int newNum) {
        name = newName;
        numEmp = newNum;
        totalNumEmp  = numEmp;
    }

    public void setEmp(int newNum) {
        totalNumEmp -= numEmp;
        numEmp = newNum;
        totalNumEmp  = numEmp;
    }
}
  

Моя проблема в том, что я понятия не имею, как я должен корректно обновлять totalNumEmp один раз dep1 = dep2 . Я должен найти способ корректно totalNumEmp обновляться после того, как dep1 указано на dep2 ссылку. Я знаю, что мог бы легко это сделать dep1.setEmp(dep2.numEmp) и избежать путаницы totalNumEmp , но я должен знать, как это сделать, dep1 указав на dep2 .

Ответ №1:

Отказ от ответственности: Я постараюсь сделать все как можно проще. Нет необходимости в инкапсуляции данных, шаблонах, параллелизме или чем-то еще. Сделайте это как можно более простым при изучении основ.

Прежде всего, вам нужно понимать, что вы делаете.

наш учитель хочет, чтобы у нас была переменная, которая подсчитывает все количество сотрудников…

Здесь я вижу Department класс с setEmp методом, который, похоже, увеличивает количество сотрудников при каждом вызове. Я не думаю, что это то, что имел в виду ваш учитель с

…во всех созданных объектах в main.

Скорее всего, ваш учитель хочет, чтобы у вас было два класса (я предполагаю, что вы создали Department по какой-то причине):

 Employee
  

которая назначается

 Department
  

Снова

…подсчитывает все количество сотрудников во всех созданных объектах в main

Мы можем интерпретировать это двумя способами

  1. Ваш учитель хочет, чтобы вы подсчитали все созданные Employee файлы (как следует из названия вопроса)
  2. Ваш учитель хочет, чтобы вы посчитали все Employee s за Department

Давайте начнем с варианта 1

Я пропущу Department класс, поскольку он на самом деле не входит в область видимости, и перейду непосредственно к количеству созданных сотрудников.
Что скажет назначенная задача, так это просто подсчитать созданные объекты, что означает созданные Employee s.

Вот как может выглядеть Employee класс

 public class Employee {
   // Count of the created employees
   public static int count = 0;

   // ... Class fields

   public Employee(
       final Department department,
       final String name,
       final String surname) {
      // ... Assign arguments to class fields

      // A new employee has been created. Increment the counter!
        count;    
   }

   ... 
}
  

Это статическое поле

 public static int count = 0;
  

увеличивается при каждом создании новой Employee .
Вы сможете получить к ней доступ через

 final int total = Employee.count;
  

Теперь, вариант 2

Поскольку вам нужно подсчитывать Employee s для каждого Department , вам нужно увеличить своего рода количество внутри Department класса. Вот как тогда мог бы выглядеть Department класс

 public class Department {
   private final List<Employee> employees;
   private final String name;

   public Department(final String name) {
      this.employees = new ArrayList<Employee>();
      this.name = name;
   }

   public String getName() {
      return name;
   }

   public List<Employee> getEmployees() {
      return employees;
   }

   public int getEmployeeCount() {
      return employees.size();
   }

   public void addEmployee(final Employee employee) {
      employees.add(employee);
   }
}
  

Вы можете видеть, что этот класс владеет

  • имя
  • список назначенных сотрудников ( private final List<Employee> employees )

Тогда у нас есть Employee класс, подобный тому, который я описал выше, но следите за изменениями

 public class Employee {
   // ... Class fields

   public Employee(
       final String name,
       final String surname) {
      // ... Assign arguments to class fields
   }

   ... 
}
  

Здесь у нас просто обычный класс (Pojo). Как мы это используем? Следуйте комментариям в коде

 public static void main(final String[] args) {
   final Department dep1 = new Department("dep1");
   dep1.addEmployee(new Employee("Name1", "Surname1"));
   dep1.addEmployee(new Employee("Name2", "Surname2"));

   final Department dep2 = new Department("dep2");
   dep2.addEmployee(new Employee("Name3", "Surname3"));

   // Now we have two departments.
   // We can retrieve the count of employees for each using
   final int dep1Count = dep1.getEmployeeCount();
   final int dep2Count = dep2.getEmployeeCount();

   // And we can have the total
   final int total = dep1Count   dep2Count;
}
  

Я не включил объекты или разделы о синхронизации или параллелизме, поскольку я думаю, что вы все еще в начале и не нужно путаться с этим материалом.

Комментарии:

1. Спасибо, ваш ответ очень помог!

2. @AidanHigginbotham Нет проблем 🙂 Вы можете настроить мой код в соответствии со своими конкретными потребностями уже сейчас, но у вас есть надежная отправная точка.

Ответ №2:

System.out.println(dep1.totalNumEmp) печатает 30, потому что переменная totalNumEmp является статической в отделе моделей.

Почему вы хотите, чтобы общее количество сотрудников всех отделов составляло dep1.totalNumEmp? На мой взгляд, вы не можете сохранить общее количество сотрудников всех отделов в одном экземпляре модели отдела, потому что каждая модель должна содержать ваши собственные данные.

Чтобы подсчитать общее количество сотрудников, вы должны сделать что-то вроде:

 Integer totalEmployees = dept1.totalNumEmp   dept2.totalNumEmp;
  

Obs: Я рекомендую вам использовать шаблон Get для доступа к данным в моделях и не сохранять закрытые поля с модификатором «public».
Пример:

 Integer totalEmployees = dept1.getTotalNumEmp()   dept2.getTotalNumEmp();
  

Ответ №3:

Избавьтесь от переменной totalNumEmp, она бесполезна и не относится к отделам объектно-ориентированного программирования, поскольку она не является атрибутом каждого из отделов.

В вашем основном, создайте arraylist ваших отделов

 ArrayList<Departments> allDepartments = new ArrayList<>();
allDepartments.add(dep1);
allDepartments.add(dep2);
//...
  

а затем создайте статический метод, который будет подсчитывать общее количество ваших сотрудников:

 private static int countTotalNum(ArrayList<Departments> allDepartments) {
    AtomicInteger sum = new AtomicInteger();
    allDepartments.forEach(department -> sum.addAndGet(department.numEmp));
    return sum.get();
}
  

Ответ №4:

Проблема заключается в том, как вы структурировали свой код: вы изменяете значение totalNumEmp в setEmp() установщике, а статическое поле и установщик принадлежат одному классу.

Из-за этого следующее:

 dep1 = dep2;     // here dep1 starts referencing dep2
dep1.setEmp(10);
  

фактически установщик будет выполнен один раз (вероятно, это то, что вы хотели), но totalNumEmp также будет изменен только один раз (и вы исключаете, что его нужно изменить дважды, чтобы правильно установить totalNumEmp значение 20).

Я бы рекомендовал изменить следующее в вашем дизайне:

  1. Сохраняйте totalNumEmp в отдельном классе или генерируйте его на лету.
  2. Не делайте этого, так как это плохая практика: dep1 = dep2 . Вместо этого используйте copying constructor ( public Department(Department other) ).
  3. Подумайте о параллелизме, например, рассмотрите возможность использования AtomicInteger вместо int или синхронизации.