Чи підзаклади успадковують приватні поля?


245

Це питання інтерв'ю.

Чи підкласи успадковують приватні поля?

Я відповів "Ні", тому що ми не можемо отримати доступ до них за допомогою "звичайного способу OOP". Але інтерв'юер вважає, що вони успадковуються, оскільки ми можемо отримати доступ до таких полів опосередковано або за допомогою рефлексії, і вони все ще існують в об'єкті.

Після повернення я знайшов таку цитату в javadoc :

Приватні члени в суперкласі

Підклас не успадковує приватних членів свого батьківського класу.

Чи знаєте ви якісь аргументи на думку інтерв'юера?


33
Я колись був у подібній ситуації, і зрозумів, що навіть не хочу працювати в компанії, де інтерв'юер знає про Яву менше, ніж я. :)
biziclop

48
Інтерв'юер іноді не погоджується з вами, навіть коли він знає, що ви маєте рацію. Хороший інтерв'ю спробує дізнатися про вас більше, ніж ваші технічні знання.
Енді Томас

4
@DigitalRoss Чи погано написана специфікація мови Java? Див RD01 відповідь: stackoverflow.com/questions/4716040 / ...
OscarRyz

9
@Andy Thomas-Cramer Я також не хотів би працювати з людьми, які свідомо брешуть, щоб перевірити мою реакцію.
biziclop

4
Ну, я думаю, нам слід спочатку розібратися у значенні поняття "успадкування" на Java. Підклас не має приватного поля, а підклас має приватне поле, але доступ до нього не може бути різним, який саме стосується точного значення успадкування на Java?
MengT

Відповіді:


238

Більшість плутанини у питанні / відповідях тут оточує визначення спадкування.

Очевидно, як @DigitalRoss пояснює, ОБ'ЄКТ підкласу повинен містити приватні поля його надкласу. За його словами, відсутність доступу до приватного члена не означає, що його там немає.

Однак. Це відрізняється від поняття спадкування для класу. Як і у світі java, де питання про семантику арбітром є специфікація мови Java (на даний момент 3-е видання).

Як зазначає JLS ( https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.2 ):

Члени класу, які оголошені приватними, не успадковуються підкласами цього класу. Тільки члени класу, які оголошені захищеними або загальнодоступними, успадковуються підкласами, оголошеними в пакеті, відмінному від того, в якому оголошено клас.

Це стосується точного питання, яке задає інтерв'юер: " підкази кластери успадковують приватні поля". (акцент додав я)

Відповідь - ні. Вони цього не роблять. ОБ'ЄКТИ підкласів містять приватні поля їхніх суперкласів. Сам підклас НЕ ПОВІДОМЛЯ про приватні поля свого надкласу.

Це семантика педантичного характеру? Так. Це корисне запитання про інтерв'ю? Напевно, ні. Але JLS встановлює визначення для світу Java, і робить це (в даному випадку) однозначно.

ВЕДЕНО (видалено паралельну цитату з Bjarne Stroustrup, яка через різницю між java та c ++, ймовірно, лише додає плутанини. Я дам свою відповідь на JLS :)


3
@digital чому зітхне. Я розумію, ти вважаєш, що ти маєш рацію. Я не погоджуюся з вами, що наслідування об'єктів - це те, чому навчають / думають більшість програмістів. Але визначення JLS стосується безпосередньо початкового питання. Це семантика так, але JLS визначає визначення, а не ти чи я
robert_x44

4
Один із способів узгодити все це - просто визнати, що слово "спадкувати" використовується двома дуже різними способами для опису взаємозв'язку похідних та батьківських класів, принаймні, у світі Java. Так, JSL є авторитетним. Так, це означає, що ви можете скористатися "успадкувати" у той нещасний спосіб. Але все одно очевидно, що підкласи хизуються (оскільки зараз у нас немає слова) приватні поля їх батьківського класу.
DigitalRoss

1
@digital Вони в об’єкті класу. не сам клас. Симула називала їх об'єднаними об'єктами. Коли був створений об'єкт підкласу, він складався з об'єднаних "префіксних об'єктів". Об'єкт надкласового класу був об'єктом префікса, який міг сам містити інші об'єкти префікса. Я думаю, що заявляти, що JLS має "явно погані формулювання", це зарозуміло. Щодо того, яке слово ми вживаємо, успадкування звичайно. Немає нічого поганого в застосуванні трохи неоднозначної термінології. Це відбувається постійно. Але це не означає, що немає точного визначення.
robert_x44

1
@digital Ми, звичайно, можемо погодитися, що слово вживається по-різному. :) Ми також можемо погодитися, що питання інтерв'ю, яке залежить від неоднозначного терміну, напевно, не є вдалим.
robert_x44

2
У когось є посилання від Java / Oracle на тему "Об'єкти підкласу містять приватні поля своїх суперкласів"? Я згоден з цим, але не можу знайти жодних офіційних документів, які б це говорили.
MengT

78

Так

Важливо усвідомити, що хоча є два класи, є лише один об’єкт.

Так, так, звичайно, він успадкував приватні поля. Вони, імовірно, є важливими для належної функціональності об'єкта, і хоча об’єкт батьківського класу не є об'єктом похідного класу, екземпляр похідного класу здебільшого є безумовно екземпляром батьківського класу. Не обходиться без усіх полів.

Ні, ви не можете безпосередньо отримати доступ до них. Так, вони передаються у спадок. Вони повинні бути.

Це гарне запитання!


Оновлення:

Помилка, "Ні"

Ну, мабуть, ми всі чомусь навчились. Оскільки в JLS виникли точні формулювання "не успадковані", правильно відповісти "ні" . Оскільки підклас не може отримати доступ або змінити приватні поля, то, іншими словами, вони не успадковуються. Але дійсно є лише один об’єкт, він дійсно містить приватні поля, і тому, якщо хтось сприймає формулювання JLS та підручника неправильно, зрозуміти об'єкти OOP, Java та те, що насправді відбувається, буде досить важко.

Оновити для оновлення:

Суперечка тут передбачає принципову неоднозначність: про що саме йде мова? Об'єкт? Або ми говоримо в якомусь сенсі про сам клас? Дозволяється велика широта при описі класу на відміну від об'єкта. Отже, підклас не успадковує приватні поля, але об'єкт, який є екземпляром підкласу, безумовно, містить приватні поля.


2
@ Ma99uS. Звичайно, вони повторно використовуються. Ось і вся суть спадщини. Без них похідний тип не був і не міг би бути екземпляром батьківського типу. OOP було б безглуздо. Поліморфні типи перестали б працювати . Розуміння того, що існує лише один об’єкт, і ви є екземпляром батьківського типу, є вирішальним для розуміння OOP. Ви повинні пройти цю проблему, щоб її взагалі зрозуміти.
DigitalRoss

2
Не впевнений, що приклад батька дуже хороший, оскільки поле може бути успадковано, поки батьківський клас все ще живе, а також є це поле. Якби спадщина працювала таким чином, я міг би успадкувати гроші свого батька, поки він живий, і він міг би зберегти ті самі гроші. У моїх дітей кожен міг би мати свої гроші і мої гроші.
Пітер Лоурі

2
@ Петер Лоурі не сперечається чи що-небудь, але ось що я думаю. Батько мав car, він зберігав його в privateшафці, від якої дитина не є ключем. Ви дійсно успадковуєте, carале це марно для вас. Так що, практично, ви не отримуєте користі від спадщини.
Нішант

1
@DigitalRoss. Я розумію вашу думку. Mhh, ми можемо сказати, що значення є через не завантажене спадкове визначення батьків . :) Я думаю, що специфікація JVM мала б правильну відповідь на це "НЕ СЛОВО", яке ми шукаємо. java.sun.com/docs/books/jvms
OscarRyz

5
-1, Специфікація мови Java чітко визначає, що вони не передаються у спадок. Ні ifs, ні buts. Їх просто немає. Будь-яке інше визначення успадкування є неправильним у контексті Java.
biziclop

21

Ні. Приватні поля не успадковуються ... і саме тому було винайдено захищене . Це за дизайном. Я думаю, це виправдало існування захищеного модифікатора.


Зараз підходимо до контекстів. Що ви маєте на увазі під успадкованим - якщо він є в об'єкті, створеному з похідного класу? Так.

Якщо ви маєте на увазі, чи може це бути корисним для похідного класу. Ну, ні.

Тепер, коли ви переходите до функціонального програмування, приватне поле суперкласу не успадковується змістовно для підкласу . Для підкласу приватне поле суперкласу - це те саме, що приватне поле будь-якого іншого класу.

Функціонально це не передається у спадок. Але в ідеалі це так.


Добре, щойно переглянувши підручник Java, вони цитують це:

Приватні члени в суперкласі

Підклас не успадковує приватних членів свого батьківського класу. Однак якщо у суперкласу є загальнодоступні або захищені методи доступу до його приватних полів, вони також можуть використовуватися підкласом.

посилайтеся: http://download.oracle.com/javase/tutorial/java/IandI/subclasses.html

Я згоден, що поле є. Але підклас не отримує жодної привілеї в цьому приватному полі. Для підкласу приватне поле є таким же, як і будь-яке приватне поле будь-якого іншого класу.

Я вважаю, що це суто питання точки зору. Ви можете сформулювати аргумент з будь-якої сторони. Краще виправдати обидві сторони.

 


2
Це неправильно. Ви не можете отримати доступ до них, це правильно. Але вони повинні бути успадковані, як я пояснив.
DigitalRoss

1
відмінна відповідь !!! +1 за I believe it's purely matter of point-of-view.таjustified the existence of protected modifier.
Раві

14

Це залежить від вашого визначення поняття "успадковувати". Чи підклас все ще має поля в пам'яті? Безумовно. Чи може він отримати доступ до них безпосередньо? Ні. Це лише тонкощі визначення; справа в тому, щоб зрозуміти, що насправді відбувається.


Правильно. Але я думаю, що в такому базовому питанні повинні бути спільні відповіді)
Стен Курілін

Я думаю, що це визначення спадщини Java.
OscarRyz

Або ж це залежить від вашого визначення поняття "поле". Визначити ціле поле "foo" - це орендувати шафку для зберігання розміру в цілому розмірі та поставити на ньому знак "foo". Якщо поле оголошено приватним, похідний клас успадковує незамічене шафа для зберігання даних без розміру у цілому. Від того, чи походить похідний клас успадковує "поле", залежить від того, чи називає цей незазначений шаф зберігання "полем".
supercat

10

Я продемонструю концепцію з кодом. Підкласи РОЗУМНО успадковують приватні змінні суперкласу. Єдина проблема полягає в тому, що вони не доступні дочірнім об'єктам, якщо ви не надаєте загальнодоступні геттери та сетери для приватних змінних у суперкласі.

Розглянемо два класу в пакеті Dump. Дитина продовжує батьків.

Якщо я добре пам’ятаю, дочірній об’єкт в пам’яті складається з двох областей. Один є лише батьківською частиною, а другий - лише дочірньою частиною. Дитина може отримати доступ до приватного розділу в коді свого батька лише публічним методом у батьків.

Думай про це так. У батька Бората Болток є сейф, що містить 100 000 доларів. Він не хоче ділитися своєю "приватною" змінною сейфом. Отже, він не дає ключ для сейфу. Борат успадковує сейф. Але яка користь, якщо він навіть не може відкрити його? Якби тільки тато надав ключ.

Батько -

package Dump;

public class Parent {

    private String reallyHidden;
    private String notReallyHidden;

    public String getNotReallyHidden() {
        return notReallyHidden;
    }

    public void setNotReallyHidden(String notReallyHidden) {
        this.notReallyHidden = notReallyHidden;
    }

}//Parent

Дитина -

package Dump;

public class Child extends Parent {

    private String childOnly;

    public String getChildOnly() {
        return childOnly;
    }

    public void setChildOnly(String childOnly) {
        this.childOnly = childOnly;
    }

    public static void main(String [] args){

        System.out.println("Testing...");
        Child c1 = new Child();
        c1.setChildOnly("childOnly");
        c1.setNotReallyHidden("notReallyHidden");

        //Attempting to access parent's reallyHidden
            c1.reallyHidden;//Does not even compile

    }//main

}//Child

10

Ні. Вони не успадковують це.

Те, що деякі інші класи можуть використовувати це опосередковано, говорить не про спадщину, а про інкапсуляцію.

Наприклад:

class Some { 
   private int count; 
   public void increment() { 
      count++;
   }
   public String toString() { 
       return Integer.toString( count );
   }
}

class UseIt { 
    void useIt() { 
        Some s = new Some();
        s.increment();
        s.increment();
        s.increment();
        int v = Integer.parseInt( s.toString() );
        // hey, can you say you inherit it?
     }
}

Ви також можете отримати значення countвсередині UseItза допомогою відображення. Це не означає, ти це успадковуєш.

ОНОВЛЕННЯ

Незважаючи на те, що значення є, воно не успадковується підкласом.

Наприклад, підклас, визначений як:

class SomeOther extends Some { 
    private int count = 1000;
    @Override
    public void increment() { 
        super.increment();
        count *= 10000;
    }
}

class UseIt { 
    public static void main( String ... args ) { 
        s = new SomeOther();
        s.increment();
        s.increment();
        s.increment();
        v = Integer.parseInt( s.toString() );
        // what is the value of v?           
     }
}

Це точно та сама ситуація, що і перший приклад. Атрибут countприхований і зовсім не успадковується підкласом. Однак, як вказує DigitalRoss, цінність є, але не за допомогою спадкування.

Поставте так. Якщо ваш батько заможний і дає вам кредитну карту, ви все одно можете придбати річ за його гроші, але це не означає, що ви успадкували всі ці гроші, чи не так?

Інше оновлення

Дуже цікаво знати, чому атрибут є.

Я, відверто кажучи, не маю точного терміна, щоб описати це, але саме JVM і спосіб його роботи завантажує також "не успадковане" батьківське визначення.

Ми могли фактично змінити батьківський і підклас все ще буде працювати.

Наприклад :

//A.java
class A {
   private int i;
   public String toString() { return ""+ i; }
}
// B.java
class B extends A {}
// Main.java
class Main {
   public static void main( String [] args ) {
      System.out.println( new B().toString() );
    }
}
// Compile all the files
javac A.java B.java Main.java
// Run Main
java Main
// Outout is 0 as expected as B is using the A 'toString' definition
0

// Change A.java
class A {
   public String toString() {
      return "Nothing here";
   }
}
// Recompile ONLY A.java
javac A.java
java Main
// B wasn't modified and yet it shows a different behaviour, this is not due to 
// inheritance but the way Java loads the class
Output: Nothing here

Я думаю, що точний термін можна знайти тут: Специфікація віртуальної машини JavaTM


:) Наступного разу, коли ви можете скористатися можливістю пояснити своєму інтерв'юеру, де він / вона помиляється, і це може дати вам додаткові бали;) Очевидно, ви повинні зробити це дипломатично правильно.
OscarRyz

1
Вони повинні бути успадковані для поліморфних типів, щоб взагалі мати якесь значення. Дивіться моє пояснення. Це правда, що ти не можеш з ними поспілкуватися, але вони є. Вони повинні бути.
DigitalRoss

У вашому коді немає ключових слів успадкування (розширення / реалізації), так що це не приклад успадкування.
fmucar

1
Ух, якщо вони там, як вони туди потрапили? Тому що підклас визначав їх? Ні. Тому що вони отримали, успадковані ?
DigitalRoss

1
Чудова точка щодо encapsulationvs inherit, я думаю, що ця відповідь заслуговує на більшу кількість голосів.
Ерік Ван

6

Ну, моя відповідь на запитання інтерв'юера полягає в тому, що - приватні члени не успадковуються в підкласах, але вони доступні для об'єкта підкласу або підкласу лише за допомогою методів загального доступу або сеттера або будь-яких таких відповідних методів оригінального класу. Звичайною практикою є збереження приватних членів та доступ до них за допомогою методів getter та setter, які є загальнодоступними. Тож у чому лише сенс успадковувати методи геттера та сетера, коли приватний член, з яким вони мають справу, недоступний об'єкту? Тут "успадкований" просто означає, що він доступний безпосередньо в підкласі для розігрування нововведеними методами в підкласі.

Збережіть файл нижче як ParentClass.java і спробуйте його самостійно ->

public class ParentClass {
  private int x;

  public int getX() {
    return x;
  }

  public void setX(int x) {
    this.x = x;
  }
}

class SubClass extends ParentClass {
  private int y;

  public int getY() {
    return y;
  }

  public void setY(int y) {
    this.y = y;
  }

  public void setXofParent(int x) {
    setX(x); 
  }
}

class Main {
  public static void main(String[] args) {
    SubClass s = new SubClass();
    s.setX(10);
    s.setY(12);
    System.out.println("X is :"+s.getX());
    System.out.println("Y is :"+s.getY());
    s.setXofParent(13);
    System.out.println("Now X is :"+s.getX());
  }
}

Output:
X is :10
Y is :12
Now X is :13

Якщо ми спробуємо використати приватну змінну x ParentClass у методі SubClass, то вона не є безпосередньо доступною для будь-яких модифікацій (засоби не успадковуються). Але x може бути змінено в SubClass за допомогою методу setX () оригінального класу, як це зроблено методом setXofParent () АБО його можна змінити, використовуючи об’єкт ChildClass, використовуючи метод setX () або метод setXofParent (), який в кінцевому підсумку викликає setX (). Отже, тут setX () і getX () є свого роду воротами до приватного члена x ParentClass.

Іншим простим прикладом є суперклас Clock, який має години та хвилини як приватних членів та відповідні методи getter та setter як загальнодоступні. Потім DigitalClock постає як підклас Clock. Ось, якщо об’єкт DigitalClock не містить годин та хвилин, то все накручується.


2
Відповідно до документа Oracle - Підклас не успадковує приватних членів свого батьківського класу. Однак якщо у суперкласу є загальнодоступні або захищені методи доступу до його приватних полів, вони також можуть використовуватися підкласом.
dganesh2002

4

Гаразд, це дуже цікава проблема, яку я багато досліджував і прийшов до висновку, що приватні члени надкласу дійсно доступні (але недоступні) в об'єктах підкласу. Щоб довести це, ось зразок коду з батьківським класом та дочірнім класом, і я записую об’єкт дочірнього класу у файл txt і читаю у файлі приватного члена з назвою "bhavesh", отже, підтверджуючи, що він дійсно доступний дитині клас, але недоступний через модифікатор доступу.

import java.io.Serializable;
public class ParentClass implements Serializable {
public ParentClass() {

}

public int a=32131,b,c;

private int bhavesh=5555,rr,weq,refw;
}

import java.io.*;
import java.io.Serializable;
public class ChildClass extends ParentClass{
public ChildClass() {
super();
}

public static void main(String[] args) {
ChildClass childObj = new ChildClass();
ObjectOutputStream oos;
try {
        oos = new ObjectOutputStream(new FileOutputStream("C:\\MyData1.txt"));
        oos.writeObject(childObj); //Writing child class object and not parent class object
        System.out.println("Writing complete !");
    } catch (IOException e) {
    }


}
}

Відкрийте MyData1.txt і знайдіть приватного члена на ім’я "bhavesh". Будь ласка, дайте мені знати, що ви думаєте.


3

Здавалося б, підклас наслідує приватні поля тим, що ці самі поля використовуються у внутрішній роботі підкласу (філософсько кажучи). Підклас у своєму конструкторі називає конструктор надкласового. Приватні поля суперкласу, очевидно, успадковуються підкласом, що викликає конструктор надкласового класу, якщо конструктор надкласового класу ініціалізував ці поля у своєму конструкторі. Це лише приклад. Але, звичайно, без методів доступу, підклас не може отримати доступ до приватних полів надкласового класу (це як не в змозі вискочити задню панель iPhone, щоб виймати акумулятор, щоб скинути телефон ... але акумулятор все ще є).

PS Одне з численних визначень успадкування, до яких я потрапив: "Спадкування - техніка програмування, яка дозволяє похідному класу розширити функціональність базового класу, успадкувавши всі його СТАТИ (акцент - мій) та поведінку".

Приватні поля, навіть якщо вони не доступні підкласу, є спадковим станом надкласу.


1

Я б відповісти , що приватні поля в Java є успадковується. Дозвольте мені продемонструвати:

public class Foo {

    private int x; // This is the private field.

    public Foo() {
        x = 0; // Sets int x to 0.
    }

    //The following methods are declared "final" so that they can't be overridden.
    public final void update() { x++; } // Increments x by 1.
    public final int getX() { return x; } // Returns the x value.

}


public class Bar extends Foo {

    public Bar() {

        super(); // Because this extends a class with a constructor, it is required to run before anything else.

        update(); //Runs the inherited update() method twice
        update();
        System.out.println(getX()); // Prints the inherited "x" int.

    }

}

Якщо ви запускаєте програму Bar bar = new Bar();, то ви завжди побачите число "2" у вихідному полі. Так як число «х» инкапсулируется за допомогою методів update()і getX(), то воно може бути доведено , що ціле число успадковується.

Плутанина полягає в тому, що оскільки ви не можете отримати прямий доступ до цілого числа "x", люди стверджують, що це не передається у спадок. Однак кожна нестатична річ у класі, будь то поле чи метод, успадковується.


3
"Містить" не означає "успадковує";)
Стен Курілін

1

Макет пам’яті в Java щодо успадкування

введіть тут опис зображення

Набивання бітів / Вирівнювання та включення класу об'єктів у VTABLE не враховуються. Таким чином, об’єкт підкласу має місце для приватних членів класу Super. Однак доступ до нього не можна отримати з об'єктів підкласу ...


1

Ні , приватні поля не успадковуються. Єдина причина - підклас не може отримати доступ до них безпосередньо .


0

Я вважаю, що відповідь повністю залежить від поставленого питання. Я маю на увазі, якщо питання є

Чи можемо ми безпосередньо отримати доступ до приватного поля суперкласу зі свого підкласу?

Тоді відповідь - ні , якщо ми переглянемо деталі специфікатора доступу , це згадується, приватні члени доступні лише в межах самого класу.

Але, якщо питання є

Чи можемо ми отримати доступ до приватного поля суперкласу зі свого підкласу?

Це означає, що не має значення, що ви зробите для доступу до приватного члена. У такому випадку ми можемо опублікувати публічний метод у суперкласі, і ви можете отримати доступ до приватного члена. Отже, у цьому випадку ви створюєте один інтерфейс / міст для доступу до приватного члена.

Інші мови OOP, такі як C ++, мають friend functionконцепцію, за допомогою якої ми можемо отримати доступ до приватного члена іншого класу.


0

Ми можемо просто констатувати, що коли надклас переходить у спадок, то приватні члени надкласу фактично стають приватними членами підкласу і не можуть бути в подальшому успадкованими або недоступними для об'єктів підкласу.



-1

Підклас не успадковує приватних членів свого батьківського класу. Однак якщо у суперкласу є загальнодоступні або захищені методи доступу до його приватних полів, вони також можуть використовуватися підкласом.


-2

Приватні члени (стан та поведінка) передаються у спадок. Вони (можуть) впливати на поведінку та розмір об'єкта, який інстанціюється класом. Не кажучи вже про те, що вони дуже добре помітні для підкласів через усі наявні механізми розбиття інкаптуляції, або їх можна припустити їх реалізаторами.

Хоча успадкування має визначення «дефакто», воно, безумовно, не має зв’язку з аспектами «видимості», які припускаються відповідями «ні».

Отже, не потрібно бути дипломатичним. JLS просто помиляється на даний момент.

Будь-яке припущення про те, що вони не «успадковані» є небезпечним та небезпечним.

Тож серед двох дефакто (частково) суперечливих визначень (яких я не повторюватиму) єдиним, якого слід дотримуватися, є те, що є більш безпечним (або безпечним).


1
-1. JLS визначає мову, JLS не може бути "неправильним". Крім того, якщо є механізми, які порушують інкапсуляцію, це не означає, що поле успадковується; лише те, що існують механізми, які підривають інкапсуляцію.
SL Barth - Відновити Моніку

Визначення може бути неправильним кількома способами. Далі обговорювати це не мій намір. Аргумент тут не в механізмах, які руйнують інкапсуляцію (бог чи поганий, як вони можуть бути), а в тому, що поле / метод є там, що впливає на поведінку та стан вашого підкласу. Так воно "успадковується". Можна було б використати приватний байтовий масив розміром 100 кб у класі та просто припустити, що його (джамбо) нащадки не успадковують його. Не пропустіть суть і оцініть це як добру чи погану практику (перебільшення допомагає зробити точку): це передбачені, законні дії. Приватні члени ТО "спадкували".
gkakas
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.