X

Доступ к данным из различных экземпляров одного класса

В Java экземпляры одного класса имеют доступ к полям друг друга. Это может стать интересной проблемой, особенно для новичков. Пример под катом.

Вот такой пример:

public class Main {

 public static void main(String[] args) {

  Employee boss = new Employee("Boss", 1000);
  Employee vasya = new Employee("Vasya", 100);

  System.out.println( "Boss salary: " + boss.getSalary() );
  System.out.println( "Vasya salary: " + vasya.getSalary() );

  boolean vasyaIsBoss = vasya.equals( boss );

  System.out.println( "Vasya is Boss: " + vasyaIsBoss );

  System.out.println( "Boss salary: " + boss.getSalary() );
  System.out.println( "Vasya salary: " + vasya.getSalary() );

 }

}

class Employee
{
 private int salary;
 private String name;

 Employee(String name, int salary) {
  this.name = name;
  this.salary = salary;
 }

 public int getSalary()
 {
  return salary;
 }

 @Override
 public boolean equals(Object emp)
 {
  Employee e = (Employee) emp;
  e.salary = 200; // Change Boss salary
  return name.equals(e.name);
 }
}

Результат выполнения:

Boss salary: 1000
Vasya salary: 100
Vasya is Boss: false
Boss salary: 200
Vasya salary: 100

Как видите, объект Vasya, не только может читать приватные свойства объекта Boss, но так же может и менять их!!! Красота! 🙂

Мне на ум сразу пришла мысль, передать копию объекта, например так:

public class Main {

 public static void main(String[] args) {

  Employee boss = new Employee("Boss", 1000);
  Employee vasya = new Employee("Vasya", 100);

  System.out.println( "Boss salary: " + boss.getSalary() );
  System.out.println( "Vasya salary: " + vasya.getSalary() );

  boolean vasyaIsBoss = vasya.equals( boss.clone() );

  System.out.println( "Vasya is Boss: " + vasyaIsBoss );

  System.out.println( "Boss salary: " + boss.getSalary() );
  System.out.println( "Vasya salary: " + vasya.getSalary() );

 }

}

class Employee
{
 private int salary;
 private String name;

 Employee(String name, int salary) {
  this.name = name;
  this.salary = salary;
 }

 public int getSalary()
 {
  return salary;
 }

 @Override
 public boolean equals(Object emp)
 {
  Employee e = (Employee) emp;
  e.salary = 200; // Change Boss salary
  return name.equals(e.name);
 }

 @Override
 public Employee clone() {
  return new Employee(name, salary);
 }
}

Результат работы теперь тот, который я бы хотел ожидать:

Boss salary: 1000
Vasya salary: 100
Vasya is Boss: false
Boss salary: 1000
Vasya salary: 100

Еще один тест, аналогичный первому, только с экземплярами потомков этого класса:

public class Main {

 public static void main(String[] args) {

  Employee boss = new Employee("Boss", 1000);
  Employee2 vasya = new Employee2("Vasya", 100);

  System.out.println( "Boss salary: " + boss.getSalary() );
  System.out.println( "Vasya salary: " + vasya.getSalary() );

  boolean vasyaIsBoss = vasya.equals( boss );

  System.out.println( "Vasya is Boss: " + vasyaIsBoss );

  System.out.println( "Boss salary: " + boss.getSalary() );
  System.out.println( "Vasya salary: " + vasya.getSalary() );

 }

}

class Employee
{
 private int salary;
 private String name;

 Employee(String name, int salary) {
  this.name = name;
  this.salary = salary;
 }

 public int getSalary()
 {
  return salary;
 }

 @Override
 public boolean equals(Object emp)
 {
  Employee e = (Employee) emp;
  e.salary = 200; // Change Boss salary
  return name.equals(e.name);
 }

}

class Employee2 extends Employee {

 Employee2(String name, int salary) {
  super(name, salary);
 }

}

Результат, такой же как и в первом случае:

Boss salary: 1000
Vasya salary: 100
Vasya is Boss: false
Boss salary: 200
Vasya salary: 100

и еще один пример:

public class Main {

 public static void main(String[] args) {

  Employee boss = new Employee("Boss", 1000);
  Employee2 vasya = new Employee2("Vasya", 100);

  System.out.println( "Boss salary: " + boss.getSalary() );
  System.out.println( "Vasya salary: " + vasya.getSalary() );

  boolean vasyaIsBoss = vasya.equals( boss );

  System.out.println( "Vasya is Boss: " + vasyaIsBoss );

  System.out.println( "Boss salary: " + boss.getSalary() );
  System.out.println( "Vasya salary: " + vasya.getSalary() );

 }

}

class Employee
{
 protected int salary;
 protected String name;

 Employee(String name, int salary) {
  this.name = name;
  this.salary = salary;
 }

 public int getSalary()
 {
  return salary;
 }

 @Override
 public boolean equals(Object emp)
 {
  Employee e = (Employee) emp;
  e.salary = 200;
  return name.equals(e.name);
 }

 @Override
 public Employee clone() {
  return new Employee(name, salary);
 } 

}

class Employee2 extends Employee {

 Employee2(String name, int salary) {
  super(name, salary);
 }

 @Override
 public boolean equals(Object emp)
 {
  Employee e = (Employee) emp;
  e.salary = 300;
  return name.equals(e.name);
 }

}

Результат:

Boss salary: 1000
Vasya salary: 100
Vasya is Boss: false
Boss salary: 300
Vasya salary: 100

Как видите, в этом случае мне пришлось поменять модификаторы доступа к переменным в родительском классе с private на protected, т.к. наследуемый класс не имеет доступа к private переменным родительского класса. А так же я переопределил equals.

Выводы:

  • Нужно всегда помнить, что различные экземпляры одного класса имеют доступ ко всем методам и полям друг друга!
  • Потомки имеют доступ ко всем методам родительского класса, если метод наследуется из родителя!
  • Потомки не имеют доступ к приватным методам родительского класса, при доступе к ним из класса наследника!
  • В случае если нужно передать объект и его надо защитить, то нужно передавать его копию!
Категории: Java Java labs

Комментарии (2)

  • В этом случае ничего у вас не выйдет. А в вашем примере protected используется как по-умолчанию, да и все.

  • пример с protected будет интереснее, если родителя и детенка разнести по разным пакаджам.