Pergunta

Problema

Um amigo sugeriu um problema interessante. Dado o seguinte código:

public class OuterClass {

    private String message = "Hello World";

    private class InnerClass {
        private String getMessage() {
            return message;
        }
    }

}

De uma aula externa, como posso imprimir o message conteúdo variável? Obviamente, mudar a acessibilidade de métodos ou campos é não permitido.

(a fonte aqui, mas é um blog francês)


Solução

O código para resolver esse problema é o seguinte:

try {
    Method m = OuterClass.class.getDeclaredMethod("access$000", OuterClass.class);
    OuterClass outerClass = new OuterClass();
    System.out.println(m.invoke(outerClass, outerClass));
} catch (Exception e) {
    e.printStackTrace();
}

Observe que o access$000 O nome do método não é realmente padrão (mesmo que este formato seja o que é fortemente recomendado), e alguma JVM nomeará este método access$0. Assim, uma solução melhor é verificar se há métodos sintéticos:

Method method = null;
int i = 0;
while ((method == null) && (i < OuterClass.class.getDeclaredMethods().length)) {
    if (OuterClass.class.getDeclaredMethods()[i].isSynthetic()) {
        method = OuterClass.class.getDeclaredMethods()[i];
    }
    i++;
}
if (method != null) {
    try {
        System.out.println(method.invoke(null, new OuterClass()));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Portanto, o ponto interessante desse problema é destacar o uso de métodos sintéticos. Com esses métodos, posso acessar um campo privado como foi feito na solução. Claro, preciso usar a reflexão e acho que o uso desse tipo de coisa pode ser bastante perigoso ...

Pergunta

Qual é o interesse - para mim, como desenvolvedor - de um método sintético? O que pode ser uma boa situação em que o uso do sintético pode ser útil?

Foi útil?

Solução

Como você demonstra, os modificadores de acesso ao Java são meramente informativos e podem ser contornados usando a reflexão. Portanto, suas perguntas são aproximadamente equivalentes a "qual é o interesse de contornar um modificador de acesso?" Além de propósitos maliciosos, depuração vem à mente; Você pode, por exemplo, registrar o estado interno dos internos de algumas bibliotecas de fora A biblioteca, sem precisar tocar o código da biblioteca. Outro exemplo é cooperação com linguagens de script; Se você não sabe no tempo de compilação quais classes e métodos estão disponíveis, a reflexão pode ser bastante útil. Por exemplo, JythonOs internos usam enormes quantidades de reflexão ao redor.

Outras dicas

Qual é o interesse - para você, como desenvolvedor - de um método sintético? Bem, para iniciantes, não os invoce (por razões que outros respondentes explicaram).

Mas há uma coisa interessante a ter em mente, principalmente se você estiver escrevendo o código Java para executar em um ambiente sensível à segurança, e isso é que os métodos sintéticos podem potencialmente fornecer aos atacantes uma porta de fundo para seus campos particulares.

Obviamente, existem alguns grandes "ifs"-quero dizer, condições necessárias-para essa vulnerabilidade para realmente importar:

  1. O invasor realmente precisa estar executando o código em sua JVM. Na maioria das vezes, isso não é um problema, porque o único código em execução é o seu.
  2. O código do invasor precisa estar no mesmo pacote que sua classe interna (porque o método sintético é declarado pacote-privado).
  3. O código do invasor deve ser carregado do mesmo carregador de classe que sua classe. Se você está deixando o código não confiável ser executado na sua JVM (condição nº 1), é melhor usar um carregador de classe separado para o código não confiável.

Você nunca deve invocar os métodos de acessórios sintéticos usando a reflexão, eles podem mudar, dependendo do compilador que você usa. Por exemplo, executar sua solução no JDK1.6 na minha máquina falhou, pois o access$000 o método não foi encontrado.

Os acessores sintéticos são um hacker do compilador sob as coberturas para contornar o fato de que as classes internas foram uma adição ao Java 1.1, e as especificações da VM nunca foram alteradas para acomodá-las.

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