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.