@Suma Como isso pode ser duplicado se a pergunta que você mencionou foi postada um ano após esta?
Ani
1
O Java 8 tem um recurso semelhante aos delegados. Chama-se lambdas.
tbodt
4
@ tbodt para ser mais correto, o Java 8 tem um recurso como os delegados. Chama-se interfaces funcionais . Os lambdas são uma maneira de criar essas instâncias delegadas (anonimamente).
@nawfal, +1, mas, para ser ainda mais correto, o Java 7 e abaixo já possuem um recurso semelhante aos delegados. Chama-se interfaces simples.
Pacerier 5/11
Respostas:
152
Não, realmente não.
Você pode conseguir o mesmo efeito usando a reflexão para obter os objetos Method que você pode chamar, e a outra maneira é criar uma interface com um único método 'invoke' ou 'execute' e instancia-los para chamar o método você está interessado (por exemplo, usando uma classe interna anônima).
Com classes internas anônimas, você pode até evitar declarar classes nomeadas separadas e quase tratá-las como funções delegadas reais.
// JavapublicvoidSomeMethod(ISomeBehaviour pSomeBehaviour){...}...SomeMethod(newISomeBehaviour(){@OverridepublicvoidSomeFunction(){// your implementation}});
Provavelmente, isso só deve ser usado quando a implementação é muito específica para o contexto atual e não se beneficiaria da reutilização.
E, claro, no Java 8, elas se tornam basicamente expressões lambda:
// Java 8SomeMethod(()->{/* your implementation */});
+1. essa é uma solução decente e a verbosidade pode ser compensada pela capacidade de manutenção no futuro.
Nawfal
isso é ótimo ... Atualmente trabalhando em um projeto onde eu sou incapaz de usar a reflexão devido a restrições do projeto e esta solução alternativa começa o trabalho feito muito bem :)
Jonathan Camarena
O Java possui uma convenção de nomenclatura com prefixo I para interfaces? Eu não vi isso antes
A versão mais recente do ambiente de desenvolvimento do Microsoft Visual J ++ oferece suporte a uma construção de linguagem chamada delegados ou referências de método vinculadas . Essa construção, e as novas palavras delegate- chave e
multicastintroduzidas para suportá-la, não fazem parte da linguagem de
programação Java TM , especificada pela Java Language Specification e emendada pela Inner Classes Specification incluída na documentação do software JDKTM 1.1 .
É improvável que a linguagem de programação Java inclua essa construção. A Sun já considerou cuidadosamente adotá-lo em 1996, a ponto de criar e descartar protótipos em funcionamento. Concluímos que as referências aos métodos encadernados são desnecessárias e prejudiciais à linguagem. Esta decisão foi tomada em consulta com a Borland International, que possuía experiência anterior com referências a métodos vinculados no Delphi Object Pascal.
Acreditamos que as referências a métodos vinculados são desnecessárias porque outra alternativa de design, classes internas , fornece funcionalidade igual ou superior. Em particular, as classes internas suportam totalmente os requisitos de manipulação de eventos da interface do usuário e foram usadas para implementar uma API da interface do usuário pelo menos tão abrangente quanto as Classes Windows Foundation.
Acreditamos que as referências aos métodos encadernados são prejudiciais porque prejudicam a simplicidade da linguagem de programação Java e o caráter abrangente das APIs orientadas a objetos. As referências de método vinculado também introduzem irregularidades na sintaxe do idioma e nas regras de escopo. Por fim, eles diluem o investimento em tecnologias de VM porque são necessárias para lidar com tipos adicionais e díspares de referências e vincular métodos com eficiência.
Ótimo artigo. EU AMO a definição deles de "simples": Java é projetado para ser uma linguagem simples, como em "Java deve ser simples de escrever compilador / VM para" enquanto ignora "Java deve ser simples de escrever / ler por uma pessoa" . Explica muito.
Juozas Kontvainis
5
Eu só acho que a SUN cometeu um grande erro. Eles simplesmente não foram convencidos pelo paradigma funcional, e isso é tudo.
Stephane Rolland
7
@ Juozas: Python é explicitamente criado para ser simples de escrever / ler por uma pessoa e implementa funções / delegados lambda .
Stephane Rolland
5
Substituído por um link archive.org. Além disso, isso é realmente estúpido, Oracle.
Delegados são uma construção útil em sistemas baseados em eventos. Essencialmente, delegados são objetos que codificam um envio de método em um objeto especificado. Este documento mostra como as classes internas do java fornecem uma solução mais genérica para esses problemas.
O que é um Delegado? Realmente, é muito semelhante a um ponteiro para função de membro, como usado em C ++. Mas um delegado contém o objeto de destino junto com o método a ser chamado. Idealmente, seria bom poder dizer:
obj.registerHandler (ano.methodOne);
..e que o método methodOne seria chamado no ano em que algum evento específico fosse recebido.
É isso que a estrutura de delegados alcança.
Classes internas de Java
Foi argumentado que o Java fornece essa funcionalidade por meio de classes internas anônimas e, portanto, não precisa da construção Delegate adicional.
À primeira vista, isso parece correto, mas ao mesmo tempo um incômodo. Porque, para muitos exemplos de processamento de eventos, a simplicidade da sintaxe de Delegados é muito atraente.
Manipulador Geral
No entanto, se a programação baseada em eventos for usada de maneira mais abrangente, digamos, por exemplo, como parte de um ambiente de programação assíncrono geral, há mais em jogo.
Em uma situação geral, não é suficiente incluir apenas o método de destino e a instância do objeto de destino. Em geral, pode haver outros parâmetros necessários, que são determinados dentro do contexto quando o manipulador de eventos é registrado.
Nesta situação mais geral, a abordagem java pode fornecer uma solução muito elegante, principalmente quando combinada com o uso de variáveis finais:
Observe que as variáveis finais podem ser acessadas nas definições de método de classe anônima. Certifique-se de estudar este código cuidadosamente para entender as ramificações. Esta é potencialmente uma técnica muito poderosa. Por exemplo, pode ser usado com bom efeito ao registrar manipuladores no MiniDOM e em situações mais gerais.
Por outro lado, a construção Delegate não fornece uma solução para esse requisito mais geral e, como tal, deve ser rejeitada como um idioma no qual os designs podem se basear.
Eu sei que este post é antigo, mas o Java 8 adicionou lambdas e o conceito de uma interface funcional, que é qualquer interface com apenas um método. Juntos, eles oferecem funcionalidade semelhante aos delegados em C #. Veja aqui para mais informações, ou apenas no Google Java Lambdas.
http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html
O bom desse idioma é que você pode verificar se o método delegado existe e tem a assinatura necessária no ponto em que você cria o delegador (embora não seja no tempo de compilação, infelizmente, embora um plug-in FindBugs possa ajuda aqui) e use-o com segurança para delegar em várias instâncias.
Implementei o retorno de chamada / delegar suporte em Java usando reflexão. Detalhes e fonte de trabalho estão disponíveis no meu site .
Como funciona
Há uma classe de princípio chamada de retorno de chamada com uma classe aninhada chamada WithParms. A API que precisa do retorno de chamada terá um objeto de retorno de chamada como parâmetro e, se necessário, criará um Callback.WithParms como uma variável de método. Como muitas das aplicações desse objeto serão recursivas, isso funciona muito bem.
Com o desempenho ainda sendo uma alta prioridade para mim, eu não queria ser obrigado a criar uma matriz de objetos descartáveis para armazenar os parâmetros de cada chamada - afinal, em uma grande estrutura de dados, poderia haver milhares de elementos e no processamento de mensagens cenário, poderíamos acabar processando milhares de estruturas de dados por segundo.
Para ser thread-safe, a matriz de parâmetros precisa existir exclusivamente para cada chamada do método API e, para eficiência, o mesmo deve ser usado para cada chamada do retorno de chamada; Eu precisava de um segundo objeto que seria barato criar para vincular o retorno de chamada a uma matriz de parâmetros para invocação. Mas, em alguns cenários, o invocador já teria uma matriz de parâmetros por outros motivos. Por esses dois motivos, a matriz de parâmetros não pertence ao objeto de retorno de chamada. Além disso, a escolha da chamada (passar os parâmetros como uma matriz ou como objetos individuais) pertence às mãos da API usando o retorno de chamada, permitindo que ela use a chamada que melhor se adequar ao seu funcionamento interno.
A classe aninhada WithParms, portanto, é opcional e serve para dois propósitos, contém a matriz de objetos de parâmetro necessária para as chamadas de retorno de chamada e fornece 10 métodos invoke () sobrecarregados (com de 1 a 10 parâmetros) que carregam a matriz de parâmetros e, em seguida, invocar o destino de retorno de chamada.
A seguir, é apresentado um exemplo usando um retorno de chamada para processar os arquivos em uma árvore de diretórios. Este é um passe de validação inicial que conta apenas os arquivos para processar e garante que nenhum exceda um tamanho máximo predeterminado. Nesse caso, apenas criamos o retorno de chamada em linha com a chamada da API. No entanto, refletimos o método de destino como um valor estático, para que a reflexão não seja feita sempre.
staticprivatefinalMethod COUNT =Callback.getMethod(Xxx.class,"callback_count",true,File.class,File.class);...IoUtil.processDirectory(root,newCallback(this,COUNT),selector);...privatevoid callback_count(File dir,File fil){if(fil!=null){// file is null for processing a directory
fileTotal++;if(fil.length()>fileSizeLimit){thrownewAbort("Failed","File size exceeds maximum of "+TextUtil.formatNumber(fileSizeLimit)+" bytes: "+fil);}}
progress("Counting",dir,fileTotal);}
IoUtil.processDirectory ():
/**
* Process a directory using callbacks. To interrupt, the callback must throw an (unchecked) exception.
* Subdirectories are processed only if the selector is null or selects the directories, and are done
* after the files in any given directory. When the callback is invoked for a directory, the file
* argument is null;
* <p>
* The callback signature is:
* <pre> void callback(File dir, File ent);</pre>
* <p>
* @return The number of files processed.
*/staticpublicint processDirectory(File dir,Callback cbk,FileSelector sel){return _processDirectory(dir,newCallback.WithParms(cbk,2),sel);}staticprivateint _processDirectory(File dir,Callback.WithParms cbk,FileSelector sel){int cnt=0;if(!dir.isDirectory()){if(sel==null|| sel.accept(dir)){ cbk.invoke(dir.getParent(),dir); cnt++;}}else{
cbk.invoke(dir,(Object[])null);File[] lst=(sel==null? dir.listFiles(): dir.listFiles(sel));if(lst!=null){for(int xa=0; xa<lst.length; xa++){File ent=lst[xa];if(!ent.isDirectory()){
cbk.invoke(dir,ent);
lst[xa]=null;
cnt++;}}for(int xa=0; xa<lst.length; xa++){File ent=lst[xa];if(ent!=null){ cnt+=_processDirectory(ent,cbk,sel);}}}}return cnt;}
Este exemplo ilustra a beleza dessa abordagem - a lógica específica do aplicativo é abstraída no retorno de chamada, e o trabalho árduo de percorrer recursivamente uma árvore de diretórios fica bem escondido em um método utilitário estático completamente reutilizável. E não precisamos pagar repetidamente o preço de definir e implementar uma interface para cada novo uso. Obviamente, o argumento para uma interface é que ela é muito mais explícita sobre o que implementar (é aplicada, e não simplesmente documentada) - mas, na prática, não achei um problema obter a definição de retorno de chamada correta.
Definir e implementar uma interface não é tão ruim (a menos que você esteja distribuindo applets, como eu, onde é importante evitar a criação de classes extras), mas o que realmente brilha é quando você tem vários retornos de chamada em uma única classe. Não apenas está sendo forçado a colocá-los em uma classe interna separada, adicionada no aplicativo implementado, mas também é tedioso de programar, e todo esse código da placa da caldeira é realmente apenas "ruído".
Sim e não, mas o padrão de delegação em Java pode ser pensado dessa maneira. Este tutorial em vídeo é sobre troca de dados entre atividade - fragmentos e possui uma grande essência de delegar o padrão sorta usando interfaces.
Ele não possui uma delegatepalavra-chave explícita como C #, mas você pode obter similar no Java 8 usando uma interface funcional (ou seja, qualquer interface com exatamente um método) e lambda:
privateinterfaceSingleFunc{void printMe();}publicstaticvoid main(String[] args){SingleFunc sf =()->{System.out.println("Hello, I am a simple single func.");};SingleFunc sfComplex =()->{System.out.println("Hello, I am a COMPLEX single func.");};
delegate(sf);
delegate(sfComplex);}privatestaticvoid delegate(SingleFunc f){
f.printMe();}
Todo novo objeto do tipo SingleFuncdeve ser implementado printMe(), portanto é seguro passá-lo para outro método (por exemplo delegate(SingleFunc)) para chamar o printMe()método.
Embora esse link possa responder à pergunta, é melhor incluir aqui as partes essenciais da resposta e fornecer o link para referência. As respostas somente para links podem se tornar inválidas se a página vinculada for alterada.
StackFlowed
2
@StackFlowed Retire o link e o que você ganha? Um post com informações. Vote para manter.
Scimonster
1
@ Scimonster, o que aconteceria se o link não fosse mais válido?
StackFlowed
@StackFlowed Ele ainda fornece uma resposta - use um Java Proxy.
Scimonster
então poderia ser deixado como um comentário?
StackFlowed
0
Não, mas tem um comportamento semelhante, internamente.
Em C #, os representantes são usados para criar um ponto de entrada separado e funcionam como um ponteiro de função.
Em java, não há ponteiro de função (em uma visão superior), mas internamente o Java precisa fazer a mesma coisa para atingir esses objetivos.
Por exemplo, a criação de encadeamentos em Java requer uma classe estendendo o Thread ou implementando Runnable, porque uma variável de objeto de classe pode ser usada como um ponteiro de local da memória.
Não, o Java não possui esse recurso incrível. Mas você pode criá-lo manualmente usando o padrão observador. Aqui está um exemplo:
Write C # delegate in java
O código descrito oferece muitas das vantagens dos delegados em C #. Métodos, estáticos ou dinâmicos, podem ser tratados de maneira uniforme. A complexidade de chamar métodos por meio de reflexão é reduzida e o código é reutilizável, no sentido de não exigir classes adicionais no código do usuário. Observe que estamos chamando uma versão alternativa conveniente de invoke, em que um método com um parâmetro pode ser chamado sem criar uma matriz de objetos.
Java não tem delegados e se orgulha disso :). Pelo que li aqui, encontrei em essência 2 maneiras de falsificar delegados: 1. reflexão; 2. classe interna
Reflexões são slooooow! A classe interna não cobre a função mais simples de caso de uso: classificação. Não quero entrar em detalhes, mas a solução com a classe interna é basicamente criar uma classe de wrapper para que uma matriz de números inteiros seja classificada em ordem crescente e uma classe para uma matriz de números inteiros para ordem decrescente.
Respostas:
Não, realmente não.
Você pode conseguir o mesmo efeito usando a reflexão para obter os objetos Method que você pode chamar, e a outra maneira é criar uma interface com um único método 'invoke' ou 'execute' e instancia-los para chamar o método você está interessado (por exemplo, usando uma classe interna anônima).
Você também pode achar este artigo interessante / útil: Um programador Java analisa delegados em C # (@ archive.org)
fonte
Dependendo exatamente do que você quer dizer, é possível obter um efeito semelhante (passando por um método) usando o Padrão de Estratégia.
Em vez de uma linha como esta declarar uma assinatura de método nomeado:
declare uma interface:
Para implementações concretas do método, defina uma classe que implemente o comportamento:
Em qualquer lugar em que você tivesse um
SomeFunction
delegado em C #, use umaISomeBehaviour
referência:Com classes internas anônimas, você pode até evitar declarar classes nomeadas separadas e quase tratá-las como funções delegadas reais.
Provavelmente, isso só deve ser usado quando a implementação é muito específica para o contexto atual e não se beneficiaria da reutilização.
E, claro, no Java 8, elas se tornam basicamente expressões lambda:
fonte
História curta: não .
fonte
Você leu isto :
fonte
Eu sei que este post é antigo, mas o Java 8 adicionou lambdas e o conceito de uma interface funcional, que é qualquer interface com apenas um método. Juntos, eles oferecem funcionalidade semelhante aos delegados em C #. Veja aqui para mais informações, ou apenas no Google Java Lambdas. http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html
fonte
Não, mas é possível usar proxies e reflexão:
O bom desse idioma é que você pode verificar se o método delegado existe e tem a assinatura necessária no ponto em que você cria o delegador (embora não seja no tempo de compilação, infelizmente, embora um plug-in FindBugs possa ajuda aqui) e use-o com segurança para delegar em várias instâncias.
Veja o código karg no github para mais testes e implementação .
fonte
Implementei o retorno de chamada / delegar suporte em Java usando reflexão. Detalhes e fonte de trabalho estão disponíveis no meu site .
Como funciona
Há uma classe de princípio chamada de retorno de chamada com uma classe aninhada chamada WithParms. A API que precisa do retorno de chamada terá um objeto de retorno de chamada como parâmetro e, se necessário, criará um Callback.WithParms como uma variável de método. Como muitas das aplicações desse objeto serão recursivas, isso funciona muito bem.
Com o desempenho ainda sendo uma alta prioridade para mim, eu não queria ser obrigado a criar uma matriz de objetos descartáveis para armazenar os parâmetros de cada chamada - afinal, em uma grande estrutura de dados, poderia haver milhares de elementos e no processamento de mensagens cenário, poderíamos acabar processando milhares de estruturas de dados por segundo.
Para ser thread-safe, a matriz de parâmetros precisa existir exclusivamente para cada chamada do método API e, para eficiência, o mesmo deve ser usado para cada chamada do retorno de chamada; Eu precisava de um segundo objeto que seria barato criar para vincular o retorno de chamada a uma matriz de parâmetros para invocação. Mas, em alguns cenários, o invocador já teria uma matriz de parâmetros por outros motivos. Por esses dois motivos, a matriz de parâmetros não pertence ao objeto de retorno de chamada. Além disso, a escolha da chamada (passar os parâmetros como uma matriz ou como objetos individuais) pertence às mãos da API usando o retorno de chamada, permitindo que ela use a chamada que melhor se adequar ao seu funcionamento interno.
A classe aninhada WithParms, portanto, é opcional e serve para dois propósitos, contém a matriz de objetos de parâmetro necessária para as chamadas de retorno de chamada e fornece 10 métodos invoke () sobrecarregados (com de 1 a 10 parâmetros) que carregam a matriz de parâmetros e, em seguida, invocar o destino de retorno de chamada.
A seguir, é apresentado um exemplo usando um retorno de chamada para processar os arquivos em uma árvore de diretórios. Este é um passe de validação inicial que conta apenas os arquivos para processar e garante que nenhum exceda um tamanho máximo predeterminado. Nesse caso, apenas criamos o retorno de chamada em linha com a chamada da API. No entanto, refletimos o método de destino como um valor estático, para que a reflexão não seja feita sempre.
IoUtil.processDirectory ():
Este exemplo ilustra a beleza dessa abordagem - a lógica específica do aplicativo é abstraída no retorno de chamada, e o trabalho árduo de percorrer recursivamente uma árvore de diretórios fica bem escondido em um método utilitário estático completamente reutilizável. E não precisamos pagar repetidamente o preço de definir e implementar uma interface para cada novo uso. Obviamente, o argumento para uma interface é que ela é muito mais explícita sobre o que implementar (é aplicada, e não simplesmente documentada) - mas, na prática, não achei um problema obter a definição de retorno de chamada correta.
Definir e implementar uma interface não é tão ruim (a menos que você esteja distribuindo applets, como eu, onde é importante evitar a criação de classes extras), mas o que realmente brilha é quando você tem vários retornos de chamada em uma única classe. Não apenas está sendo forçado a colocá-los em uma classe interna separada, adicionada no aplicativo implementado, mas também é tedioso de programar, e todo esse código da placa da caldeira é realmente apenas "ruído".
fonte
Sim e não, mas o padrão de delegação em Java pode ser pensado dessa maneira. Este tutorial em vídeo é sobre troca de dados entre atividade - fragmentos e possui uma grande essência de delegar o padrão sorta usando interfaces.
fonte
Ele não possui uma
delegate
palavra-chave explícita como C #, mas você pode obter similar no Java 8 usando uma interface funcional (ou seja, qualquer interface com exatamente um método) e lambda:Todo novo objeto do tipo
SingleFunc
deve ser implementadoprintMe()
, portanto é seguro passá-lo para outro método (por exemplodelegate(SingleFunc)
) para chamar oprintMe()
método.fonte
Embora não seja tão limpo, você pode implementar algo como delegados de C # usando um Java Proxy .
fonte
Não, mas tem um comportamento semelhante, internamente.
Em C #, os representantes são usados para criar um ponto de entrada separado e funcionam como um ponteiro de função.
Em java, não há ponteiro de função (em uma visão superior), mas internamente o Java precisa fazer a mesma coisa para atingir esses objetivos.
Por exemplo, a criação de encadeamentos em Java requer uma classe estendendo o Thread ou implementando Runnable, porque uma variável de objeto de classe pode ser usada como um ponteiro de local da memória.
fonte
Não, o Java não possui esse recurso incrível. Mas você pode criá-lo manualmente usando o padrão observador. Aqui está um exemplo: Write C # delegate in java
fonte
O código descrito oferece muitas das vantagens dos delegados em C #. Métodos, estáticos ou dinâmicos, podem ser tratados de maneira uniforme. A complexidade de chamar métodos por meio de reflexão é reduzida e o código é reutilizável, no sentido de não exigir classes adicionais no código do usuário. Observe que estamos chamando uma versão alternativa conveniente de invoke, em que um método com um parâmetro pode ser chamado sem criar uma matriz de objetos.
fonte
Java não tem delegados e se orgulha disso :). Pelo que li aqui, encontrei em essência 2 maneiras de falsificar delegados: 1. reflexão; 2. classe interna
Reflexões são slooooow! A classe interna não cobre a função mais simples de caso de uso: classificação. Não quero entrar em detalhes, mas a solução com a classe interna é basicamente criar uma classe de wrapper para que uma matriz de números inteiros seja classificada em ordem crescente e uma classe para uma matriz de números inteiros para ordem decrescente.
fonte