Questao de certificaçao OCPJP 7. Pq n compila?

15 respostas
S

E ai gente blz?
Eu n consigo entender pq esse codigo n compila.
Essa é uma questao da Enthuware, o cara explicou mas n entendi. Alguém consegue me explicar?

Consider following two classes:

//in file A.java
package p1;
public class A {
  protected int i = 10;
  public int getI() {
    return i;
  }
}
//in file B.java
package p2;
import p1.*;
public class B extends p1.A{
  public void process(A a){
    a.i = a.i*2;
  }
  public static void main(String[] args){
    A a = new B();
    B b = new B();
    b.process(a);
    System.out.println( a.getI());
  }
}

A explicaçao é a seguinte:
Although, class B extends class A and ‘i’ is a protected member of A, B still cannot access i, (now this is imp) through A’s reference because B is not involved in the implementation of A.
Had the process() method been defined as process(B b); b.i would have been accessible as B is involved in the implementation of B.
For more information read Section 6.6.2.2. Qualified Access to a protected Constructor of JLS: http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6.2.2

15 Respostas

A

Repare no final da explicação : Had the process() method been defined as process(B b); b.i would have been accessible as B is involved in the implementation of B. Ele diz que se o método processo fosse definido como process(B b) . A variável b poderia acessar a variável i já que ela contém o campo i . Como o método foi declarado como argumento A, e os campos de A só estão disponíveis via herança ou via métodos públicos não é possível acessar o campo i a partir de A. Na engenharia de software chamados isso de composição. Não há herança , já que o método process() chama apenas a classe A via composição . Esta é uma questão bem pegadinha que se a pessoa não estiver atenta cai nessa armadilha.

S

Como n ha herança? B extends A

A

Sim B extends A ,só que a classe B herda quem ? os campos de A , que é a variável i . E se B tivesse a variável A ou algum método tivesse esta variável? Aí já não é mais herança e sim composição. A classe B possui A e não herda de A , para o caso da variável a. Tente o seguinte dentro do método process() ou qualquer outro método de instância : System.out.println(i);. irá compilar ? Sim , já que a variável i é de herdada por B. Da mesma forma se fizéssemos o seguinte no método process(): B b = new B() ; System.out.println(b.i); iria compilar? sim pois a variável b do tipo B herda o campo i do tipo A

S

Meu! Q confrusao!
:frowning:

drsmachado

Skim:
Meu! Q confrusao!
:-(

Veja bem, a razão pela qual não compila é que o método process recebe um objeto de A.
Como A e B estão em packages diferentes, a única forma de acessar o atributo i, do objeto da classe A, seria através de herança ou através do eventual getter.
Note que, no método process, há uma tentativa de acesso que não é feita por herança, nem pelo getter, desta forma, o atributo i está inacessivel. Como o mesmo está inacessível, não é possível compilar.

//in file A.java  
package p1;  
public class A {  
  protected int i = 10;  
  public int getI() {  
    return i;  
  }  
}

E em outro package

//in file B.java  
package p2;  
import p1.*;  
public class B extends p1.A{  
  public void process(A a){  
    //Se fosse: this.i = this.i * 2;
    //Ou a.setI(a.getI() * 2);
   //Seriam modos aceitos
    a.i = a.i*2;  
   //a.i não retorna nada, afinal, i é protected e A está em outro package.
  }  
  public static void main(String[] args){  
    A a = new B();  
    B b = new B();  
    b.process(a);  
    System.out.println( a.getI());  
  }  
}
A

Vamos explicar de outra forma. Quando a variável é protected a única forma dessa variável ser usada em outra classe ,caso as classe estejam em pacotes diferentes, é através de herança . Certo? Então usando este exemplo de A e B . quais variáveis possui a classe A ? i apenas. e B? i tmb. A variável i da Classe B é herdada devido ao extends. Como podemos usar a variável i ?

nos construtores de B? sim

package p2;  
import p1.*;  
public class B extends p1.A{  
  
   public B (){ 
    System.out.println(i); 
} 

  public static void main(String[] args){  
    A a = new B();  
    B b = new B();  
    b.process(a);  
    System.out.println( a.getI());  
  }  
}

Há outra forma de usar o field i ? sim , pela Classe B .

package p2;  
import p1.*;  
public class B extends p1.A{  
   
   B  b ;
   public B (){ 
     b = new B(); 
    System.out.println(b.i); 
} 

  public static void main(String[] args){  
    A a = new B();  
    B b = new B();  
    b.process(a);  
    System.out.println( a.getI());  
  }  
}

Certo ?

Agora a última parte . Eu poderia usar o campo i através da classe A , declarada dentro de B? não .

Eu poderia ter por exemplo:

package p2;  
import p1.*;  
public class B extends p1.A{  
   
   A  a ;
   public B (){ 
     A = new A(); 
     
} 

  public static void main(String[] args){  
    A a = new B();  
    B b = new B();  
    b.process(a);  
    System.out.println( a.getI());  
  }  
}

TUdo certo até aqui , só que quando tento usar o i dentro do construtor ou de qq outro método de instância ocorre o erro.

package p2;  
import p1.*;  
public class B extends p1.A{  
   
   A a ;
   public B (){ 
     A = new A(); 
   System.out.println(a.i)//erro de compilação 
  
     
} 

  public static void main(String[] args){  
    A a = new B();  
    B b = new B();  
    b.process(a);  
    System.out.println( a.getI());  
  }  
}

O campo A declarado na classe B não é o herdeiro da classe A a relação é de composição , embora na classe haja a relação de herança. Mais isso é possível ? herança e composição ao mesmo tempo? sim . Então posso usar o campo i através de herança (lembre-se que é a única forma permitida para membros protected, já que o mesmo esta em outro pacote) , mas não posso usá-lo através do A ou seja da variável do tipo A. Veja como fica o final com as três possibilidades, que compilam ou não.

package p2;  
import p1.*;  
public class B extends p1.A{  
   
   A  a ;
   B b ; 
   public B (){ 
     A = new A(); 
     b = new B(); 
   System.out.println(a.i)//erro de compilação 
    System.out.println(i)//ok
  System.out.println(b.i)//ok 
  
     
} 

  public static void main(String[] args){  
    A a = new B();  
    B b = new B();  
    b.process(a);  
    System.out.println( a.getI());  
  }  
}

Se ficou complicado a explicação , esqueça herança e composição. E lembre apenas que membros protected só poderão ser usado , quando a classe estiver em outro pacote, por herança. Ou seja , usando o extends. Quem tá herdando a classe A ? A classe B então todas as variáveis do tipo B herdarão o campo i . Mas o A não é o A ? sim só que em outra classe que está em outro pacote ele só possui os atributos que estão visíveis que na realidade é somente o método public. A variável está invisível para ele mesmo.

drsmachado

Errado.
Você pode tornar qualquer atributo acessível através de métodos públicos, como getters e setters.

A

Isso perfeito , valeu pela correção.

drsmachado

V

Errado.
Você pode tornar qualquer atributo acessível através de métodos públicos, como getters e setters.

Mas ai a variável não é usada e sim os métodos. Um atributo com protected assim como método só pode ser acessado pela própria classe ou por um classe que herde a mesma

V
package p1;  
public class A {  
  protected int i = 10;  
  public int getI() {  
    return i;  
  }  
}  


view plaincopy to clipboardprint?
//in file B.java  
package p2;  
import p1.*;  
public class B extends p1.A{  
  public void process(A a){  
    a.i = a.i*2;  
  }  
  public static void main(String[] args){  
    A a = new B();  
    B b = new B();  
    b.process(a);  
    System.out.println( a.getI());  
  }  
}

Ele da erro no metodo process, por que ele ta acessando o atributo i do objeto instanciado a, porém o atributo i é protected, mas ai vem a dúvida, B não herda de A ? Sim B herda de A e ele pode acessar o atributo i diretamente, porém ele ta tentando acessar o atributo i do objeto a e esse atributo ta encapsulado.

V

Imagina você usando o atributo i do objeto a através de outras classe qualquer, você ia conseguir acessar ? Não, é a mesma coisa, essa questão foi só uma pegadinha.

A

Errado.
Você pode tornar qualquer atributo acessível através de métodos públicos, como getters e setters.

Mas ai a variável não é usada e sim os métodos. Um atributo com protected assim como método só pode ser acessado pela própria classe ou por um classe que herde a mesma
Valeu boa … É isso mesmo que queria dizer , no java básico , quando ainda não se fala em getters e setters o protected só estão disponíveis quando usados em pacotes diferentes , quando for usado por herança.
Mas não compliquemos ambas as formas de explicação tão corretas (métodos getters e setters ou por herança ) .

drsmachado

Errado.
Você pode tornar qualquer atributo acessível através de métodos públicos, como getters e setters.

Mas ai a variável não é usada e sim os métodos. Um atributo com protected assim como método só pode ser acessado pela própria classe ou por um classe que herde a mesma
Então quer dizer que:

public class A{
    private String nome;
    public String getNome(){
        return this.nome;
    }
    public void setNome(String nome){
        this.nome = nome;
    }
}
//
public class B{
    private A a;
    public B(String nome){
        a = new A();
        a.setNome(nome);
    }
}

Não utiliza a variável nome? Muito bom saber…

V

Errado.
Você pode tornar qualquer atributo acessível através de métodos públicos, como getters e setters.

Mas ai a variável não é usada e sim os métodos. Um atributo com protected assim como método só pode ser acessado pela própria classe ou por um classe que herde a mesma
Então quer dizer que:

public class A{
    private String nome;
    public String getNome(){
        return this.nome;
    }
    public void setNome(String nome){
        this.nome = nome;
    }
}
//
public class B{
    private A a;
    public B(String nome){
        a = new A();
        a.setNome(nome);
    }
}

Não utiliza a variável nome? Muito bom saber…

Não, você acessa através do get/set e não diretamente, é simples, isso é o conceito básico da OO. Até por não se chama variável e sim atributo.

drsmachado

Errado.
Você pode tornar qualquer atributo acessível através de métodos públicos, como getters e setters.

Mas ai a variável não é usada e sim os métodos. Um atributo com protected assim como método só pode ser acessado pela própria classe ou por um classe que herde a mesma
Então quer dizer que:

public class A{
    private String nome;
    public String getNome(){
        return this.nome;
    }
    public void setNome(String nome){
        this.nome = nome;
    }
}
//
public class B{
    private A a;
    public B(String nome){
        a = new A();
        a.setNome(nome);
    }
}

Não utiliza a variável nome? Muito bom saber…

Não, você acessa através do get/set e não diretamente, é simples, isso é o conceito básico da OO. Até por não se chama variável e sim atributo.


O nome do conceito é encapsulamento e, independente de ser atributo, propriedade, variável ou o diabo a quatro, você, de alguma forma, está manipulando (definindo ou obtendo) o valor de uma propriedade que está com um modificador de acesso restritivo (private, protected ou default) e que, por isso, não é visível e/ou acessível em um elemento que esteja em outro package e, dependendo, mesmo que este elemento possua uma relação do tipo é um com a classe de onde se deseja obter a propriedade.

Seguindo tua linha de raciocínio, podemos nos livrar de todas as propriedades de um objeto, já que os métodos get e set farão todo o trabalho, não?

Criado 25 de novembro de 2013
Ultima resposta 25 de nov. de 2013
Respostas 15
Participantes 4