Estou a ler a 3ª edição do livro "Thinking in Java" mas agora fiquei preso num dos exercicios que é dado para fazer.. resolvi por aqui para ver se alguem me pode dizer se isto é mesmo possivel ou se foi um erro do autor, é q eu não estou mesmo a ver como o fazer
Este é o exercicio:
Create an interface with at least one method, in its own package. Create a class in a separate package. Add a protected inner class that implements the interface. In a third package, inherit from your class and, inside a method, return an object of the protected inner class, upcasting to the interface during the return.
O erro está em return (A)b.new C();, não me deixa criar um objecto porque a classe interna C não está visivel por ser protected.. sei que se mudar para public funciona mas n é essa a ideia, alguem me pode ajudar e esclarecer ?
O modificador “protected” eh a coisa mais bizarra que existe no Java. Tem cada coisa sinistra no funcionamento dele que chega a assustar…
Se voce declarar o construtor como public ( nao a classe, mas apenas o construtor ), entao vc pode ter acesso sem problemas. O mais estranho nesse caso eh que voce pode ter entao acesso mesmo sem extender a classe que contem a inner class, o que violaria as regras.
Sinistro, e a Java Language Specification eh meio confusa em relacao a isso…
mais info ( ou correcoes ) no decorrer do periodo.
Rafael
Paulo_Silveira
ateh faz sentido nao funcionar. porque o protected, fora do meesmo pacote, voce nao pode acessar esse membro/classe interna de outra instancia, voce herda, mas nao acessa.
O Rafael compilou mas disse que ainda reclama do protected la de cima. Parece que o construtor default dela ta protected tambem, internamente a classe. Nao faz muito sentido.
O que ele coloca na resposta?
Rafael_Steil
Voce consgue acessar um membro protected via heranca, o que nao consegue eh acessar via instancia:
resumindo: deverimos poder acessar a inner classe tambem.
Rafael
Bruno_Cardoso
Paulo, experimentei como disse e também não dá, continua a dizer que o constructor não é visivel.. já tentei de todas as maneiras.. o mais estranho é que o autor coloca no livro o seguinte exemplo:
PDestination is protected, so no one but Parcel3, classes in the same package (since protected also gives package access), and the inheritors of Parcel3 can access PDestination. This means that the client programmer has restricted knowledge and access to these members.
Então se Teste é uma classe derivada de B, segundo o que o autor diz, eu deveria ter acesso às classes internas de Bmesmo tendo elas acesso protected, certo?
Obrigado aos dois pela ajuda,
PEACE!
dukejeffrie
Será que ele não quis dizer isso?
returnnewB.C();
[]s!
Rafael_Steil
Isso nao funciona tambem, pelos mesmos motivos anteriores… :-
Rafael
Bani
O enunciado da questão é “return an object of the protected inner class”. Não está especificado que tenha que ser um “novo” objeto da inner class…
Então, considerando que você consegue acessar através de herança, minha sugestão seria retornar um objeto tipo um singleton.
Rafael_Steil
Bom, com base nisso nem precisa ser singleton… poderia ter um metodo public da classe pai q retornasse o objeto:
// B.java
...
public A newCInstance()
{
new return C();
}
]
e entao usar o newCInstance() pra pegar o objeto.
Mas mesmo assim: por que diabos eh possivel acessar um membro protected e nao eh possivel acessar a inner class protected??
Rafael
Bruno_Cardoso
Como o Rafael diz funciona mas eu acho que a ideia seria fazer um objecto da inner class C sem ter que acrescentar mais código… e daí posso estar enganado… não sei o que ia na cabeça do autor quando escreveu este exercicio, e quanto às soluções do mesmo só comprando o livro
Kewl! Ainda hoje li sobre esta tecnica aqui no manual, mas só agora é que fiquei a saber que é um pattern conhecido como singleton!
Bem, mais uma vez obrigado pessoal.
PEACE!
Bani
Rafael,
Como você mesmo disse na sua primeira mensagem, é possível acessar a inner class sim! Apenas o construtor da inner class que não dá para acessar.
Declarando o construtor público, é possível instanciar a inner class.
Porém aí você disse que com o construtor público teria acesso mesmo sem estender a outer class, mas isso já não é verdade. Se você não estende a outer class, seus membros ficam “private” para a classe que está chamando, e portanto você nem encherga ela desta outra classe, dando erro de “cannot resolve symbol” quando você tenta compilar.
Bani
E sobre porque tem que declarar o construtor público, a razão é simples: se você não coloca nenhum construtor para a sua classe, o compilador cria um construtor para você.
E esse construtor é sempre um simples
NomeDaClasse() { super(); }
Portanto, ele tem o acesso “default” e não é visível de fora do pacote.
Se voce tenta isso com membros protected ( acesso sem extender ), da erro. Mas com a inner class nao. ( BEM o contrario do que acontecer quando voce extende e nao tem o construtor public ).
Rafael
Paulo_Silveira
“Bani”:
E sobre porque tem que declarar o construtor público, a razão é simples: se você não coloca nenhum construtor para a sua classe, o compilador cria um construtor para você.
E esse construtor é sempre um simples
NomeDaClasse() { super(); }
Portanto, ele tem o acesso “default” e não é visível de fora do pacote.
Isso nao eh verdade. Pode ateh ser para classe itnerna, mas para classe normal (nao interna, nao nested) o construtor EH public
acabei de fazer o teste novamente para nao falar besteira.
mas o que voce disse PARECE fazer sentido para classe interna
Bani
Realmente falei besteira sobre o construtor.
Após as verificações no JLS do Paulo e Rafael concluiu-se que o construtor fica com o mesmo modificador de acesso da classe.
Mas a idéia básica ainda está valendo: o construtor é protected, portanto só tem acesso por herança, e a classe que estamos estendendo não é a inner class, e sim a outer.
Bani
E sobre o novo código do Rafael, aparentemente depende da versão do compilador…
O meu está dando erro:
C:>javac c08cTeste.java
c08cTeste.java:10: b.ClassePai.Inner has protected access in b.ClassePai
return new ClassePai().new Inner();
^
c08cTeste.java:10: Inner() in b.ClassePai.Inner is not defined in a public class or interface; cannot be accessed from outside package
return new ClassePai().new Inner();
^
2 errors
Rafael_Steil
Eu testei com dois compiladores diferentes… nao pode ser o compilador, deve ser alguma outra coisa…
Para quem quiser testar, o codigo esta em