Quais são os interetações dos métodos sintéticos?
-
20-09-2019 - |
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?
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:
- 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.
- O código do invasor precisa estar no mesmo pacote que sua classe interna (porque o método sintético é declarado pacote-privado).
- 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.