Por que não consigo definir um método estático em uma interface Java?

499

EDIT: A partir do Java 8, métodos estáticos agora são permitidos em interfaces.

Aqui está o exemplo:

public interface IXMLizable<T>
{
  static T newInstanceFromXML(Element e);
  Element toXMLElement();
}

Claro que isso não vai funcionar. Mas porque não?

Um dos possíveis problemas seria o que acontece quando você liga para:

IXMLizable.newInstanceFromXML(e);

Nesse caso, acho que deveria chamar apenas um método vazio (ou seja, {}). Todas as subclasses seriam forçadas a implementar o método estático, para que ficassem bem ao chamar o método estático. Então, por que isso não é possível?

Edição: Eu acho que estou procurando uma resposta que é mais profunda do que "porque é assim que Java é".

Existe uma razão tecnológica específica para que métodos estáticos não possam ser substituídos? Ou seja, por que os designers de Java decidiram tornar os métodos de instância substituíveis, mas não os métodos estáticos?

Edição: O problema com o meu design é que estou tentando usar interfaces para impor uma convenção de codificação.

Ou seja, o objetivo da interface é duplo:

  1. Eu quero que a interface IXMLizable me permita converter classes que a implementam em elementos XML (usando polimorfismo, funciona bem).

  2. Se alguém quiser criar uma nova instância de uma classe que implemente a interface IXMLizable, sempre saberá que haverá um construtor estático newInstanceFromXML (Element e).

Existe alguma outra maneira de garantir isso, além de apenas colocar um comentário na interface?

cdmckay
fonte
4
Você não precisa desordenar definições de método (e campo) com public in interfaces, btw.
Tom Hawtin #
Hmm, parece ser uma duplicata do stackoverflow.com/questions/21817/… . Não tinha visto isso antes.
Michael Myers
1
Você poderia fornecer algum código, como você gostaria de usar métodos de interface estática?
Pavel Feldman
43
Isso será possível no Java 8: docs.oracle.com/javase/tutorial/java/IandI/…
dakshang
1
@dakshang Sim, mas não faz o que o OP quer.
user253751

Respostas:

518

Java 8 permite métodos de interface estática

Com o Java 8, as interfaces podem ter métodos estáticos. Eles também podem ter métodos de instância concretos, mas não campos de instância.

Há realmente duas perguntas aqui:

  1. Por que, nos velhos tempos, as interfaces não podiam conter métodos estáticos?
  2. Por que métodos estáticos não podem ser substituídos?

Métodos estáticos em interfaces

Não havia uma forte razão técnica pela qual as interfaces não poderiam ter métodos estáticos nas versões anteriores. Isso é resumido muito bem pelo pôster de uma pergunta duplicada. Os métodos de interface estática foram inicialmente considerados como uma pequena alteração de linguagem e, em seguida, houve uma proposta oficial para adicioná-los no Java 7, mas posteriormente foi descartada devido a complicações imprevistas.

Por fim, o Java 8 introduziu métodos de interface estática, bem como métodos de instância substituíveis por uma implementação padrão. Eles ainda não podem ter campos de instância. Esses recursos fazem parte do suporte à expressão lambda e você pode ler mais sobre eles na Parte H do JSR 335.

Substituindo métodos estáticos

A resposta para a segunda pergunta é um pouco mais complicada.

Métodos estáticos são resolvíveis em tempo de compilação. O despacho dinâmico faz sentido, por exemplo, nos métodos em que o compilador não pode determinar o tipo concreto do objeto e, portanto, não pode resolver o método a ser chamado. Mas invocar um método estático requer uma classe e, como essa classe é conhecida estaticamente - em tempo de compilação -, o envio dinâmico é desnecessário.

Um pequeno histórico de como os métodos de instância funcionam é necessário para entender o que está acontecendo aqui. Tenho certeza de que a implementação real é bem diferente, mas deixe-me explicar minha noção de envio de método, que modela o comportamento com precisão.

Finja que cada classe tem uma tabela de hash que mapeia assinaturas de métodos (tipos de nomes e parâmetros) para um pedaço de código real para implementar o método. Quando a máquina virtual tenta chamar um método em uma instância, consulta o objeto para sua classe e procura a assinatura solicitada na tabela da classe. Se um corpo de método for encontrado, ele será chamado. Caso contrário, a classe pai da classe é obtida e a pesquisa é repetida lá. Isso continua até que o método seja encontrado ou que não haja mais classes pai - o que resulta em a NoSuchMethodError.

Se uma superclasse e uma subclasse possuem uma entrada em suas tabelas para a mesma assinatura de método, a versão da subclasse é encontrada primeiro e a versão da superclasse nunca é usada - isso é uma "substituição".

Agora, suponha que pularemos a instância do objeto e apenas começaremos com uma subclasse. A resolução pode prosseguir como acima, fornecendo uma espécie de método estático "substituível". No entanto, a resolução pode ocorrer em tempo de compilação, pois o compilador está iniciando a partir de uma classe conhecida, em vez de aguardar até o tempo de execução para consultar um objeto de um tipo não especificado para sua classe. Não há sentido em "substituir" um método estático, pois sempre é possível especificar a classe que contém a versão desejada.


Construtor "interfaces"

Aqui está um pouco mais de material para abordar a edição recente da pergunta.

Parece que você deseja efetivamente exigir um método semelhante ao construtor para cada implementação do IXMLizable. Esqueça de tentar impor isso com uma interface por um minuto e finja que você tem algumas classes que atendem a esse requisito. Como você usaria isso?

class Foo implements IXMLizable<Foo> {
  public static Foo newInstanceFromXML(Element e) { ... }
}

Foo obj = Foo.newInstanceFromXML(e);

Como você precisa nomear explicitamente o tipo concreto Fooao "construir" o novo objeto, o compilador pode verificar se ele realmente possui o método de fábrica necessário. E se não, e daí? Se eu puder implementar um IXMLizableque não tenha o "construtor" e criar uma instância e passá-la ao seu código, será uma IXMLizablecom toda a interface necessária.

A construção faz parte da implementação, não a interface. Qualquer código que funcione com sucesso com a interface não se importa com o construtor. Qualquer código que se preocupe com o construtor precisa conhecer o tipo concreto de qualquer maneira, e a interface pode ser ignorada.

erickson
fonte
Boa chamada no Project Coin. mail.openjdk.java.net/pipermail/coin-dev/2009-March/000117.html
Michael Myers
12
O motivo do número 1 pode ser herança múltipla? Como podemos herdar de várias interfaces, se duas interfaces contiverem a mesma assinatura de método estático e, em seguida, uma classe os implementa e os chamamos de método, as coisas podem se complicar de uma maneira que os criadores da linguagem Java desejavam evitar ao proibir a herança de várias classes em o primeiro lugar. Obviamente, o mesmo argumento poderia ser feito para a interface que não permite nenhuma definição de método.
precisa saber é o seguinte
1
@ shrini1000 - Não, os métodos estáticos são resolvidos em tempo de compilação. A ambiguidade pode ser tratada da mesma maneira que é tratada com constantes: com um erro do compilador. No entanto, a proposta do Project Coin foi rejeitada, citando algumas dificuldades imprevistas. Não tenho certeza do que eram, mas acho que não foi nesse sentido.
21711
1
@ tgm1024 Sim, a seção "Interfaces do construtor" "explica por que não faz sentido tentar chamar o comportamento polimórfico por meio de um tipo conhecido em tempo de compilação. Como você invocaria RESET()em uma determinada classe? Você escreveria SomeClass.RESET(). Portanto, você não precisa de uma interface para descrever essa API; é estático. As interfaces são usadas quando você não conhece o tipo concreto em tempo de compilação. Esse nunca é o caso de um método estático.
22616
2
"A construção faz parte da implementação, não da interface. Qualquer código que funcione com sucesso com a interface não se importa com o construtor." - Isso claramente não é verdade. Em outros idiomas (por exemplo, Swift), eu posso criar novas instâncias Tsem saber Testaticamente, porque prometo em uma interface que um certo construtor (ou método estático) existirá em tempo de execução. O fato de que a geração é impossível de especificar em Java não significa que não é algo significativo a se fazer.
Raphael
48

Isso já foi perguntado e respondido, aqui

Para duplicar minha resposta:

Nunca há razão para declarar um método estático em uma interface. Eles não podem ser executados pela chamada normal MyInterface.staticMethod (). Se você chamá-los especificando a classe de implementação MyImplementor.staticMethod (), deverá conhecer a classe real, portanto, é irrelevante se a interface a contém ou não.

Mais importante, os métodos estáticos nunca são substituídos e se você tentar:

MyInterface var = new MyImplementingClass();
var.staticMethod();

as regras para static dizem que o método definido no tipo declarado de var deve ser executado. Como essa é uma interface, isso é impossível.

O motivo pelo qual você não pode executar "result = MyInterface.staticMethod ()" é que ele precisaria executar a versão do método definido em MyInterface. Mas não pode haver uma versão definida no MyInterface, porque é uma interface. Não possui código por definição.

Embora você possa dizer que isso equivale a "porque o Java faz dessa maneira", na realidade, a decisão é uma consequência lógica de outras decisões de design, também feitas por uma boa razão.

DJClayworth
fonte
14
Se você usar <T extends MyInterface> como um parâmetro de tipo genérico, seria bom garantir via interface que T possa .doSomething ().
22613 Chris Betti
4
Enquanto entendo os argumentos, concordo com o @Chris_Betti (mesmo para tipos não genéricos): seria bom que a estrutura de código garanta que algumas classes implementem uma API estática específica. Talvez seja possível usar um conceito diferente ...
Juh_
@Juh_, ..... ou uma nova palavra-chave, se absolutamente necessário. De staticqualquer maneira, acredito que seja um termo ruim em idiomas, e foi esticado demais. Portanto, tê-lo por si só já é superficial. Veja meu exemplo acima stackoverflow.com/questions/512877/… {shrug}.
3
Isso parece falso: "Nunca há sentido em declarar um método estático em uma interface". Se eu tiver uma coleção de classes que, sem ser instanciada, possa me oferecer algumas informações, mas eu precisaria de uma interface comum para colocar essas informações estáticas no nível da classe (ou seja, uma interface com um método estático substituível), é um uso válido . Pense em reflexão ++, onde você pode capturar meta-informações sobre propriedades de classe sem vasculhar atributos, reflexão etc.
Jason
1
"Nunca há razão para declarar um método estático em uma interface." Isso não é verdade: imagine que seu sistema tenha um resolvedor de classe padrão. Se detectar que você implementa o método ContainerInjectionInterce :: create (Container $ container), será criado, por exemplo, o objeto com esta função.
user3790897
37

Normalmente, isso é feito usando um padrão de fábrica

public interface IXMLizableFactory<T extends IXMLizable> {
  public T newInstanceFromXML(Element e);
}

public interface IXMLizable {
  public Element toXMLElement();
}
Peter Lawrey
fonte
7
Marcar um padrão de fábrica com +1 é a solução para o problema. (embora não para a causa)
pvgoddijn
Alguém pode me dizer qual é o significado de colocar <T estende IXMLizable> aqui. Eu sou novo no java. O que ele faz?
Nuwan Harshakumara Piyarathna
1
@NuwanHarshakumaraPiyarathna T deve ser uma classe que estende IXMLizable. Pesquise genéricos Java para entender melhor o que isso significa
adrian
37

Com o advento do Java 8 , agora é possível escrever métodos estáticos e padrão na interface. docs.oracle/staticMethod

Por exemplo:

public interface Arithmetic {

    public int add(int a, int b);

    public static int multiply(int a, int b) {
        return a * b;
    }
}
public class ArithmaticImplementation implements Arithmetic {

    @Override
    public int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        int result = Arithmetic.multiply(2, 3);
        System.out.println(result);
    }
}

Resultado : 6

DICA: A chamada de um método de interface estática não precisa ser implementada por nenhuma classe. Certamente, isso acontece porque as mesmas regras para métodos estáticos nas superclasses se aplicam aos métodos estáticos nas interfaces.

rapaz desonesto
fonte
Este é um exemplo perfeito dessa pergunta.
21

Como os métodos estáticos não podem ser substituídos nas subclasses e, portanto, não podem ser abstratos. E todos os métodos em uma interface são, de fato , abstratos.

Michael Myers
fonte
2
Você sempre pode forçar cada tipo a implementar qualquer método de interface estática. Tipo de aula, alguém?
MichaelGG
16
Saia de si mesmo e responda à pergunta: Por que um método estático não pode ser substituído? Se métodos estáticos pudessem ser substituídos, como seria? O que você poderia fazer com eles? Esta resposta é basicamente "Você não pode porque não pode".
214 erickson
10

Por que não consigo definir um método estático em uma interface Java?

Na verdade você pode em Java 8.

Conforme o documento Java :

Um método estático é um método associado à classe em que está definido, e não a qualquer objeto. Cada instância da classe compartilha seus métodos estáticos

No Java 8, uma interface pode ter métodos padrão e métodos estáticos . Isso facilita a organização de métodos auxiliares em nossas bibliotecas. Podemos manter métodos estáticos específicos para uma interface na mesma interface, em vez de em uma classe separada.

Exemplo de método padrão:

list.sort(ordering);

ao invés de

Collections.sort(list, ordering);

Exemplo de método estático (do próprio documento ):

public interface TimeClient {
    // ...
    static public ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default public ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }    
}
akhil_mittal
fonte
6

As interfaces se preocupam com o polimorfismo, inerentemente vinculado a instâncias de objetos, não a classes. Portanto, estática não faz sentido no contexto de uma interface.

cliff.meyers
fonte
Lógica clara e concisa. Bem colocado.
Oke Uwechue 15/08/19
6

Primeiro, todas as decisões de idioma são tomadas pelos criadores do idioma. Não há nada no mundo da engenharia de software ou definição de linguagem ou redação de compilador / intérprete que diga que um método estático não possa fazer parte de uma interface. Eu criei algumas linguagens e escrevi compiladores para elas - tudo é apenas sentar e definir semântica significativa. Eu argumentaria que a semântica de um método estático em uma interface é notavelmente clara - mesmo que o compilador precise adiar a resolução do método para o tempo de execução.

Em segundo lugar, o fato de usarmos métodos estáticos significa que existe uma razão válida para ter um padrão de interface que inclua métodos estáticos - não posso falar por nenhum de vocês, mas uso métodos estáticos regularmente.

A resposta correta mais provável é que não havia necessidade percebida, no momento em que a linguagem foi definida, de métodos estáticos nas interfaces. O Java cresceu muito ao longo dos anos e este é um item que aparentemente ganhou algum interesse. O fato de ele ter sido analisado no Java 7 indica que ele aumentou para um nível de interesse que pode resultar em uma mudança de idioma. Eu, por exemplo, ficarei feliz quando não precisar mais instanciar um objeto para poder chamar meu método getter não estático para acessar uma variável estática em uma instância de subclasse ...

Tallgirl
fonte
5

Os métodos estáticos não são virtuais como os métodos de instância, portanto, suponho que os designers de Java decidiram que não os desejavam nas interfaces.

Mas você pode colocar classes contendo métodos estáticos dentro de interfaces. Você poderia tentar isso!

public interface Test {
    static class Inner {
        public static Object get() {
            return 0;
        }
    }
}
Adrian Pronk
fonte
5
  • "Existe uma razão específica para que métodos estáticos não possam ser substituídos".

Deixe-me reformular essa pergunta preenchendo as definições.

  • "Existe uma razão específica para que os métodos resolvidos em tempo de compilação não possam ser resolvidos em tempo de execução."

Ou, para colocar de forma mais completa, se eu quiser chamar um método sem uma instância, mas conhecendo a classe, como posso resolvê-lo com base na instância que não tenho.

Darron
fonte
3

Várias respostas discutiram os problemas com o conceito de métodos estáticos substituíveis. No entanto, às vezes, você encontra um padrão em que parece que é exatamente isso que deseja usar.

Por exemplo, trabalho com uma camada relacional de objeto que possui objetos de valor, mas também possui comandos para manipular os objetos de valor. Por várias razões, cada classe de objeto de valor precisa definir alguns métodos estáticos que permitem que a estrutura encontre a instância do comando. Por exemplo, para criar uma pessoa que você faria:

cmd = createCmd(Person.getCreateCmdId());
Person p = cmd.execute();

e carregar uma Pessoa por ID que você faria

cmd = createCmd(Person.getGetCmdId());
cmd.set(ID, id);
Person p = cmd.execute();

Isso é bastante conveniente, porém tem seus problemas; notavelmente a existência dos métodos estáticos não pode ser imposta na interface. Um método estático substituível na interface seria exatamente o que precisaríamos, se pudesse funcionar de alguma forma.

Os EJBs resolvem esse problema tendo uma interface inicial; cada objeto sabe como encontrar sua casa e a casa contém os métodos "estáticos". Dessa forma, os métodos "estáticos" podem ser substituídos conforme necessário, e você não confunde a interface normal (chamada "Remota") com métodos que não se aplicam a uma instância do seu bean. Basta fazer com que a interface normal especifique um método "getHome ()". Retorne uma instância do objeto Home (que poderia ser um singleton, suponho) e o chamador pode executar operações que afetam todos os objetos Person.

Sr. Brilhante e Novo 安 宇
fonte
3

Comentando EDIT: As of Java 8, static methods are now allowed in interfaces.

É certo, métodos estáticos, já que o Java 8 é permitido em interfaces, mas seu exemplo ainda não funcionará. Você não pode simplesmente definir um método estático: você precisa implementá-lo ou obterá um erro de compilação.

flavio
fonte
2

Bem, sem genéricos, as interfaces estáticas são inúteis porque todas as chamadas de métodos estáticos são resolvidas no momento da compilação. Portanto, não há uso real para eles.

Com os genéricos, eles têm uso - com ou sem uma implementação padrão. Obviamente, seria necessário substituir e assim por diante. No entanto, meu palpite é que esse uso não foi muito OO (como as outras respostas apontam obtusamente) e, portanto, não foi considerado digno do esforço necessário para implementar de maneira útil.

MichaelGG
fonte
1
O que os genéricos têm a ver com isso? Um método estático em uma interface ainda não seria executável.
DJClayworth 5/02/09
Primeiro, isso seria uma decisão de implementação. Mas suponho que ele não queira chamar métodos estáticos em uma interface (ele poderia apenas usar uma classe). Mas, em vez disso, deseja ter algo como uma classe de tipo ou algo do tipo sobre parâmetros de tipo. De fato, sua edição mais recente mostra isso ainda mais claramente.
28411 MichaelGG
2
Why can't I define a static method in a Java interface?

Todos os métodos em uma interface são explicitamente abstratos e, portanto, você não pode defini-los como estáticos porque os métodos estáticos não podem ser abstratos.

Aniket Thakur
fonte
1

Uma interface nunca pode ser desreferenciada estaticamente, por exemplo ISomething.member. Uma interface é sempre desreferenciada por meio de uma variável que se refere a uma instância de uma subclasse da interface. Assim, uma referência de interface nunca pode saber a qual subclasse se refere sem uma instância de sua subclasse.

Portanto, a aproximação mais próxima de um método estático em uma interface seria um método não estático que ignora "this", isto é, não acessa nenhum membro não estático da instância. Na abstração de baixo nível, todo método não estático (após pesquisa em qualquer vtable) é realmente apenas uma função com escopo de classe que considera "this" como um parâmetro formal implícito. Veja o objeto único de Scala e a interoperabilidade com Java como evidência desse conceito. E, portanto, todo método estático é uma função com escopo de classe que não aceita um parâmetro "this". Assim, normalmente, um método estático pode ser chamado estaticamente, mas, como afirmado anteriormente, uma interface não tem implementação (é abstrata).

Portanto, para obter uma aproximação mais próxima de um método estático em uma interface, é usar um método não estático e não acessar nenhum membro da instância não estática. Não haveria benefício de desempenho possível de nenhuma outra maneira, porque não há maneira de vincular estaticamente (em tempo de compilação) a ISomething.member(). O único benefício que vejo de um método estático em uma interface é que ele não inseria (isto é, ignora) um "isto" implícito e, portanto, desaprova o acesso a qualquer membro da instância não estática. Isso declararia implicitamente que a função que não acessa "this" é imutável e nem mesmo é apenas de leitura em relação à classe que o contém. Mas uma declaração de "estática" em uma interfaceISomething também confundiria as pessoas que tentaram acessá-la comISomething.member()o que causaria um erro do compilador. Suponho que se o erro do compilador fosse suficientemente explicativo, seria melhor do que tentar educar as pessoas sobre o uso de um método não estático para realizar o que elas desejam (aparentemente métodos principalmente de fábrica), como estamos fazendo aqui (e foi repetido por 3 anos). Perguntas e respostas neste site), portanto é obviamente um problema que não é intuitivo para muitas pessoas. Eu tive que pensar por um tempo para obter o entendimento correto.

A maneira de obter um campo estático mutável em uma interface é usar métodos getter e setter não estáticos em uma interface, para acessar esse campo estático na subclasse. Sidenote, estática aparentemente imutável pode ser declarada em uma interface Java com static final.

Shelby Moore III
fonte
0

As interfaces apenas fornecem uma lista das coisas que uma classe fornecerá, não uma implementação real dessas coisas, que é o seu item estático.

Se você deseja estática, use uma classe abstrata e a herde; caso contrário, remova a estática.

Espero que ajude!

samoz
fonte
2
Bem, em teoria, você pode definir uma interface para incluir um comportamento estático, ou seja, "implementações dessa interface terão um método estático foo () com essa assinatura" e deixar a implementação para a classe específica. Eu encontrei situações em que esse comportamento seria útil.
Rob
0

Você não pode definir métodos estáticos em uma interface porque os métodos estáticos pertencem a uma classe e não a uma instância da classe, e as interfaces não são Classes. Leia mais aqui.

No entanto, se você quiser, pode fazer o seguinte:

public class A {
  public static void methodX() {
  }
}

public class B extends A {
  public static void methodX() {
  }
}

Nesse caso, você tem duas classes com 2 métodos estáticos distintos, denominados methodX ().

Handerson
fonte
0

Suponha que você possa fazer isso; considere este exemplo:

interface Iface {
  public static void thisIsTheMethod();
}

class A implements Iface {

  public static void thisIsTheMethod(){
    system.out.print("I'm class A");
  }

}

class B extends Class A {

  public static void thisIsTheMethod(){
    System.out.print("I'm class B");
  } 
}

SomeClass {

  void doStuff(Iface face) {
    IFace.thisIsTheMethod();
    // now what would/could/should happen here.
  }

}
pvgoddijn
fonte
1
Seria impresso "Eu sou da classe A". No entanto, se você digitar A.thisIsTheMethod(), imprimirá "Sou da classe B".
Cdmckay 15/02/09
mas chamando os métodos na interface, como você (ou o compilador) sabe qual método deve ser chamado? (rember pode haver mais aulas dricetly implementação Iface
pvgoddijn
desculpe, eu quis dizer: No entanto, se você digitar, B.thisIsTheMethod()ele imprimirá "Sou da classe B".
Cdmckay 19/02/09
Eu disse IFace.thisIsTHeMethod de propósito, porque aí reside o problema. não seria possível chamá-lo na interface sem um comportamento indefinido (embora a sua declarada nele)
pvgoddijn
0

Algo que pode ser implementado é a interface estática (em vez do método estático em uma interface). Todas as classes que implementam uma determinada interface estática devem implementar os métodos estáticos correspondentes. Você pode obter a interface estática SI de qualquer classe usando

SI si = clazz.getStatic(SI.class); // null if clazz doesn't implement SI
// alternatively if the class is known at compile time
SI si = Someclass.static.SI; // either compiler errror or not null

então você pode ligar si.method(params). Isso seria útil (para o padrão de design de fábrica, por exemplo), porque você pode obter (ou verificar a implementação de) implementação de métodos estáticos de SI a partir de uma classe desconhecida em tempo de compilação! Um despacho dinâmico é necessário e você pode substituir os métodos estáticos (se não finais) de uma classe estendendo-os (quando chamados pela interface estática). Obviamente, esses métodos podem acessar apenas variáveis ​​estáticas de sua classe.

Christophe Bouchon
fonte
0

Enquanto eu percebo que o Java 8 resolve esse problema, pensei em entrar em contato com um cenário em que estou trabalhando no momento (bloqueado no uso do Java 7), no qual seria útil especificar métodos estáticos em uma interface.

Eu tenho várias definições de enum em que defini os campos "id" e "displayName", juntamente com os métodos auxiliares que avaliam os valores por vários motivos. A implementação de uma interface permite garantir que os métodos getter estejam em vigor, mas não os métodos auxiliares estáticos. Sendo um enum, realmente não existe uma maneira limpa de transferir os métodos auxiliares para uma classe abstrata herdada ou algo parecido, de modo que os métodos tenham que ser definidos no próprio enum. Também porque é um enum, você nunca seria capaz de transmiti-lo como um objeto instanciado e tratá-lo como o tipo de interface, mas é possível exigir a existência de métodos auxiliares estáticos por meio de uma interface. sendo suportado no Java 8.

Aqui está o código que ilustra meu ponto.

Definição da interface:

public interface IGenericEnum <T extends Enum<T>> {
    String getId();
    String getDisplayName();
    //If I was using Java 8 static helper methods would go here
}

Exemplo de uma definição de enumeração:

public enum ExecutionModeType implements IGenericEnum<ExecutionModeType> {
    STANDARD ("Standard", "Standard Mode"),
    DEBUG ("Debug", "Debug Mode");

    String id;
    String displayName;

    //Getter methods
    public String getId() {
        return id;
    }

    public String getDisplayName() {
        return displayName;
    }

    //Constructor
    private ExecutionModeType(String id, String displayName) {
        this.id = id;
        this.displayName = displayName;
    }

    //Helper methods - not enforced by Interface
    public static boolean isValidId(String id) {
        return GenericEnumUtility.isValidId(ExecutionModeType.class, id);
    }

    public static String printIdOptions(String delimiter){
        return GenericEnumUtility.printIdOptions(ExecutionModeType.class, delimiter);
    }

    public static String[] getIdArray(){
        return GenericEnumUtility.getIdArray(ExecutionModeType.class);
    }

    public static ExecutionModeType getById(String id) throws NoSuchObjectException {
        return GenericEnumUtility.getById(ExecutionModeType.class, id);
    }
}

Definição de utilitário de enumeração genérica:

public class GenericEnumUtility {
    public static <T extends Enum<T> & IGenericEnum<T>> boolean isValidId(Class<T> enumType, String id) {       
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(enumOption.getId().equals(id)) {
                return true;
            }
        }

        return false;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String printIdOptions(Class<T> enumType, String delimiter){
        String ret = "";
        delimiter = delimiter == null ? " " : delimiter;

        int i = 0;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(i == 0) {
                ret = enumOption.getId();
            } else {
                ret += delimiter + enumOption.getId();
            }           
            i++;
        }

        return ret;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String[] getIdArray(Class<T> enumType){
        List<String> idValues = new ArrayList<String>();

        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            idValues.add(enumOption.getId());
        }

        return idValues.toArray(new String[idValues.size()]);
    }

    @SuppressWarnings("unchecked")
    public static <T extends Enum<T> & IGenericEnum<T>> T getById(Class<T> enumType, String id) throws NoSuchObjectException {
        id = id == null ? "" : id;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(id.equals(enumOption.getId())) {
                return (T)enumOption;
            }
        }

        throw new NoSuchObjectException(String.format("ERROR: \"%s\" is not a valid ID. Valid IDs are: %s.", id, printIdOptions(enumType, " , ")));
    }
}
Ryan
fonte
0

Vamos supor que métodos estáticos foram permitidos nas interfaces: Eles forçariam todas as classes de implementação a declarar esse método. * As interfaces normalmente seriam usadas por meio de objetos, portanto os únicos métodos eficazes para esses métodos seriam os não estáticos. * Qualquer classe que conhece uma interface específica pode invocar seus métodos estáticos. Portanto, o método estático de uma classe de implementação seria chamado por baixo, mas a classe invocadora não sabe qual. Como saber isso? Não há instancia para adivinhar isso!

As interfaces foram pensadas para serem usadas ao trabalhar com objetos. Dessa forma, um objeto é instanciado a partir de uma classe específica, para que esta última questão seja resolvida. A classe de chamada não precisa saber qual classe específica é porque a instanciação pode ser feita por uma terceira classe. Portanto, a classe de chamada conhece apenas a interface.

Se queremos que isso seja estendido aos métodos estáticos, devemos ter a possibilidade de especificar uma classe de implementação antes e depois passar uma referência à classe de chamada. Isso poderia usar a classe através dos métodos estáticos na interface. Mas qual é a diferença entre essa referência e um objeto? Nós apenas precisamos de um objeto representando o que era a classe. Agora, o objeto representa a classe antiga e pode implementar uma nova interface, incluindo os métodos estáticos antigos - esses agora não são estáticos.

As metaclasses servem para esse fim. Você pode tentar a classe Class of Java. Mas o problema é que o Java não é flexível o suficiente para isso. Você não pode declarar um método no objeto de classe de uma interface.

Esta é uma meta questão - quando você precisa fazer burro

..blah blah

de qualquer maneira, você tem uma solução fácil - tornando o método não estático com a mesma lógica. Mas então você teria que primeiro criar um objeto para chamar o método.

beibichunai
fonte
0

Para resolver isso: error: falta o corpo do método ou declare abstract static static void main (String [] args);

interface I
{
    int x=20;
    void getValue();
    static void main(String[] args){};//Put curly braces 
}
class InterDemo implements I
{
    public void getValue()
    {
    System.out.println(x);
    }
    public static void main(String[] args)
    {
    InterDemo i=new InterDemo();
    i.getValue();   
    }

}

saída: 20

Agora podemos usar o método estático na interface

Aashish Pawar
fonte
1
Isso é inútil, no entanto. Definir um método estático em uma interface não impõe definições adicionais nas classes que implementam essa interface. Se você apenas remover completamente o método estático da interface I, seu código será compilado e executado de qualquer maneira, sem problemas. Em outras palavras, você NÃO está substituindo o método principal da interface I na classe InterDemo, apenas criando um novo método com a mesma assinatura.
27618 Fran Marzoa
-2

Eu acho que o java não tem métodos de interface estática, porque você não precisa deles. Você pode pensar que sim, mas ... Como você os usaria? Se você quiser chamá-los como

MyImplClass.myMethod()

então você não precisa declará-lo na interface. Se você quiser chamá-los como

myInstance.myMethod()

então não deve ser estático. Se você realmente usar a primeira maneira, mas apenas desejar aplicar cada implementação a ter esse método estático, será realmente uma convenção de codificação, não um contrato entre a instância que implementa uma interface e o código de chamada.

As interfaces permitem definir o contrato entre a instância da classe que implementa a interface e o código de chamada. E o java ajuda você a garantir que este contrato não seja violado, para que você possa confiar nele e não se preocupar com a classe que implementa esse contrato, apenas "alguém que assinou um contrato" é suficiente. No caso de interfaces estáticas, seu código

MyImplClass.myMethod()

não depende do fato de que cada implementação de interface possui esse método, portanto você não precisa do java para ajudá-lo a ter certeza.

Pavel Feldman
fonte
-5

Qual é a necessidade do método estático na interface, os métodos estáticos são usados ​​basicamente quando você não precisa criar uma instância do objeto. A idéia da interface é trazer conceitos de POO com a introdução do método estático que você está desviando do conceito.

VIckyb
fonte