As subclasses herdam campos particulares?

245

Esta é uma pergunta de entrevista.

As subclasses herdam campos particulares?

Respondi "Não", porque não podemos acessá-los usando o "modo normal de POO". Mas o entrevistador pensa que eles são herdados, porque podemos acessar esses campos indiretamente ou usando a reflexão e eles ainda existem no objeto.

Depois que voltei, encontrei a seguinte citação no javadoc :

Membros privados em uma superclasse

Uma subclasse não herda os membros privados de sua classe pai.

Você conhece algum argumento para a opinião do entrevistador?

Stan Kurilin
fonte
33
Eu já estava em uma situação semelhante e percebi que nem queria trabalhar para uma empresa em que o entrevistador sabia menos sobre Java do que eu. :)
biziclop
48
Às vezes, um entrevistador discorda de você, mesmo quando sabe que você está certo. Um bom entrevistador tentará aprender mais sobre você do que seu conhecimento técnico.
Andy Thomas
4
@DigitalRoss A especificação da linguagem Java também está mal escrita? Veja a resposta RD01: stackoverflow.com/questions/4716040/…
OscarRyz
9
@ Andy Thomas-Cramer Eu também não gostaria de trabalhar com pessoas que estão mentindo deliberadamente para testar minha reação.
biziclop
4
Bem, acho que devemos primeiro descobrir o significado de "herança" em Java. A subclasse não possui o campo privado e a subclasse possui o campo privado, mas não pode acessá-lo são diferentes. Qual deles se refere ao significado exato da herança em Java?
MengT

Respostas:

238

A maior parte da confusão nas perguntas / respostas aqui envolve a definição de herança.

Obviamente, como o @DigitalRoss explica, um OBJETO de uma subclasse deve conter os campos privados de sua superclasse. Como ele afirma, não ter acesso a um membro privado não significa que não existe.

Contudo. Isso é diferente da noção de herança para uma classe. Como é o caso no mundo java, onde há uma questão de semântica, o árbitro é a Java Language Specification (atualmente na 3ª edição).

Como o JLS declara ( https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.2 ):

Os membros de uma classe declarada privada não são herdados pelas subclasses dessa classe. Somente membros de uma classe declarada protegida ou pública são herdados por subclasses declaradas em um pacote diferente daquele em que a classe é declarada.

Isso aborda a pergunta exata feita pelo entrevistador: "as sub CLASSES herdam campos privados". (ênfase adicionada por mim)

A resposta é não. Eles não. OBJETOS de subclasses contêm campos particulares de suas superclasses. A subclasse em si não tem NOTION de campos particulares de sua superclasse.

É semântica de natureza pedante? Sim. É uma pergunta de entrevista útil? Provavelmente não. Mas o JLS estabelece a definição para o mundo Java e o faz (neste caso) sem ambiguidade.

EDITADO (removida uma citação paralela de Bjarne Stroustrup que, devido às diferenças entre java e c ++, provavelmente apenas aumenta a confusão. Vou deixar minha resposta no JLS :)

robert_x44
fonte
3
@ digital porque o suspiro. Eu entendo que você acredita que está certo. Não discordo de você que a herança de objetos é o que a maioria dos programadores é ensinada / pensa. Mas a definição JLS se aplica diretamente à pergunta original. É semântica sim, mas o JLS determina a definição, não você ou eu.
robert_x44
4
Uma maneira de reconciliar tudo isso é simplesmente reconhecer que a palavra "herdar" é usada de duas maneiras muito diferentes para descrever o relacionamento das classes derivada e pai, pelo menos no mundo Java. Sim, a JSL é autorizada. Sim, significa que você pode usar "herdar" dessa maneira infeliz. Mas ainda é manifestamente verdade que as subclasses froggle (porque agora não temos uma palavra) os campos particulares de sua classe pai.
DigitalRoss
1
@ digital Eles estão no objeto da classe. não a classe em si. Simula os chamou de objetos concatenados. Quando um objeto de uma subclasse foi criado, ele era composto de 'objetos de prefixo' concatenados. O objeto de superclasse era um objeto de prefixo que poderia conter outros objetos de prefixo. Eu acho que é arrogância dizer que o JLS tem "uma redação claramente ruim". Quanto à palavra que usamos, herança, é claro. Não há nada de errado em usar uma terminologia ligeiramente ambígua. Isso acontece o tempo todo. Mas isso não significa que não há uma definição precisa.
robert_x44
1
Certamente podemos concordar que a palavra é usada de maneiras diferentes. :) Também podemos concordar que uma pergunta de entrevista que depende de um termo ambíguo provavelmente não é boa.
robert_x44
2
Alguém tem uma referência do Java / Oracle para "Objetos da subclasse contêm os campos privados de suas superclasses"? Eu concordo com isso, mas não consigo encontrar nenhum documento oficial dizendo isso.
MengT
78

sim

É importante perceber que, enquanto não são duas classes, há apenas um objeto.

Então, sim, é claro que herdou os campos particulares. Eles são, presumivelmente, essenciais para a funcionalidade apropriada do objeto e, embora um objeto da classe pai não seja um objeto da classe derivada, uma instância da classe derivada é definitivamente uma instância da classe pai. Não poderia muito bem ser isso sem todos os campos.

Não, você não pode acessá-los diretamente. Sim, eles são herdados. Eles têm que ser.

É uma boa pergunta!


Atualizar:

Err, "Não"

Bem, acho que todos aprendemos alguma coisa. Como o JLS originou a expressão exata "não herdada", é correto responder "não" . Como a subclasse não pode acessar ou modificar os campos particulares, em outras palavras, eles não são herdados. Mas, na verdade, existe apenas um objeto, ele realmente contém os campos privados; portanto, se alguém usar o JLS e o tutorial de maneira errada, será muito difícil entender OOP, objetos Java e o que realmente está acontecendo.

Atualize para atualizar:

A controvérsia aqui envolve uma ambiguidade fundamental: o que exatamente está sendo discutido? O objeto? Ou estamos falando de algum modo sobre a própria classe? Muita latitude é permitida ao descrever a classe em oposição ao objeto. Portanto, a subclasse não herda campos privados, mas um objeto que é uma instância da subclasse certamente contém os campos privados.

DigitalRoss
fonte
2
@ Ma99uS. Claro que eles são reutilizados. Esse é o ponto inteiro da herança. Sem eles, o tipo derivado não seria e não poderia ser uma instância do tipo pai. OOP seria sem sentido. Tipos polimórficos parariam de funcionar . Entender que existe apenas um objeto e você é uma instância do tipo pai é crucial para entender o POO. Você deve superar esse problema para entendê-lo.
DigitalRoss 17/01
2
Não tenho certeza se o exemplo pai é muito bom porque um campo pode ser herdado enquanto a classe pai ainda vive e também possui esse campo. Se a herança funcionasse dessa maneira, eu poderia herdar o dinheiro do meu pai enquanto ele estivesse vivo e ele também poderia manter o mesmo dinheiro. Meus filhos teriam o dinheiro dele e o meu.
precisa saber é o seguinte
2
@ Peter Lawrey não discutindo nem nada, mas aqui está o que eu acho. O pai tinha um car, ele o guardava em um privatearmário que a criança não tem a chave. Você de fato herda o carmas é inútil para você. Então, praticamente, você não está se beneficiando da herança.
Nishant
1
@DigitalRoss. Eu entendi o seu ponto. Mhh, poderíamos dizer que o valor existe, porque a definição de pai não herdada também é carregada. :) Acho que a especificação da JVM teria a resposta correta para este "NO WORD" que estamos procurando. java.sun.com/docs/books/jvms
OscarRyz
5
-1, a Java Language Specification indica claramente que não são herdadas. Sem ifs, buts. Eles simplesmente não são. Qualquer outra definição de herança está errada no contexto de Java.
biziclop
21

Não. Os campos particulares não são herdados ... e é por isso que Protected foi inventado. É por design. Eu acho que isso justificou a existência de modificador protegido.


Agora chegando aos contextos. O que você quer dizer com herdado - se ele existe no objeto criado a partir da classe derivada? Sim, ele é.

Se você quer dizer, pode ser útil para a classe derivada. Bem não.

Agora, quando você chega à programação funcional, o campo privado da superclasse não é herdado de maneira significativa para a subclasse . Para a subclasse, um campo privado de superclasse é igual a um campo privado de qualquer outra classe.

Funcionalmente, não é herdado. Mas , idealmente , é.


OK, apenas olhei para o tutorial Java, eles citam isso:

Membros privados em uma superclasse

Uma subclasse não herda os membros privados de sua classe pai. No entanto, se a superclasse tiver métodos públicos ou protegidos para acessar seus campos particulares, eles também poderão ser usados ​​pela subclasse.

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

Eu concordo que o campo está lá. Porém, a subclasse não recebe nenhum privilégio nesse campo privado. Para uma subclasse, o campo privado é o mesmo que qualquer campo particular de qualquer outra classe.

Eu acredito que é puramente questão de ponto de vista. Você pode moldar o argumento de ambos os lados. É melhor justificar para os dois lados.

 

Nishant
fonte
2
Isso não está correto. Você não pode acessá-los, isso está correto. Mas eles precisam ser herdados, como expliquei.
precisa saber é o seguinte
1
excelente resposta !!! +1 para I believe it's purely matter of point-of-view.ejustified the existence of protected modifier.
Ravi
14

Depende da sua definição de "herdar". A subclasse ainda possui os campos na memória? Definitivamente. Pode acessá-los diretamente? Não. São apenas sutilezas da definição; o objetivo é entender o que realmente está acontecendo.

user541686
fonte
Corrigir. Mas acho que essa questão de base deve haver respostas comuns)
Stan Kurilin
Eu acho que é a definição Java de herança.
OscarRyz
Ou então depende da sua definição de "campo". Definir um campo inteiro "foo" é alugar um armário de armazenamento de tamanho inteiro e colocar um sinal de "foo" nele. Se o campo for declarado privado, a classe derivada herdará um armário de armazenamento de tamanho inteiro não rotulado. Se a classe derivada herda ou não o "campo" depende se alguém chama esse armário de armazenamento sem rótulo de "campo".
7238 supercat
10

Vou demonstrar o conceito com código. Subclasses REALMENTE herdam as variáveis ​​privadas da super classe. O único problema é que eles não são acessíveis aos objetos filhos, a menos que você forneça getters e setters públicos para as variáveis ​​privadas na superclasse.

Considere duas classes no pacote Dump. Filho estende Pai.

Se bem me lembro, um objeto filho na memória consiste em duas regiões. Um é apenas a parte pai e o outro é apenas a parte filho. Um filho pode acessar a seção privada no código de seu pai apenas através de um método público no pai.

Pense desta maneira. O pai de Borat, Boltok, tem um cofre contendo US $ 100.000. Ele não quer compartilhar seu cofre "variável" privado. Então, ele não fornece uma chave para o cofre. Borat herda o cofre. Mas, de que adianta ele nem conseguir abri-lo? Se ao menos o pai dele tivesse fornecido a chave.

Pai -

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

Criança -

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
Erran Morad
fonte
10

Não. Eles não herdam.

O fato de alguma outra classe usá-lo indiretamente não diz nada sobre herança, mas sobre encapsulamento.

Por exemplo:

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?
     }
}

Você também pode obter o valor de countdentro UseItvia reflexão. Isso não significa que você herda.

ATUALIZAR

Mesmo que o valor esteja lá, ele não é herdado pela subclasse.

Por exemplo, uma subclasse definida como:

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?           
     }
}

Essa é exatamente a mesma situação do primeiro exemplo. O atributo countestá oculto e não é herdado pela subclasse. Ainda assim, como DigitalRoss aponta, o valor está lá, mas não por meio de herança.

Põe desta forma. Se seu pai é rico e lhe dá um cartão de crédito, você ainda pode comprar coisas com o dinheiro dele, mas não significa que você herdou todo esse dinheiro, não é?

Outra atualização

É muito interessante saber por que o atributo está lá.

Francamente, não tenho o termo exato para descrevê-lo, mas é a JVM e a maneira como funciona que carrega também a definição de pai "não herdada".

Poderíamos realmente mudar o pai e a subclasse ainda funcionará.

Por exemplo :

//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

Acho que o termo exato pode ser encontrado aqui: The JavaTM Virtual Machine Specification

OscarRyz
fonte
:) Na próxima vez, você poderá explicar ao entrevistador onde ele está errado, e isso pode lhe dar pontos extras;) Obviamente, você deve fazer isso da maneira correta diplomática.
precisa saber é o seguinte
1
Eles precisam ser herdados para que os tipos polimórficos tenham algum significado. Veja minha explicação. É verdade que você não pode mexer com eles, mas eles estão lá. Eles têm que ser.
precisa saber é o seguinte
Não há palavras-chave de herança (estende / implementa) em seu código; portanto, esse não é um exemplo de herança.
Fmucar
1
Uhh, se eles estão lá, como eles chegaram lá? Porque a subclasse os definiu? Não. Porque eles foram herdados ?
precisa saber é o seguinte
1
Ótimo ponto sobre encapsulationvs inherit, acho que essa resposta merece mais votos positivos.
Eric Wang
6

Bem, minha resposta para a pergunta do entrevistador é: os membros privados não são herdados das subclasses, mas são acessíveis à subclasse ou ao objeto da subclasse apenas por meio de métodos públicos getter ou setter ou por qualquer método apropriado da classe original. A prática normal é manter os membros privados e acessá-los usando métodos getter e setter que são públicos. Então, qual é o sentido de herdar apenas métodos getter e setter quando o membro privado com o qual lidam não está disponível para o objeto? Aqui 'herdado' significa simplesmente que ele está disponível diretamente na subclasse para brincar com os métodos recém-introduzidos na subclasse.

Salve o arquivo abaixo como ParentClass.java e tente você mesmo ->

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

Se tentarmos usar a variável privada x de ParentClass no método SubClass, ele não estará diretamente acessível para quaisquer modificações (significa não herdado). Mas x pode ser modificado na SubClasse via método setX () da classe original, como foi feito no método setXofParent () OU pode ser modificado usando o objeto ChildClass usando o método setX () ou o método setXofParent () que chama finalmente setX (). Então aqui setX () e getX () são uma espécie de porta para o membro privado x de uma ParentClass.

Outro exemplo simples é a superclasse Clock que possui horas e minutos como membros particulares e métodos getter e setter apropriados como públicos. Então vem o DigitalClock como uma subclasse de Clock. Aqui, se o objeto do DigitalClock não contiver membros horas e minutos, as coisas estão erradas.

dganesh2002
fonte
2
Conforme o documento Oracle - Uma subclasse não herda os membros privados de sua classe pai. No entanto, se a superclasse tiver métodos públicos ou protegidos para acessar seus campos particulares, eles também poderão ser usados ​​pela subclasse.
precisa saber é o seguinte
4

Ok, este é um problema muito interessante. Pesquisei bastante e cheguei à conclusão de que membros privados de uma superclasse estão realmente disponíveis (mas não acessíveis) nos objetos da subclasse. Para provar isso, aqui está um código de exemplo com uma classe pai e uma classe filho. Estou escrevendo um objeto de classe filho em um arquivo txt e lendo um membro privado chamado 'bhavesh' no arquivo, provando que ele está realmente disponível no filho classe, mas não acessível devido ao modificador de acesso.

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) {
    }


}
}

Abra MyData1.txt e procure o membro particular chamado 'bhavesh'. Por favor me digam o que vocês acham.

Bhavesh Agarwal
fonte
3

Parece que uma subclasse herda os campos privados, pois esses mesmos campos são utilizados no funcionamento interno da subclasse (filosoficamente falando). Uma subclasse, em seu construtor, chama o construtor da superclasse. Os campos privados da superclasse são obviamente herdados pela subclasse que chama o construtor da superclasse se o construtor da superclasse inicializou esses campos em seu construtor. Isso é apenas um exemplo. Mas é claro que sem os métodos de acesso, a subclasse não pode acessar os campos particulares da superclasse (é como não ser capaz de abrir o painel traseiro de um iPhone para tirar a bateria e reiniciar o telefone ... mas a bateria ainda está lá).

PS Uma das muitas definições de herança que encontrei: "Herança - uma técnica de programação que permite que uma classe derivada estenda a funcionalidade de uma classe base, herdando todo o seu ESTADO (ênfase é minha) e comportamento".

Os campos particulares, mesmo que não sejam acessíveis pela subclasse, são o estado herdado da superclasse.

Flanker
fonte
1

Eu teria que responder que os campos privados em Java são herdados. Permita-me demonstrar:

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.

    }

}

Se você executar um programa Bar bar = new Bar();, sempre verá o número "2" na caixa de saída. Como o número inteiro "x" é encapsulado com os métodos update()e getX(), é possível provar que o número inteiro é herdado.

A confusão é que, como você não pode acessar diretamente o número inteiro "x", as pessoas argumentam que ele não é herdado. No entanto, todas as coisas não estáticas em uma classe, seja campo ou método, são herdadas.

Legal preguiçoso
fonte
3
"Contém" não significa "herda";)
Stan Kurilin
1

Layout de memória em Java em relação à herança

insira a descrição da imagem aqui

Os bits de preenchimento / alinhamento e a inclusão da classe de objeto no VTABLE não são considerados. Portanto, o objeto da subclasse tem um lugar para os membros privados da classe Super. No entanto, ele não pode ser acessado a partir dos objetos da subclasse ...

somenath mukhopadhyay
fonte
1

Não , campos privados não são herdados. A única razão é que a subclasse não pode acessá-los diretamente .

joooohnli
fonte
0

Creio que a resposta depende totalmente da pergunta que foi feita. Quero dizer, se a pergunta for

Podemos acessar diretamente o campo privado da superclasse a partir da subclasse?

Então a resposta é Não . Se formos examinados os detalhes do especificador de acesso , é mencionado que membros privados são acessíveis apenas dentro da própria classe.

Mas, se a pergunta for

Podemos acessar o campo privado da superclasse a partir da subclasse?

O que significa, não importa, o que você fará para acessar o membro privado. Nesse caso, podemos tornar o método público na superclasse e você pode acessar o membro privado. Portanto, neste caso, você está criando uma interface / ponte para acessar o membro privado.

Outras linguagens de POO, como C ++, têm o friend functionconceito pelo qual podemos acessar o membro privado de outra classe.

Ravi
fonte
0

Podemos simplesmente afirmar que, quando uma superclasse é herdada, os membros privados da superclasse tornam-se membros privados da subclasse e não podem mais ser herdados ou são inacessíveis aos objetos da subclasse.

Aamir wani
fonte
-1

Uma subclasse não herda os membros privados de sua classe pai. No entanto, se a superclasse tiver métodos públicos ou protegidos para acessar seus campos particulares, eles também poderão ser usados ​​pela subclasse.

suprinder
fonte
-2

Membros privados (estado e comportamento) são herdados. Eles podem afetar o comportamento e o tamanho do objeto instanciado pela classe. Sem mencionar que eles são muito bem visíveis para as subclasses através de todos os mecanismos de quebra de encapulação disponíveis ou podem ser assumidos por seus implementadores.

Embora a herança tenha uma definição "defacto", ela definitivamente não tem vínculo com os aspectos de "visibilidade", que são assumidos pelas respostas "não".

Portanto, não há necessidade de ser diplomático. JLS está errado neste momento.

Qualquer suposição de que eles não sejam "herdados" é insegura e perigosa.

Assim, entre duas definições defacto (parcialmente) conflitantes (que não repetirei), a única que deve ser seguida é a mais segura (ou segura).

gkakas
fonte
1
-1. O JLS define a linguagem, é impossível que o JLS esteja "errado". Além disso, se houver mecanismos que quebrem o encapsulamento, isso não significa que o campo seja herdado; apenas que existem mecanismos que subvertem o encapsulamento.
SL Barth - Restabelece Monica
Uma definição pode, por si só, estar errada de várias maneiras. Discutir mais sobre isso não é minha intenção. O argumento aqui não é sobre os mecanismos que quebram o encapsulamento (por mais ruins ou ruins que sejam), mas o fato de o campo / método estar lá, afetando o comportamento e o estado da sua subclasse. Então é "herdado". Pode-se usar uma matriz de bytes privados de 100kb em uma classe e apenas supor que seus descendentes (jumbo) não a herdam. Não perca o argumento e julgue isso como uma boa ou má prática (o exagero ajuda a explicar): é uma ação prevista e legítima. Membros privados SÃO "herdados".
gkakas