Java 8 Adicionar extensão / método predefinido à classe

Estou à procura de um java equivalente ao recurso de métodos de extensão C#. Agora eu tenho lido sobre os métodos padrão do Java 8, mas tanto quanto eu posso ver, eu só posso adicioná-los às interfaces...

... Existe algum recurso de linguagem que me permita escrever um método de extensão para uma classe final que não implemente uma interface? (Eu prefiro não ter que embrulhá-lo...)

Author: Cheetah, 2014-06-07

4 answers

Os Métodos de extensão C# são apenas açúcar sintático para métodos estáticos que tomam o tipo estendido como primeiro argumento. Os métodos padrão Java são algo completamente diferente. Para imitar os métodos de extensão C#, Basta escrever os métodos estáticos habituais. Você não terá o açúcar sintático, no entanto; Java não tem este recurso.

Os métodos padrão Java são métodos virtuais reais. Por exemplo, eles podem ser sobrepostos. Considere uma classe X que herda de uma interface I que declara uma método por omissão foo(). Se {[[0]} ou qualquer uma das suas super classes declarar nenhum método próprio {[[2]}, então X irá obter a foo() implementação de I. Agora, uma subclasse Y de X pode sobrepor X.foo() como um método habitual. Assim, os métodos padrão não são apenas açúcar sintático. Eles são extensões reais do método prevalecendo e mecanismo de herança que não podem ser imitados por outras características da linguagem.

Os métodos predefinidos exigem mesmo um suporte VM especial, por isso eles nem sequer são apenas um compilador funcionalidade: durante o carregamento de classes, a hierarquia de uma classe tem de ser verificada para determinar quais os métodos predefinidos que herdará. Assim, esta decisão é tomada em tempo de execução, não em tempo de compilação. A coisa legal sobre isso é que você não tem que recompilar uma classe quando uma interface que herda recebe um novo método padrão: o VM irá, no tempo de carga de classe, atribuir esse novo método a ele.

 21
Author: gexicide, 2018-04-12 21:45:33

C# extension methods are static and use-site , whereas Java's default methods are virtual and declaration-site.

O que eu acredito que você está esperando é a capacidade de "remendar macaco" um método em uma classe que você não controla, mas Java não lhe dá isso (por design; foi considerado e rejeitado.)

Outro benefício dos métodos padrão sobre a abordagem C# é que eles são reflexivamente descobríveis, e de fato a partir do lá fora, não pareça diferente dos métodos de interface "regulares".

Uma vantagem dos métodos de extensão de C#sobre os métodos predefinidos de Java é que com os genéricos reificados de C#, os métodos de extensão são injectados em tipos , não classes , para que possa injectar um método sum() em List<int>.

Acima de tudo, a principal diferença filosófica entre os métodos padrão de Java e os métodos de extensão de C#é que C# permite injectar métodos em tipos Você não controla (o que é certamente conveniente para os desenvolvedores), enquanto os métodos de extensão de Java são uma parte de primeira classe da API em que eles aparecem (eles são declarados na interface, eles são refletivamente descobríveis, etc.) Isto reflete vários princípios de design; os desenvolvedores de bibliotecas devem ser capazes de manter o controle de suas APIs, e o uso da biblioteca deve ser transparente -- o método de chamada x() no tipo Y deve significar a mesma coisa em todos os lugares.

 18
Author: Brian Goetz, 2018-04-13 13:30:25

Java não tem métodos de extensão. Os métodos padrão não são métodos de extensão. Vamos ver cada característica.

Os métodos predefinidos do Java

Problemas resolvidos:

  1. Muitos objectos podem implementar a mesma interface e todos eles podem usar a mesma implementação para um método. Uma classe base poderia resolver este problema, mas apenas se os implementadores de interface não tiverem uma classe base já que java não suporta herança múltipla.
  2. Uma API gostaria de adicionar um método para uma interface sem quebrar os consumidores API. Adicionar um método com uma implementação padrão resolve isso.

Os métodos padrão de Java são uma funcionalidade para adicionar uma implementação padrão a uma interface. Então objetos que estendem uma interface não precisam implementar o método, eles poderiam apenas usar o método padrão.

interface IA { default public int AddOne(int i) { return i + 1; } }

Qualquer objecto que implemente o IA não tem de implementar o AddOne porque existe um método por omissão que seria usado.

public class MyClass implements IA { /* No AddOne implementation needed */ } 

C# falta Esta característica e seria muito melhorada adicionando este recurso. (Actualização: funcionalidade em C # 8)

Método de Extensão da C#

Problemas resolvidos:

    Capacidade de adicionar métodos a classes seladas. Capacidade de adicionar métodos às classes de bibliotecas de terceiros sem forçar a herança.
  1. capacidade de adicionar métodos a classes de modelos em ambientes onde os métodos em classes de modelos não são permitidos por razões de convenção.
  2. a capacidade para intellisense para lhe apresentar estes métodos.

Exemplo: a cadeia de tipos é uma classe selada em C#. Você não pode herdar da cadeia como ela está selada. Mas você pode adicionar métodos que você pode chamar a partir de uma string.

var a = "mystring";
a.MyExtensionMethed()

Java não tem esta funcionalidade e seria muito melhor se adicionasse esta funcionalidade.

Conclusão

Não há nada de semelhante nos métodos predefinidos do Java e nas funcionalidades do método de extensão c#. São completamente diferentes e resolvem completamente diferentes problema.

 17
Author: Rhyous, 2018-05-18 13:46:33
É possível ter métodos de extensão com alguns truques. Pode tentar o Lombok ou o XTend. Embora os métodos de extensão não vêm com a implementação fora da caixa Java, tanto Lombok e XTend oferece uma solução totalmente funcional.

Lombok é um simples framework de processamento de código autônomo, o que torna a maior parte do problema específico Java criticado menos doloroso, incluindo extensão meios: https://projectlombok.org/features/experimental/ExtensionMethod.html

Xtend http://www.eclipse.org/xtend/ vai alguns anos-luz para a frente, e implementa uma linguagem que é uma combinação das melhores partes de linguagens modernas, como o Scala em cima do Java e do Java type system. Isso permite implementar algumas classes no Xtend e outras em Java dentro do mesmo projeto. O código Xtend está em conformidade com o código Java válido, então nenhuma magia JVM acontece sob o capô. No por outro lado, é um pouco demais Se você tem apenas métodos de extensão em falta.

JPropel https://github.com/nicholas22/jpropel-light implementa métodos de extensão de estilo LINQ em Java usando Lombok. Pode valer a pena dar uma espreitadela:)

 6
Author: Gee Bee, 2016-04-11 23:54:04