Dúvida declaração estranha

Olá a todos,

Estava estudando um código para captura de eventos em Android e me deparei com uma declaração que não havia visto antes.
Esse código funciona, mas eu não entendo muito bem o que está acontecendo
Percebam que setOnClickListener recebe uma interface do tipo OnClickListener, mas ai tem uma implementação de um metodo dentro, isso é estranho.

O que eu entendi é que o cara ao invés de definir uma classe com a interface OnCLickListener dando um override no OnClick, ele deu um new passando a implementação da interface.

Alguém já havia visto isso antes para me explicar o que exatamente esta acontecendo?

   [code]Button cmdOk = (Button) findViewById(R.id.cmdOk);
    
    //Ao botão ser clicado, ele irá dar um Log no logcat
    cmdOk.setOnClickListener(
    	new Button.OnClickListener()
        {
			public void onClick(View v) {
				Log.d("TesteEventos", "Prezado(a) " + txtNome.getText().toString());
			}
        }
    );[/code]

Obrigado!

        cmdOk.setOnClickListener(  
            new Button.OnClickListener()  
            {  
                public void onClick(View v) {  
                    Log.d("TesteEventos", "Prezado(a) " + txtNome.getText().toString());  
                }  
            }  
        ); 

equivale exatamente a:

       private class XXX implements Button.OnClickListener {
                public void onClick(View v) {  
                    Log.d("TesteEventos", "Prezado(a) " + txtNome.getText().toString());  
                }  
       }
       ...
       XXX xxx = new XXX();
        cmdOk.setOnClickListener(  xxx );

onde XXX é um nome que o compilador criou internamente para batizar uma “classe anônima”. Essas classes anônimas normalmente têm nomes como BBB$20 ou coisa parecida (se a classe onde você criou o seu OnClickListener se chamar BBB). Veja os arquivos .class que foram gerados e perceba que vários deles têm nomes com $ mais um número.

Isso é uma Anonymous Class, voce está implementando diretamente onde usa.

Olá Rafagan, esse tipo de código é estranho mesmo quando vemos pela primeira vez, mas realmente faz parte da linguagem Java e é muito útil para listeners, como é o caso.
Basicamente, o código está declarando uma classe anônima, a qual implementa a interface que aparentemente estaria sendo instanciada, mas a instância é, na verdade, dessa classe anônima.
Isso funciona para interfaces e classes também, onde você pode sobrescrever os métodos de uma classe normal na nova classe anônima.
Continua estudando e logo, logo você acostuma! :smiley:

Galera, obrigado mesmo!

Vocês são demais!!!

Como eu coloquei na dúvida, já desconfiava que alguma coisa assim estava acontecendo, mas como sou programador C++ senti certa insegurança e preferi tirar a prova real com o pessoal que conhece essa sintaxe haha.

Obrigado mesmo pelas respostas!

Pois é, só agora no C++ criaram uma sintaxe semelhante, pode ser que nem esteja disponível na sua versão do compilador C++ que você está usando.

Conheço alguma coisa sobre lambda, seria essa a “notação” que você esta se referindo?

É exatamente isso mesmo. Só não é igual ao “lambda” porque o “lambda” é mais conciso e mais poderoso que “anonymous classes”.

Esse código combina dois recursos. O primeiro é o de Inner Class (classe interna). O conceito tem esse nome, mas vale para interfaces também.
Nada mais é do que uma classe que é declarada dentro de outra:

public class Button { public static interface OnClickListener { void onClick(View v); } //Implementação do button aqui }
Note que a interface foi declarada dentro do escopo do Button.
O static ali indica que você não precisa de uma instância do Button para criar um objeto dessa interface.

Você pode criar um filho dessa interface assim:

public MeuListener implements Button.OnClickListener { @Override public void onClick(View v) { //Implementação do clique } }

Para usar:

Button.OnClickListener meuListener = new MeuClickListener(); cmdOk.setClickListener(meuListener);

O segundo conceito é o de anonimous inner class (classe interna anônima). No Java, existe uma forma bem fácil de criar uma classe que implemente uma interface ou estenda de uma superclasse, para sobrescrever alguns métodos. É assim:

Button.OnClickListener meuClickListener = new Button.OnClickListener() { @Override public void onClick(View v) { //Implementação do meuClickListener aqui } });

Esse código acima é equivalente a:
a) Criar uma nova classe, que implementa a interface OnClickListener;
b) Sobrescrever seu método OnClick;
c) Chamar seu construtor.
d) Atribuir o resultado a variável meuClickListener.

A nova classe criada não terá um nome. Porém, é uma nova classe mesmo, portanto:

meuListener.getClass() == Button.OnClickListener.class; //Retorna false. Não são exatamente a mesma classe meuListener instanceof Button.OnClickListener; //True. É filho de OnClickListener

Existe apenas uma limitação numa Inner class anônima: a superclasse precisa ter um construtor padrão. É o que é chamado ao fazer new Button.OnClickListener()
A vantagem é que elas podem ser declaradas dentro de métodos, como você viu no seu código. No caso do código que você passou, a função setOnClickListener espera uma instância de Button.OnClickListener.

O código então cria a nova classe anônima ali mesmo, e o resultado disso entra como parâmetro de entrada do método.

A partir do Java 8, haverá a inclusão de Lambda Expressions, que simplificará essa sintaxe:

button.addClickListener { view => //Código do listener aqui }

O C# já possui lambda expressions desde a versão 3.5. Mas, por criarem cedo esse recurso, não implementaram o conceito de inner class anônima.
O C++11 também incluiu lambda expressions.