Подклассы наследуют частные поля?

246

Это вопрос интервью.

Подклассы наследуют частные поля?

Я ответил «Нет», потому что мы не можем получить к ним доступ «обычным способом ООП». Но интервьюер считает, что они наследуются, потому что мы можем получить доступ к таким полям косвенно или с помощью отражения, и они все еще существуют в объекте.

После того, как я вернулся, я нашел следующую цитату в Javadoc :

Частные Члены в Суперклассе

Подкласс не наследует частные члены своего родительского класса.

Знаете ли вы какие-либо аргументы для мнения интервьюера?

Стан Курилин
источник
33
Однажды я оказался в подобной ситуации и понял, что даже не хочу работать в компании, где интервьюер знает о Java меньше, чем я. :)
biziclop
48
Интервьюер иногда не соглашается с вами, даже если знает, что вы правы. Хороший интервьюер постарается узнать о вас больше, чем ваши технические знания.
Энди Томас
4
@DigitalRoss Спецификация языка Java также плохо написана? См. Ответ RD01: stackoverflow.com/questions/4716040/…
OscarRyz
9
@ Энди Томас-Крамер Я бы не хотел работать с людьми, которые намеренно лгут, чтобы проверить мою реакцию.
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, и это делает это (в данном случае) однозначно.

EDITED (удалена параллельная цитата из Bjarne Stroustrup, которая из-за различий между java и c ++, вероятно, только усугубляет путаницу. Я оставлю свой ответ на JLS :)

robert_x44
источник
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 и учебное пособие, будет довольно сложно понять ООП, объекты Java и то, что на самом деле происходит.

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

Спор здесь включает фундаментальную двусмысленность: что именно обсуждается? Объект? Или мы в каком-то смысле говорим о самом классе? При описании класса в отличие от объекта допускается много возможностей. Таким образом, подкласс не наследует приватные поля, но объект, который является экземпляром подкласса, безусловно, содержит приватные поля.

DigitalRoss
источник
2
@ Ma99uS. Конечно они используются повторно. Вот и весь смысл наследования. Без них производный тип не был бы и не мог быть экземпляром родительского типа. ООП будет бессмысленным. Полиморфные типы перестали бы работать . Понимание того, что существует только один объект и вы являетесь экземпляром родительского типа, имеет решающее значение для понимания ООП. Вы должны пройти эту проблему, чтобы понять это вообще.
DigitalRoss
2
Не уверен, что пример отца очень хорош, потому что поле может быть унаследовано, пока родительский класс все еще живет и также имеет это поле. Если бы наследство работало так, я мог бы наследовать деньги моего отца, пока он жив, и он мог бы хранить те же деньги. У каждого из моих детей были свои деньги и мои деньги.
Питер Лоури
2
@ Питер Лори не спорит или что-то еще, но вот что я думаю. Родитель имел car, он держал его в privateшкафчике, от которого ребенок не пользуется ключом. Вы действительно наследуете, carно это бесполезно для вас. Таким образом, практически, вы не получаете выгоды от наследования.
Nishant
1
@DigitalRoss. Я понимаю вашу точку зрения. Ммм, мы могли бы сказать, что значение здесь, потому что также не загружено родительское определение. :) Я думаю, что у спецификации JVM будет правильный ответ для этого "НЕТ СЛОВА", которое мы ищем. java.sun.com/docs/books/jvms
OscarRyz
5
-1, в спецификации языка Java четко прописано, что они не наследуются. Нет если, нет но. Их просто нет. Любое другое определение наследования неверно в контексте Java.
biziclop
21

Нет. Частные поля не наследуются ... и поэтому было создано изобретение Protected . Это по замыслу. Полагаю, это оправдывало существование защищенного модификатора.


Теперь подходит к контексту. Что вы подразумеваете под унаследованным - если он есть в объекте, созданном из производного класса? Да, это так.

Если вы имеете в виду, может ли это быть полезным для производного класса. Ну нет.

Теперь, когда вы переходите к функциональному программированию, приватное поле суперкласса не наследуется значимым образом для подкласса. . Для подкласса приватное поле суперкласса такое же, как приватное поле любого другого класса.

Функционально это не наследуется. Но в идеале это так.


Хорошо, только что посмотрел учебник Java, они цитируют это:

Частные Члены в Суперклассе

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

см: http://download.oracle.com/javase/tutorial/java/IandI/subclasses.html.

Я согласен, что поле есть. Но подкласс не получает никаких привилегий для этого частного поля. Для подкласса личное поле такое же, как и любое личное поле любого другого класса.

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

 

Nishant
источник
2
Это не правильно. Вы не можете получить к ним доступ, это правильно. Но они должны быть унаследованы, как я объяснил.
DigitalRoss
1
отличный ответ !!! +1 за I believe it's purely matter of point-of-view.иjustified the existence of protected modifier.
Рави
14

Это зависит от вашего определения «наследовать». У подкласса все еще есть поля в памяти? Определенно. Может ли он получить к ним доступ напрямую? Нет. Это просто тонкости определения; дело в том, чтобы понять, что на самом деле происходит.

user541686
источник
Верный. Но я думаю, что на такой базовый вопрос должны быть общие ответы)
Стэн Курилин
Я думаю, что это Java-определение наследования.
ОскарРиз
Или же это зависит от вашего определения «поля». Чтобы определить целочисленное поле «foo», нужно арендовать хранилище целого размера и поставить на нем знак «foo». Если поле объявлено как личное, производный класс наследует немаркированный целочисленный хранилище. То, наследует ли производный класс «поле», зависит от того, называет ли тот немаркированный шкафчик хранения «полем».
Суперкат
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
Отличное замечание encapsulationпротив 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 имеет часы и минуты как частные члены и соответствующие методы получения и установки как публичные. Затем идет DigitalClock как подкласс часов. Здесь, если объект DigitalClock не содержит часов и минут, тогда все испорчено.

dganesh2002
источник
2
Согласно документу Oracle - подкласс не наследует частные члены своего родительского класса. Однако, если суперкласс имеет открытые или защищенные методы для доступа к своим закрытым полям, они также могут использоваться подклассом.
dganesh2002
4

Хорошо, это очень интересная проблема. Я много исследовал и пришел к выводу, что частные объекты суперкласса действительно доступны (но не доступны) в объектах подкласса. Чтобы доказать это, вот пример кода с родительским классом и дочерним классом, и я записываю объект дочернего класса в текстовый файл и читаю закрытый член с именем «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 Одно из многих определений наследования, с которыми мне приходилось сталкиваться: «Наследование - метод программирования, который позволяет производному классу расширять функциональные возможности базового класса, наследуя все его состояние STATE (выделено мной) и поведение».

Закрытые поля, даже если они недоступны для подкласса, являются унаследованным состоянием суперкласса.

мошенничество
источник
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» в поле вывода. Поскольку целое число «x» инкапсулировано с методами update()и getX(), то можно доказать, что целое число наследуется.

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

Законный ленивый
источник
3
«Содержит» не означает «наследует»;)
Стэн Курилин
1

Расположение памяти в Java по отношению к наследованию

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

Заполнение битов / выравнивание и включение класса объекта в VTABLE не рассматривается. Таким образом, объект подкласса имеет место для частных членов класса Super. Однако к нему нельзя получить доступ из объектов подкласса ...

Соменат Мухопадхяй
источник
1

Нет , приватные поля не наследуются. Единственная причина в том, что подкласс не может получить к ним доступ напрямую .

joooohnli
источник
0

Я считаю, что ответ полностью зависит от вопроса, который был задан. Я имею в виду, если вопрос

Можем ли мы напрямую получить доступ к закрытому полю суперкласса из их подкласса?

Тогда ответ « Нет» , если мы рассмотрим детали спецификатора доступа , упомянуто, частные члены доступны только внутри самого класса.

Но если вопрос

Можем ли мы получить доступ к закрытому полю суперкласса из их подкласса?

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

Другие языки ООП, такие как C ++, имеют friend function концепцию, с помощью которой мы можем получить доступ к закрытому члену другого класса.

Ravi
источник
0

Мы можем просто заявить, что когда наследуется суперкласс, тогда частные члены суперкласса фактически становятся частными членами подкласса и не могут быть унаследованы в дальнейшем или недоступны объектам подкласса.

Амир Вани
источник
-1

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

suprinder
источник
-2

Частные члены (состояние и поведение) наследуются. Они (могут) влиять на поведение и размер объекта, который создается классом. Не говоря уже о том, что они очень хорошо видны для подклассов через все механизмы разрушения инкапсуляции, которые доступны или могут быть приняты их исполнителями.

Хотя наследование имеет определение «де-факто», оно определенно не имеет связи с аспектами «видимости», которые предполагаются ответами «нет».

Таким образом, нет необходимости быть дипломатичным. JLS просто не прав в этой точке.

Любое предположение, что они не «унаследованы», небезопасно и опасно.

Таким образом, среди двух де-факто (частично) противоречивых определений (которые я не буду повторять), единственное, которое следует соблюдать, - это более безопасное (или безопасное).

gkakas
источник
1
-1. JLS определяет язык, JLS не может быть «неправильным». Кроме того, если существуют механизмы, которые нарушают инкапсуляцию, это не означает, что поле наследуется; просто есть механизмы, которые разрушают инкапсуляцию.
SL Barth - Восстановить Монику
Определение может быть ошибочным по нескольким причинам. Обсуждать дальше это не мое намерение. Аргумент здесь не о механизмах, которые нарушают инкапсуляцию (бог или плохо, как они могут быть), а о факте наличия поля / метода, влияющих на поведение и состояние вашего подкласса. Так что это "унаследовано". Можно использовать приватный байтовый массив размером 100 КБ в классе и просто предположить, что его потомки (jumbo) не наследуют его. Не упустите момент и оцените это как хорошую или плохую практику (преувеличение помогает подчеркнуть): это предвиденное, законное действие. Частные члены "унаследованы".
gkakas