Protegido em Interfaces

111

Por que todos os métodos estão interfaceimplicitamente em uma definição public? Por que não permite um protectedmétodo?

Swaranga Sarma
fonte
22
Ótima pergunta. Para quase todas as outras coisas em Java, encontrei uma razão real para as escolhas feitas, mas para esta não. Faz todo o sentido para mim definir um método protegido em uma interface que permite que outra classe dentro do mesmo pacote use esse método em um objeto de implementação sem a necessidade de expor esse método, que pode não ser chamado por ninguém que não seja o membros do pacote, para o resto do mundo.
Markus A.
4
@MarkusA. Mas as interfaces funcionam em dois sentidos, ou seja, também podem ser implementadas por classes fora do pacote atual (e então talvez passadas como argumentos para métodos dentro deste pacote). Como uma classe de fora do pacote atual seria capaz de implementar métodos "protegidos" de alguma interface pública?
MartinStettner
8
@MartinStettner: Não seria. Esse seria o ponto. Um pacote pode ter várias classes não relacionadas que implementam uma interface e deseja garantir a qualquer código que receba uma referência desse tipo de interface que se comportará de uma determinada maneira. Essa garantia poderia ser muito mais forte se o código externo pudesse ser impedido de reivindicar a implementação da interface enquanto se comporta de maneira contrária ao seu contrato.
supercat
1
@MarkusA. você levantou um bom ponto, você deve ser capaz de alcançá-lo com o sistema de módulos do Java 9
Nir Alfasi
1
se interface tiver protectedmétodo, todas as classes de implementação serão vistas como um subtipo da interface. e todas essas classes PODEM acessar métodos protegidos. não torna a protectedpalavra - chave no método inútil? contanto que não tenhamos nenhuma maneira de restringir quem implementa essa palavra-chave protegida de interface no método, é inútil. Corrija-me se eu estiver errado!
Amarnath Harish

Respostas:

67

Porque uma interface deve significar "o que você pode ver de fora da classe". Não faria sentido adicionar métodos não públicos.

Raveline
fonte
16
Mas por que não ter funções que apenas membros do mesmo pacote que a interface "podem ver de fora da classe"? Tive vários casos de uso em que desejava isso.
Markus A.
5
@MarkusA. Sei que está tarde, mas então você pode fazer um completo abstract class, que é tudo interfaceo que é, e especificar o acesso que deseja. Concedido, isso perde o benefício de várias implementações que interfaceobtêm em Java, mas honestamente estabelecer um contrato que adere às limitações de algum outro pacote seria não testável e confuso, já que você praticamente não seria capaz de acessar o método de sua própria implementação fora desse pacote .
pickypg de
10
@pickypg Mas se a classe que implementaria a interface já estende outra classe, você não pode fazer com que ela estenda outra classe. Eu não acharia confuso para uma interface que é usada apenas dentro de um pacote.
Flamma de
24
@Raveline, -1, Isso levanta a questão "por que uma interface significa o que você pode ver de fora da classe?" O Java 8 já permite o corpo do método em interfaces, então por que não permitir métodos abstratos protegidos também?
Pacerier
8
Costumo ler esta explicação, mas é IMHO errado. Uma Interface é uma espécie de "protocolo de troca padrão", não importa se falando sobre OOP, API de comunicação ou hardware. A porta USB do meu PC é claramente uma interface pública. Mas os pinos da minha placa-mãe, que está atrás de uma caixa com chave, que fornecem acesso a portas USB opcionais são claramente uma interface "protegida". Depois, temos o chip BIOS - que também é uma interface padronizada, mas nunca foi divulgada de forma alguma, apenas algumas empresas sabem os detalhes exatos em particular. Então, é claro, as interfaces podem ter qualquer visibilidade! Por que não em OOP?
Foo Bar de
55

Embora o motivo frequentemente citado seja que "as interfaces definem APIs públicas", acho que é uma simplificação excessiva. (E também "cheira" a lógica circular.)

Não faria sentido ter interfaces com uma mistura de modificadores de acesso; por exemplo, parcialmente público e parcialmente restrito a outras classes no mesmo pacote da interface. Na verdade, em alguns casos, isso poderia ser útil, IMO.

Na verdade, acho que a parte do raciocínio por trás de tornar os membros de uma interface implicitamente públicos é que isso torna a linguagem Java mais simples :

  • Membros de interface implicitamente públicos são mais simples de lidar para os programadores. Quantas vezes você já viu código (classes) em que os modificadores de acesso do método foram escolhidos aparentemente de forma aleatória? Muitos programadores "comuns" têm dificuldade em entender a melhor forma de gerenciar os limites de abstração do Java 1 . Adicionar public / protected / package-private às interfaces torna ainda mais difícil para eles.

  • Os membros da interface implicitamente públicos simplificam a especificação da linguagem ... e, portanto, a tarefa para os escritores do compilador Java e as pessoas que implementam as APIs de reflexão.

A linha de pensamento de que as "interfaces definem APIs públicas" é indiscutivelmente uma consequência (ou característica) da simplificação da decisão de design de linguagem ... e não o contrário. Mas, na realidade, as duas linhas de pensamento provavelmente se desenvolveram em paralelo nas mentes dos designers de Java.

De qualquer forma, a resposta oficial ao RFE no JDK-8179193 deixa claro que a equipe de design Java decidiu 2 que permitir protectedinterfaces adiciona complexidade para poucos benefícios reais. Parabéns a @skomisa por encontrar as evidências .

A evidência no RFE resolve a questão. Essa é a razão oficial pela qual não foi adicionado.


1 - É claro que os programadores de primeira linha não têm dificuldade com essas coisas e podem receber uma paleta mais rica de recursos de controle de acesso. Mas, o que acontece quando o código é entregue a outra pessoa para manutenção?

2 - Você pode discordar da decisão ou do raciocínio deles, mas isso é discutível.

Stephen C
fonte
21

Devo dizer que essa questão foi reaberta com a introdução de métodos padrão em Java 8. O projeto em que estou trabalhando agora é, semelhante à natureza básica de uma interface, destinado a abstrair a intenção da implementação.

Existem vários casos em que eu poderia simplificar drasticamente meu código com um método "protegido por padrão". Acontece que isso realmente não funciona, já que as interfaces ainda seguem a lógica do Java 7. Um método normal protegido não faz nenhum sentido especialmente, pelas razões mencionadas acima; mas se um método público padrão requer um recurso de baixo nível que provavelmente não mudará e pode ser fornecido por um método protegido, parece-me que ter um trabalho "protegido por padrão" não apenas manteria um código mais limpo, mas protegeria futuros usuários de abusos acidentais.

(Isso tragicamente não muda o fato de que ainda preciso complicar demais meu código com resumos desnecessários; mas pretendo colocar uma solicitação de recurso no Oracle.)

Michael Oberlin
fonte
Eu concordo 100%. As classes abstratas eram uma alternativa sensata antes da introdução dos métodos padrão. No entanto, as limitações que eles colocam na herança múltipla significa que eles não são perfeitos. Interfaces com métodos padrão são normalmente melhores alternativas em um mundo> = JDK 1.8, mas como não podem armazenar o estado, eles dependem da definição de outros métodos abstratos para expor o estado, o que significa que o estado é tornado público, o que nem sempre é o que você quer.
Pe. Jeremy Krieg
10

Porque as interfaces definem APIs públicas. Tudo o que é protegido é um detalhe interno que não pertence a uma interface.

Você pode usar classes abstratas com métodos abstratos protegidos, mas as interfaces são restritas a métodos públicos e campos finais públicos estáticos.

Sean Patrick Floyd
fonte
5
Você declarou "porque as interfaces definem APIs públicas". Então, por que as interfaces devem definir apenas publicAPIs? Há uma diferença entre "detalhe interno" e "detalhe de implementação", protectedem Java definitivamente não é um detalhe interno, pois agora é uma interface pública publicada para todos que podem criar uma subclasse, que é basicamente o mundo inteiro.
Pacerier
1
Isso não é mais verdade com os métodos padrão do Java 8.
Mario Rossi
@MarioRossi E também não é mais verdade com os métodos de interface privada do Java 9.
skomisa
7

Talvez porque seja uma interface , ou seja, existe para dizer aos clientes o que eles podem fazer com as instâncias, em vez de dizer o que não podem fazer.

Ingo
fonte
1
Não vejo por que uma interface também não poderia dizer às subclasses o que elas podem fazer sem expor essa implementação para o mundo externo. Essa foi uma decisão de design que foi tomada em um momento em que classes abstratas podiam ser usadas como uma alternativa perfeita. Mas, com o advento dos métodos padrão nas interfaces, as classes abstratas agora são uma alternativa imperfeita.
Pe. Jeremy Krieg
6

Acredito fortemente que as interfaces devem permitir métodos protegidos; quem disse que as interfaces têm que ser visíveis para todos no mundo inteiro? Quanto ao seu ponto, isso pode confundir programadores "comuns" (leia-se: incompetentes): Muito do OOP é sobre estruturar objetos, classes, pacotes, etc., se um programador tem dificuldade em fazer tudo isso corretamente, ele tem um problema muito maior. Java foi construído para esse tipo de coisa.

IntelliData
fonte
Isso não responde à pergunta.
Stephen C
5

Várias respostas aqui empregam raciocínio circular para explicar por que os métodos de interface não podem ser protegidos: é porque eles têm que ser públicos, então obviamente eles não podem ser protegidos!

Isso não explica nada, mas felizmente alguém levantou uma solicitação de aprimoramento para métodos protegidos em interfaces como um bug do JDK alguns anos atrás, o que lança alguma luz sobre o problema:

Métodos protegidos em interfaces: compartilhe entre pacotes

Como os modificadores são um pouco limitados em Java, uma maneira de compartilhar métodos entre os pacotes é restrita aos métodos públicos. Às vezes, é perigoso tornar um método público, mas precisa ser devido à falta de modificadores adequados. Minha solução supera essa limitação.

A especificação da linguagem java atualmente não permite o modificador protegido para métodos de interface. Podemos tirar vantagem desse fato e usar métodos de interface protegidos para esse novo recurso.

Se um método de interface for marcado como protegido e a interface for implementada por uma classe em outro pacote, o método não precisa ser público, mas também pode ser privado ou pelo menos protegido por pacote. O método é visível, o que quer que a classe declare como e adicionalmente visível no pacote fonte da interface (e subpacotes?).

Dessa forma, podemos compartilhar certos métodos entre pacotes bem conhecidos.

E esta é a resposta a essa solicitação de melhoria, que foi encerrada com o status Won't fix:

Esta proposta tenta resolver um problema de uma forma que adiciona complexidade e casos especiais com pouco ganho real. Uma maneira típica de resolver esse problema é ter uma classe privada que implemente uma interface pública. Os métodos de implementação são públicos, mas estão dentro de uma classe privada, portanto, permanecem privados.

Uma alternativa disponível a partir do Java 9 é tornar as classes e métodos públicos, mas dentro de um módulo que possui uma exportação qualificada para módulos "amigos" específicos em vez de ser exportado para o público em geral.

Portanto, as conclusões oficiais desse relatório de bug são:

  • A situação atual não vai mudar; as interfaces provavelmente nunca suportarão protectedmétodos.
  • A justificativa para não suportar protectedmétodos em interfaces é que isso " adiciona complexidade e casos especiais para pouco ganho real ".
  • Desde o Java 9, existe uma abordagem alternativa para fornecer acesso aos métodos em nível de pacote. Use o Java Platform Module System (JPMS) para " tornar as classes e métodos públicos, mas dentro de um módulo que tenha uma exportação qualificada para módulos" amigos "específicos em vez de ser exportado para o público em geral ".
Skomisa
fonte
4

Como uma classe de implementação deve implementar TODOS os métodos declarados em sua interface, o que aconteceria se sua classe de implementação estivesse em um pacote diferente?

dm76
fonte
2

Interface Se você quiser usar algo como você descreveu, continue com classes abstratas ou interfaces aninhadas.

Um exercício do Estilo de Código sobre variáveis ​​de interface, mas ainda se aplica a métodos:

Variáveis ​​de interface são implicitamente públicas porque as interfaces se destinam a fornecer uma Interface de Programação de Aplicativo (API) totalmente acessível aos programadores Java para referência e implementação em seus próprios aplicativos. Como uma interface pode ser usada em pacotes Java diferentes dos seus, a visibilidade pública garante que o código do programa possa acessar a variável.
urso pardo
fonte
2

Declarar subinterfaces internas é uma boa prática, mas você não pode declarar seus métodos internos como protectedem uma interface em Java, tecnicamente.

Claro, você pode criar outra interface para uso interno que estenda a interface pública:

package yourpackage;

public interface PublicInterface {

    public void doThing1();

    public void doThing2();

    public void doThing3();

}

package yourpackage;

interface InternalInterface extends PublicInterface {

    void doAnyInternalThing1();

    void doAnyInternalThing2();

}

Você pode usar a InternalInterfaceinterface dentro do pacote, mas deve aceitar qualquer subtipo de PublicInterface(nos métodos públicos):

package yourpackage;

public class SomeClass {

    public void someMethod(PublicInterface param) {
        if (param instanceof InternalInterface) {
            // run the optimized code
        } else {
            // run the general code
        }
    }

}

Fora do pacote, os usuários podem usar PublicInterfacesem problemas.

Normalmente, os programadores criam classes abstratas em situações semelhantes. No entanto, neste caso, perdemos os benefícios da herança múltipla.

Dávid Horváth
fonte
1
Fora do pacote, os usuários também podem usar YourPublicInterface.Internal. Tudo em uma interface, incluindo interfaces aninhadas, é público, independentemente da presença ou ausência da publicpalavra - chave.
Greg Roelofs
1

O único cenário em que faria sentido é quando você deseja restringir a visibilidade ao mesmo pacote. Todos os outros usos de protectednão são aplicáveis. Especificamente, os protectedmétodos são freqüentemente usados ​​para fornecer acesso a alguns detalhes de implementações de nível inferior para descendentes. Mas declarar isso em uma interface não faz sentido, pois não há implementação de nível inferior para expor.

E mesmo o cenário do pacote não é realmente do que tratam as interfaces.

Para conseguir o que você provavelmente deseja, você precisa de duas interfaces, uma para uso interno e outra que você expõe na API pública. (Com o interno possivelmente, mas não necessariamente estendendo o público.) Ou, como outros apontaram, uma superclasse abstrata.

biziclop
fonte
Uma superclasse abstrata pode evitar que seja derivada de tipos fora de seu pacote. Alguém que recebe uma referência desse tipo de superclasse, que confia no autor do pacote, pode ter certeza de que o objeto se comportará conforme reivindicado. Se um pacote tem várias classes que desejam expor alguma funcionalidade comum, mas não se encaixam em uma hierarquia adequada (por exemplo, um implementa as funções X e Y, um Y e Z e um X e Z), seria útil se pudesse expor a funcionalidade usando interfaces, embora ainda prometa que as instâncias referidas pelos tipos de interface seriam "genuínas".
supercat
0

Os métodos protegidos estão sempre acessíveis pela subclasse apenas se a subclasse estender a classe base.

No caso de interface, a subclasse nunca estende a interface. Ele implementa a interface.

Os métodos protegidos são acessíveis via extend e não com implemento .

Aftaab Siddiki
fonte
que diferença qual palavra-chave, não importa.
Alex78191 de
0

As interfaces destinam-se a expor métodos ao mundo exterior . Portanto, esses métodos são públicos por natureza. No entanto, se você deseja introduzir abstração dentro da mesma família de classes , é possível criar outro nível de abstração entre sua interface e a classe de implementação, ou seja, uma classe abstrata. Um exemplo é demonstrado abaixo.

public interface MyInterface {
    public void publicMethod(); // needs to be public
}

public abstract class MyAbstractClass implements MyInterface {
    @Override
    public void publicMethod() {
        protectedMethod(); // you can call protected method here
        // do other stuff
    }
    protected abstract void protectedMethod(); // can be protected
}

public class MyClass extends MyAbstractClass {
    @Override
    protected void protectedMethod() {
        // implement protected method here, without exposing it as public
    }
}
Stefanos Kargas
fonte
2
Mas métodos privados que ninguém verá são permitidos nas interfaces.
Alex78191 de
java tem métodos padrão em interfaces, ou seja, uma interface é uma muleta para contornar a herança múltipla de classes abstratas. Vamos então permitir a herança múltipla de classes abstratas. Os conflitos de métodos padrão não se tornaram um problema.
Alex78191
Você está certo. A partir do Java 9, os métodos privados são permitidos nas interfaces. Eles não podem ser abstratos e são implementados e usados ​​dentro da interface, principalmente por outros métodos padrão ou estáticos (se eles próprios forem estáticos).
Stefanos Kargas
1
Essa resposta simplesmente ignora a pergunta feita: por que as interfaces não podem ter métodos protegidos? Os métodos protegidos ainda "exporiam os métodos ao mundo exterior" , e a alegação de que "esses métodos são públicos por natureza" é simplesmente falsa. Eles são públicos porque a linguagem foi projetada dessa forma, mas poderia ter permitido métodos protegidos em interfaces. O OP está simplesmente perguntando por quê.
skomisa