Pergunta

O compilador eclipse se recusa a compilar o código a seguir, afirmando que o campo é não é visível. (Compilador J Aspecto da IBM também se recusa, afirmando que "s não pôde ser resolvido") Por que isso?

public class Test {

    String s;

    void foo(Object o) {
        String os = getClass().cast(o).s;
    }
}

A especificação de linguagem Java afirma:

Caso contrário, dizemos que há padrão acesso, que somente quando é permitido o acesso ocorre de dentro do pacote no qual o tipo é declarado.

A forma como eu entendo, o campo é declarado e acessados ??na mesma unidade de compilação, portanto, dentro do mesmo pacote, e deve, portanto, ser acessível.

Ainda mais estranhamente, adicionando uma entrada de ar de ? extends Test para Test faz, isto é, os compila o seguinte código no campo visíveis:

public class Test {

    String s;

    void foo(Object o) {
        Test t = getClass().cast(o);
        String os = t.s;
    }
}

Tem me deparei com um erro do compilador, ou mal compreendido o Java Spec?

Editar: Estou em outro computador agora. Aqui, javac aceita o código, mas eclipse ainda não. Versões desta máquina:

Eclipse Platform

Versão: 3.4.2 Construir ID: M20090211-1700

JDK 1.6.0

Editar 2 Na verdade, javac aceita o código. Eu tinha testado executando a compilação de formiga, que usa da IBM Ascpect J compilador ...

Foi útil?

Solução

Tente isto:

void foo(Object o) {
    Test foo = getClass().cast(o);
    String so = foo.s;
}

[Edit para esclarecer]:

getClass().cast(o) retorna um objeto do tipo 'capture#1-of? extends Test' e não Test. Então, o problema está relacionado aos genéricos e como os compilador trata de TI. Eu não sei os detalhes da especificação sobre os genéricos, mas dado que alguns compiladores (por comentários aqui) não aceitar o seu código, então este é ou uma lacuna nas especificações ou alguns destes compiladores não estão inteiramente de acordo com as especificações.

[últimos pensamentos]: Eu acredito que o compilador eclipse é realmente (com cuidado) correto aqui. O objecto o pode, de facto, ser uma extensão de Teste (e definido em outro pacote) e o compilador não tem maneira de saber se isso for de facto o caso, ou não. Por isso, é tratá-la como o pior caso de uma instância de uma extensão definida em outro pacote. Teria sido super correto se adicionar um qualificador final para Test classe teria permitido o acesso a s campo, mas isso não acontece.

Outras dicas

Bem, vamos ver. Eu diria que o compilador não pode garantir adequadamente que foo() será chamado por alguma entidade dentro do pacote e, portanto, não pode garantir que s é visível. Por exemplo, adicione

protected void bar() {
    foo();
}

e, em seguida, em algum Banana subclasse em outro pacote

public void quux() { bar(); }

e oops! rendimentos getClass() Banana, que não pode ver s.

Edit: Em certo sentido, other.package.Banana não Have a s campo. Se Banana foram no mesmo pacote, poderia ainda ter sua própria propriedade s, e teria que se referem a Test de s via super.

Eu não posso reproduzir o que você está dizendo. Estes dois fina compilação para mim sem aviso, erro ou qualquer coisa com javac diretamente.

WinXP, javac 1.6.0_16


Não, eu tentei com eclipse (v3.4.1, Construir ID: M20080911-1700) e para o primeiro que diz:

The field Test.s is not visible

Pelo menos para o nível Compiler Compliance 1.6 e 1.5. A coisa ser engraçado, se você olhar para as opções de Quick-Fix it enumera uma resolução Change to 's'. O que, naturalmente, não resolve o problema. Portanto, o compilador eclipse eo "gerador" quick-fix parecem ter opiniões diferentes sobre isso também; -)


Para o nível Compiler Compliance 1.4 (como era de se esperar) em eclipse para o primeiro que eu get

s cannot be resolved or is not a field

e para o segundo I get

Type mismatch: cannot convert from Object to Test

Se eu especificar -source 1.4 e target -1.4 na linha de comando diretamente javac diz para o primeiro

cannot find symbol

e para o segundo I get

incompatible types

Na verdade, em quase todos os casos, exceto quando exigido pela Generics, é melhor (e mais seguro) para usar Java operador de conversão. Eu discuti-lo aqui . Java operador de conversão faz olhar sobre detalhado, mas é a ferramenta certa aqui.

Substituir método cast com as compilações operador muito bem em Eclipse.

public class Test {

    String s;

    void foo(Object o) {
        String os = ((Test) o).s;
    }
}

Eu acho que alphazero está correto aqui , que Eclipse é um pouco mais cauteloso.

Muito estranho. Por uma razão desconhecida (para mim), o compilador eclipse requer uma conversão explícita:

void foo(Object o) {
    String os = ((Test)getClass().cast(o)).s;
}

Enquanto o código perfeitamente compilado sem o elenco com o JDK da Sun (estou executando a versão 1.6.0_16 no GNU / Linux).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top