Existe mais em uma interface do que ter os métodos corretos


159

Então, digamos que eu tenho essa interface:

public interface IBox
{
   public void setSize(int size);
   public int getSize();
   public int getArea();
  //...and so on
}

E eu tenho uma classe que a implementa:

public class Rectangle implements IBox
{
   private int size;
   //Methods here
}

Se eu quisesse usar a interface IBox, não posso realmente criar uma instância dela, da maneira:

public static void main(String args[])
{
    Ibox myBox=new Ibox();
}

certo? Então, eu realmente teria que fazer isso:

public static void main(String args[])
{
    Rectangle myBox=new Rectangle();
}

Se isso for verdade, o único objetivo das interfaces é garantir que a classe que implementa uma interface tenha os métodos corretos, conforme descrito por uma interface? Ou existe algum outro uso de interfaces?


2
Lembre-se, as interfaces não são específicas para Java. Todas as linguagens OOP as possuem de uma forma ou de outra, embora nem sempre sejam explicitamente definidas como Java.
Herms

2
Tecnicamente, todas as linguagens OOP fortemente tipadas as possuem de uma forma ou de outra. Idiomas sem tipo ou com tipo de pato não têm um conceito semelhante.
Jared

1
@ Jared Você não está confundindo digitação forte com digitação estática e "não digitado" com digitado dinamicamente?
eljenso

O polimorfismo também pode ser realizado através de interfaces. Confira a última seção desta página codenuggets.com/2014/06/20/java-interface
Jeff

Respostas:


143

As interfaces são uma maneira de tornar seu código mais flexível. O que você faz é o seguinte:

Ibox myBox=new Rectangle();

Posteriormente, se você decidir usar um tipo diferente de caixa (talvez exista outra biblioteca, com um tipo melhor de caixa), mude seu código para:

Ibox myBox=new OtherKindOfBox();

Depois de se acostumar, você descobrirá que é uma ótima maneira (realmente essencial) de trabalhar.

Outro motivo é, por exemplo, se você deseja criar uma lista de caixas e executar alguma operação em cada uma, mas deseja que a lista contenha diferentes tipos de caixas. Em cada caixa, você pode fazer:

myBox.close()

(supondo que o IBox tenha um método close ()) mesmo que a classe real de myBox mude dependendo de qual caixa você está na iteração.


54
Não há nada nesta resposta que seja exclusivo para interfaces Java . O mesmo se aplica igualmente às classes abstratas, ou mesmo às concretas. Eu esperaria uma boa resposta mencionar a capacidade de implementar várias interfaces e quando / por que isso seria útil.
Rogério

16
Como isso foi selecionado como resposta? É uma breve descrição do motivo pelo qual o polimorfismo é útil, mas como o pôster acima disse, eu esperaria uma explicação melhor de várias interfaces e ainda mais importante quando for apropriado usar uma interface versus uma classe abstrata.
trevorkavanaugh

2
Isso tem muito pouco a ver com a explicação de interfaces e tudo a ver com o básico do polimorfismo.
A-Developer-Has-No-Name

123

O que torna as interfaces úteis não é o fato de que "você pode mudar de idéia e usar uma implementação diferente posteriormente e só precisa mudar o local onde o objeto é criado". Isso não é problema.

O ponto real já está no nome: eles definem uma interface que qualquer pessoa pode implementar para usar todo o código que opera nessa interface. O melhor exemplo é o java.util.Collectionsque fornece todos os tipos de métodos úteis que operam exclusivamente em interfaces, como sort()ou reverse()para List. O ponto aqui é que esse código agora pode ser usado para classificar ou reverter qualquer classe que implemente as Listinterfaces - não apenas ArrayListe LinkedList, mas também as classes que você escreve, que podem ser implementadas de uma maneira que as pessoas que escreveram java.util.Collectionsnunca imaginaram.

Da mesma forma, você pode escrever um código que opere em interfaces conhecidas ou interfaces definidas, e outras pessoas podem usar seu código sem precisar solicitar que você ofereça suporte às classes.

Outro uso comum de interfaces é para retornos de chamada. Por exemplo, java.swing.table.TableCellRenderer , que permite influenciar como uma tabela Swing exibe os dados em uma determinada coluna. Você implementa essa interface, transmite uma instância para JTablee, em algum momento durante a renderização da tabela, seu código será chamado para executar suas tarefas.


9
Essa é uma resposta muito bom, eu gosto quando você deu exemplos de classes de pacotes java ...
Owais Qureshi

1
Gosteiyou can write code that operates on well-known interfaces, or interfaces you define
Manish Kumar 08/02

Espere um momento ... O que torna as interfaces úteis não é [a capacidade de usar qualquer implementação que você gosta], mas sim [a capacidade de usar qualquer implementação que você gosta]? Mencionar o caso oposto é um bom argumento.
Powerslave

4
@Powerslave: parafraseando-o mais como O que torna as interfaces úteis não é [a capacidade de escrever código onde você precisa alterar apenas uma linha ao alterar a imposição], mas sim [a capacidade de escrever código onde você nem especifica uma implementação em tudo].
Michael Borgwardt

@MichaelBorgwardt Isso parece muito melhor. :) Obrigado por esclarecer!
Powerslave

119

Um dos muitos usos que li é onde é difícil sem várias interfaces de herança usando Java:

class Animal
{
void walk() { } 
....
.... //other methods and finally
void chew() { } //concentrate on this
} 

Agora, imagine um caso em que:

class Reptile extends Animal 
{ 
//reptile specific code here
} //not a problem here

mas,

class Bird extends Animal
{
...... //other Bird specific code
} //now Birds cannot chew so this would a problem in the sense Bird classes can also call chew() method which is unwanted

Um design melhor seria:

class Animal
{
void walk() { } 
....
.... //other methods 
} 

Animal não possui o método chew () e, em vez disso, é colocado em uma interface como:

interface Chewable {
void chew();
}

e a classe Reptile implementa isso e não o Birds (já que o Birds não pode mastigar):

class Reptile extends Animal implements Chewable { } 

e caso dos Birds simplesmente:

class Bird extends Animal { }

6
@CHEBURASHKA E má nomeação. Se Reptile"mastiga", então não é em si "mastigável". A convenção de (às vezes) nomear interfaces O que é digno de nota deve ser aplicado apenas onde faz todo sentido. Nomear a interface Predatorseria mais apropriado aqui.
Powerslave

6
@ PowerSlave É imho correto, um réptil é "capaz de mastigar" / "mastigável". Um falcão é um predador, mas ainda não é capaz de mastigar ... apenas nitpicking mas "mastigável" podem ser melhor definidos na documentação da interface.
Madmenyo

Soberbo .. Explicado muito bem. Obrigado..!
Gurusinghe

1
Eu não entendo. Tudo parece que as interfaces são uma boa maneira de garantir que você implemente os mesmos métodos em cada classe que a implementa (por exemplo, isso me impede de fazer a escolha estúpida de uma classe Bird com run () e uma classe Dog com runn () - são todos iguais). Mas prestando atenção e fazendo com que minhas aulas tenham os mesmos formatos / estruturas de método, eu não poderia conseguir a mesma coisa? Realmente parece que as interfaces apenas garantem que o programador não esteja sendo esquecido. Além disso, as interfaces parecem não me poupar tempo; Eu ainda preciso definir o método em cada classe que o implementa.
Alex G

@ AlexG - eu disse a um dos muitos usos cara :) Há mais, nós mal arranhamos a superfície para responder à pergunta de uma maneira simples!
peevesy

47

O objetivo das interfaces é o polimorfismo , também conhecido como substituição de tipo . Por exemplo, dado o seguinte método:

public void scale(IBox b, int i) {
   b.setSize(b.getSize() * i);
}

Ao chamar o scalemétodo, você pode fornecer qualquer valor de um tipo que implemente a IBoxinterface. Em outras palavras, se Rectanglee Squareambos implementam IBox, você pode fornecer um Rectangleou um Squareonde quer que IBoxseja esperado.


8
Por que o objetivo do polimorfismo de interfaces é se eu já consigo isso em Java com subclassificação e substituição de método?
284 eljenso

1
É a mesma coisa, exceto que as interfaces devem omitir qualquer implementação. As classes podem, portanto, implementar mais de uma interface.
Apocalisp

4
Ei, eu nunca disse que o Java tinha algum tipo de integridade conceitual. A substituição de tipo é o objetivo de todas as subtipos. O Java tem mais de um mecanismo de subtipagem, nenhum dos quais é particularmente bom.
Apocalisp

1
Eu nunca disse nada sobre integridade conceitual também. Mas vamos seguir em frente. Se você pode dimensionar todo IBox com seu método, não deve ser uma operação declarada no IBox: IBox.scale (int)?
284 eljenso

1
Não queremos acoplar Integer ao IBox, é por isso que não o tornamos um método no Integer. E o número de métodos em uma interface é decidido pela consistência e coesão da abstração que ela expressa, e não pelo quão complicado seria implementá-la. Enfim, obrigado por suas respostas Apo.
284 eljenso

33

As interfaces permitem que as linguagens estaticamente digitadas suportem o polimorfismo. Um purista orientado a objetos insistiria que uma linguagem deveria fornecer herança, encapsulamento, modularidade e polimorfismo, a fim de ser uma linguagem orientada a objetos com todos os recursos. Em linguagens de tipo dinâmico - ou tipo pato - (como Smalltalk), o polimorfismo é trivial; no entanto, em linguagens estaticamente tipadas (como Java ou C #), o polimorfismo está longe de ser trivial (na verdade, parece superficialmente estar em desacordo com a noção de digitação forte).

Deixe-me demonstrar:

Em uma linguagem de tipo dinâmico (ou tipo pato) (como Smalltalk), todas as variáveis ​​são referências a objetos (nada menos e nada mais.) Portanto, no Smalltalk, eu posso fazer isso:

|anAnimal|    
anAnimal := Pig new.
anAnimal makeNoise.

anAnimal := Cow new.
anAnimal makeNoise.

Esse código:

  1. Declara uma variável local chamada anAnimal (observe que NÃO especificamos o TYPE da variável - todas as variáveis ​​são referências a um objeto, nem mais nem menos.)
  2. Cria uma nova instância da classe chamada "Pig"
  3. Atribui essa nova instância do Pig à variável anAnimal.
  4. Envia a mensagem makeNoisepara o porco.
  5. Repete a coisa toda usando uma vaca, mas atribuindo-a à mesma variável exata que o porco.

O mesmo código Java se pareceria com isso (assumindo que Duck e Cow são subclasses de Animal:

Animal anAnimal = new Pig();
duck.makeNoise();

anAnimal = new Cow();
cow.makeNoise();

Tudo bem, até introduzirmos a classe Vegetable. Os vegetais têm o mesmo comportamento do Animal, mas não todos. Por exemplo, animais e vegetais podem crescer, mas claramente os vegetais não fazem barulho e os animais não podem ser colhidos.

No Smalltalk, podemos escrever o seguinte:

|aFarmObject|
aFarmObject := Cow new.
aFarmObject grow.
aFarmObject makeNoise.

aFarmObject := Corn new.
aFarmObject grow.
aFarmObject harvest.

Isso funciona perfeitamente no Smalltalk porque é do tipo pato (se andar como um pato e grasnar como um pato - é um pato.) Nesse caso, quando uma mensagem é enviada para um objeto, é realizada uma pesquisa no a lista de métodos do receptor e, se um método correspondente for encontrado, ele será chamado. Caso contrário, algum tipo de exceção NoSuchMethodError é lançada - mas tudo é feito em tempo de execução.

Mas em Java, uma linguagem de tipo estaticamente, que tipo podemos atribuir à nossa variável? O milho precisa herdar do vegetal, para sustentar o crescimento, mas não pode herdar do animal, porque não faz barulho. A vaca precisa herdar do Animal para apoiar o makeNoise, mas não pode herdar do Vegetable porque não deve implementar a colheita. Parece que precisamos de herança múltipla - a capacidade de herdar de mais de uma classe. Mas isso acaba sendo um recurso de linguagem bastante difícil, devido a todos os casos extremos que aparecem (o que acontece quando mais de uma superclasse paralela implementa o mesmo método ?, etc.)

Junto vem interfaces ...

Se fizermos as classes Animal e Vegetal, com cada Growable implementando, podemos declarar que nossa Vaca é Animal e nosso Milho é Vegetal. Também podemos declarar que tanto os animais quanto os vegetais são cultiváveis. Isso nos permite escrever isso para crescer tudo:

List<Growable> list = new ArrayList<Growable>();
list.add(new Cow());
list.add(new Corn());
list.add(new Pig());

for(Growable g : list) {
   g.grow();
}

E isso nos permite fazer barulhos de animais:

List<Animal> list = new ArrayList<Animal>();
list.add(new Cow());
list.add(new Pig());
for(Animal a : list) {
  a.makeNoise();
}

A vantagem da linguagem do tipo pato é que você obtém um polimorfismo muito bom: tudo o que uma classe precisa fazer para fornecer comportamento é fornecer o método. Desde que todos se saibam bem e enviem apenas mensagens que correspondam a métodos definidos, tudo ficará bem. A desvantagem é que o tipo de erro abaixo não é detectado até o tempo de execução:

|aFarmObject|
aFarmObject := Corn new.
aFarmObject makeNoise. // No compiler error - not checked until runtime.

Linguagens de tipo estático fornecem "programação por contrato" muito melhor, porque elas capturam os dois tipos de erro abaixo em tempo de compilação:

// Compiler error: Corn cannot be cast to Animal.
Animal farmObject = new Corn();  
farmObject makeNoise();

-

// Compiler error: Animal doesn't have the harvest message.
Animal farmObject = new Cow();
farmObject.harvest(); 

Então .... para resumir:

  1. A implementação de interface permite especificar quais tipos de coisas os objetos podem fazer (interação) e a herança de classe permite especificar como as coisas devem ser feitas (implementação).

  2. As interfaces nos oferecem muitos dos benefícios do polimorfismo "verdadeiro", sem sacrificar a verificação do tipo de compilador.


2
Este é o texto da minha resposta para outra pergunta: stackoverflow.com/questions/379282/… . Mas, são respostas relacionadas.
Jared

2
Posso perguntar, então, como uma linguagem do tipo pato distingue entre Animal.water () (que, o fazendeiro puritano costumava dizer que é vazado) e Plant.water (), que ele usa para regar as plantas. A ambiguidade é o inimigo. Qualquer quantidade de verbosidade necessária para superar a ambiguidade é IMO aceitável.
Bill Bill K

1
Sim .. ambiguidade é o nome do jogo com idiomas digitados por pato. Ao trabalhar profissionalmente em uma linguagem de tipo duck, não é incomum ver membros (métodos e variáveis) com nomes com 50 a 100 caracteres.
Jared

1
Outra grande desvantagem das linguagens digitadas por pato é a incapacidade de fazer refatoração programática com base na análise estática - tente pedir uma imagem do Smalltalk para a lista de todos os chamadores do seu método printString ... você obterá a lista de todos os chamadores de TODOS os métodos printString. ...
Jared

... porque o chamador do Automobile # printString não pode ser diferenciado programaticamente do chamador do NearEarthOrbit # printString.
Jared

9

Normalmente, as interfaces definem a interface que você deve usar (como o nome diz ;-)). Amostra


public void foo(List l) {
   ... do something
}

Agora sua função fooaceita ArrayLists,LinkedList s, ... não apenas um tipo.

O mais importante em Java é que você pode implementar várias interfaces, mas só pode estender UMA classe! Amostra:


class Test extends Foo implements Comparable, Serializable, Formattable {
...
}
é possível mas

class Test extends Foo, Bar, Buz {
...
}
não é!

Seu código acima também poderia ser: IBox myBox = new Rectangle();. O importante é agora que myBox contém SOMENTE os métodos / campos da IBox e não os (possivelmente existentes) outros métodos da Rectangle.


1
'List' deveria ser um membro da interface?
Click Upvote

1
List é uma interface na biblioteca de coleções java.
Rmeador 02/02/09

List é uma interface na biblioteca Java padrão ( java.sun.com/javase/6/docs/api/java/util/List.html ). Ele está apenas usando isso para ilustrar seu argumento.
Michael Myers

6

Acho que você entende tudo o que as interfaces fazem, mas ainda não está imaginando as situações em que uma interface é útil.

Se você estiver instanciando, usando e liberando um objeto em um escopo restrito (por exemplo, em uma chamada de método), uma Interface não adiciona nada. Como você observou, a classe concreta é conhecida.

Onde as interfaces são úteis é quando um objeto precisa ser criado em um local e retornado a um chamador que pode não se importar com os detalhes da implementação. Vamos mudar o seu exemplo de IBox para um Shape. Agora podemos ter implementações de Shape como Rectangle, Circle, Triangle, etc. As implementações dos métodos getArea () e getSize () serão completamente diferentes para cada classe concreta.

Agora você pode usar uma fábrica com uma variedade de métodos createShape (params) que retornarão uma Shape apropriada dependendo dos parâmetros passados. Obviamente, a fábrica saberá que tipo de Shape está sendo criado, mas o chamador não terá se preocupar se é um círculo, um quadrado ou assim por diante.

Agora, imagine que você tem uma variedade de operações que precisa executar em suas formas. Talvez você precise classificá-los por área, configurá-los para um novo tamanho e exibi-los em uma interface do usuário. As Formas são criadas pela fábrica e podem ser passadas para as classes Classificador, Sizer e Display com muita facilidade. Se você precisar adicionar uma classe hexagonal em algum momento no futuro, não precisará alterar nada além da fábrica. Sem a interface, adicionar outra forma se torna um processo muito confuso.


6

você poderia fazer

Ibox myBox = new Rectangle();

Dessa forma, você está usando esse objeto como Ibox e não se importa com isso Rectangle.


Isso significa que poderíamos escrever assim ?! > Retângulo inst = novo Retângulo ();
precisa saber é o seguinte

@ Mr.Hyde Se você quiser adicionar mais tarde, Squareterá um problema .... se tentar fazê-lo sem interfaces, não poderá garantir isso Squaree Rectangleterá os mesmos métodos ... isso pode resultar em um pesadelo quando você tiver uma base de código maior ... Lembre-se, as interfaces definem um modelo.
Kolob Canyon

6

POR QUE INTERFACE ??????

Começa com um cachorro. Em particular, um pug .

O pug tem vários comportamentos:

public class Pug { 
private String name;
public Pug(String n) { name = n; } 
public String getName() { return name; }  
public String bark() { return  "Arf!"; } 
public boolean hasCurlyTail() { return true; } }

E você tem um Labrador, que também tem um conjunto de comportamentos.

public class Lab { 
private String name; 
public Lab(String n) { name = n; } 
public String getName() { return name; } 
public String bark() { return "Woof!"; } 
public boolean hasCurlyTail() { return false; } }

Podemos fazer alguns pugs e laboratórios:

Pug pug = new Pug("Spot"); 
Lab lab = new Lab("Fido");

E podemos invocar seus comportamentos:

pug.bark() -> "Arf!" 
lab.bark() -> "Woof!" 
pug.hasCurlyTail() -> true 
lab.hasCurlyTail() -> false 
pug.getName() -> "Spot"

Digamos que eu corro um canil e preciso acompanhar todos os cães que estou abrigando. Eu preciso armazenar meus pugs e labradors em matrizes separadas :

public class Kennel { 
Pug[] pugs = new Pug[10]; 
Lab[] labs = new Lab[10];  
public void addPug(Pug p) { ... } 
public void addLab(Lab l) { ... } 
public void printDogs() { // Display names of all the dogs } }

Mas isso claramente não é o ideal. Se eu também quero guardar alguns poodles , preciso alterar minha definição de Kennel para adicionar um conjunto de poodles. Na verdade, preciso de uma matriz separada para cada tipo de cachorro.

Introspecção: pugs e labradores (e poodles) são tipos de cães e têm o mesmo conjunto de comportamentos. Ou seja, podemos dizer (para os fins deste exemplo) que todos os cães podem latir, ter um nome e podem ou não ter um rabo encaracolado. Podemos usar uma interface para definir o que todos os cães podem fazer, mas deixe que os tipos específicos de cães implementem esses comportamentos específicos. A interface diz "aqui estão as coisas que todos os cães podem fazer", mas não diz como cada comportamento é feito.

public interface Dog 
{
public String bark(); 
public String getName(); 
public boolean hasCurlyTail(); }

Depois, altero levemente as classes Pug e Lab para implementar os comportamentos de cães. Podemos dizer que um Pug é um cachorro e um laboratório é um cachorro.

public class Pug implements Dog {
// the rest is the same as before } 

public class Lab implements Dog { 
// the rest is the same as before 
}

Ainda posso instanciar Pugs e laboratórios como fiz anteriormente, mas agora também tenho uma nova maneira de fazer isso:

Dog d1 = new Pug("Spot"); 
Dog d2 = new Lab("Fido");

Isso diz que d1 não é apenas um cão, é especificamente um Pug. E d2 também é um cão, especificamente um laboratório. Podemos invocar os comportamentos e eles funcionam como antes:

d1.bark() -> "Arf!" 
d2.bark() -> "Woof!" 
d1.hasCurlyTail() -> true 
d2.hasCurlyTail() -> false 
d1.getName() -> "Spot"

Aqui é onde todo o trabalho extra compensa. A classe Kennel se torna muito mais simples. Eu preciso apenas de uma matriz e um método addDog. Ambos irão trabalhar com qualquer objeto que seja um cachorro; isto é, objetos que implementam a interface Dog.

public class Kennel {
Dog[] dogs = new Dog[20]; 
public void addDog(Dog d) { ... } 
public void printDogs() {
// Display names of all the dogs } }

Veja como usá-lo:

Kennel k = new Kennel(); 
Dog d1 = new Pug("Spot"); 
Dog d2 = new Lab("Fido"); 
k.addDog(d1); 
k.addDog(d2); 
k.printDogs();

A última declaração seria exibida: Spot Fido

Uma interface permite especificar um conjunto de comportamentos que todas as classes que implementam a interface compartilharão em comum. Conseqüentemente, podemos definir variáveis ​​e coleções (como matrizes) que não precisam saber com antecedência que tipo de objeto específico elas conterão, apenas que elas conterão objetos que implementam a interface.


@niranjan kurambhatti eu posso fazer todas as classes para estender o cão, mas ainda por que fazer interface?
Jeeva

3

Um ótimo exemplo de como as interfaces são usadas está na estrutura de coleções. Se você escreve uma função que aceita a List, então não importa se o usuário passa um Vectorou um ArrayListou um HashListou o que quer. E você pode passar isso Listpara qualquer função que exija uma interface Collectionou Iterabletambém.

Isso torna as funções Collections.sort(List list)possíveis, independentemente de como isso Listé implementado.


3

Essa é a razão pela qual os Padrões de Fábrica e outros padrões criacionais são tão populares em Java. Você está certo de que, sem eles, o Java não fornece um mecanismo pronto para uso para fácil abstração da instanciação. Ainda assim, você obtém abstração em todos os lugares em que não cria um objeto no seu método, que deve ser a maior parte do seu código.

Como um aparte, geralmente incentivo as pessoas a não seguirem o mecanismo "IRealname" para nomear interfaces. Isso é algo do Windows / COM que coloca um pé no túmulo da notação húngara e realmente não é necessário (Java já é fortemente tipado, e o objetivo de ter interfaces é tê-las o mais amplamente indistinguíveis dos tipos de classe possível).


1
Você está confundindo digitação forte com digitação estática.
223 eljenso

3

Não se esqueça de que, posteriormente, você poderá ter uma classe existente e implementá-laIBox , e ela ficará disponível para todo o seu código de reconhecimento de caixa.

Isso fica um pouco mais claro se as interfaces forem nomeadas como -able . por exemplo

public interface Saveable {
....

public interface Printable {
....

etc. (Os esquemas de nomeação nem sempre funcionam, por exemplo, não tenho certeza se Boxableé apropriado aqui)


3

o único objetivo das interfaces é garantir que a classe que implementa uma interface tenha os métodos corretos, conforme descrito por uma interface? Ou existe algum outro uso de interfaces?

Estou atualizando a resposta com novos recursos da interface, que foram introduzidos no java 8 versão .

Na página de documentação da Oracle no resumo da interface :

Uma declaração de interface pode conter

  1. assinaturas de método
  2. métodos padrão
  3. métodos estáticos
  4. definições constantes.

Os únicos métodos que possuem implementações são métodos padrão e estáticos.

Usos da interface :

  1. Para definir um contrato
  2. Para vincular classes não relacionadas com recursos, por exemplo, as classes que implementam a Serializableinterface podem ou não ter qualquer relação entre elas, exceto a implementação dessa interface
  3. Fornecer implementação intercambiável, por exemplo, padrão de estratégia
  4. Os métodos padrão permitem adicionar novas funcionalidades às interfaces de suas bibliotecas e garantir compatibilidade binária com o código escrito para versões mais antigas dessas interfaces.
  5. Organize métodos auxiliares em suas bibliotecas com métodos estáticos (você pode manter métodos estáticos específicos para uma interface na mesma interface, em vez de em uma classe separada)

Algumas questões relacionadas ao SE relacionadas à diferença entre classe abstrata e interface e casos de uso com exemplos de trabalho:

Qual é a diferença entre uma interface e uma classe abstrata?

Como devo ter explicado a diferença entre uma interface e uma classe abstrata?

Dê uma olhada na página de documentação para entender os novos recursos adicionados no java 8: métodos padrão e métodos estáticos .


Eu removi a tag java-8 porque a pergunta não fazia nada sobre o java-8 (e na verdade foi feita muito tempo antes do java-8). Tags são para perguntas, não para respostas.
Tagir Valeev

2

O objetivo das interfaces é abstração ou dissociação da implementação.

Se você introduzir uma abstração em seu programa, não se importará com as possíveis implementações. Você está interessado no que ele pode fazer e não em como , e você usa um interfacepara expressar isso em Java.


O objetivo de toda a programação estruturada é a abstração. Por que você diria que o objetivo das interfaces é a abstração, já que eu posso conseguir exatamente a mesma coisa usando genéricos e composição de classes?
Apocalisp

1
Se toda a programação estruturada é abstração (sua reivindicação), as interfaces são abstrações nessa abstração.
234 eljenso

1

Se você tiver CardboardBox e HtmlBox (os quais implementam o IBox), poderá passar os dois para qualquer método que aceite um IBox. Mesmo sendo ambos muito diferentes e não totalmente intercambiáveis, os métodos que não se preocupam com "abrir" ou "redimensionar" ainda podem usar suas aulas (talvez porque se preocupem com quantos pixels são necessários para exibir algo na tela).


1

Interfaces onde uma fetature foi adicionada ao java para permitir herança múltipla. Os desenvolvedores de Java, no entanto, perceberam que ter uma herança múltipla era um recurso "perigoso", por isso surgiu a idéia de uma interface.

herança múltipla é perigosa porque você pode ter uma classe como a seguinte:


class Box{
    public int getSize(){
       return 0;
    }
    public int getArea(){
       return 1;
    }

}

class Triangle{
    public int getSize(){
       return 1;
    }
    public int getArea(){
       return 0;
    }

}

class FunckyFigure extends Box, Triable{
   // we do not implement the methods we will used the inherited ones
}

Qual seria o método que deveria ser chamado quando usamos


   FunckyFigure.GetArea(); 

Todos os problemas são resolvidos com interfaces, porque você sabe que pode estender as interfaces e que elas não terão métodos de classificação ... é claro que o compilador é bom e informa se você não implementou um método, mas eu gosto de pensar que é um efeito colateral de uma ideia mais interessante.


Você pode fazer a diferença entre herança múltipla de implementação e herança múltipla de interface em sua resposta, caso contrário, isso fica confuso.
284 eljenso

0

Aqui está o meu entendimento da vantagem da interface. Corrija-me se eu estiver errada. Imagine que estamos desenvolvendo sistema operacional e outra equipe está desenvolvendo os drivers para alguns dispositivos. Por isso, desenvolvemos uma interface StorageDevice. Temos duas implementações (FDD e HDD) fornecidas por outra equipe de desenvolvedores.

Em seguida, temos uma classe OperatingSystem que pode chamar métodos de interface como saveData, apenas passando uma instância da classe implementada na interface StorageDevice.

A vantagem aqui é que não nos importamos com a implementação da interface. A outra equipe fará o trabalho implementando a interface StorageDevice.

package mypack;

interface StorageDevice {
    void saveData (String data);
}


class FDD implements StorageDevice {
    public void saveData (String data) {
        System.out.println("Save to floppy drive! Data: "+data);
    }
}

class HDD implements StorageDevice {
    public void saveData (String data) {
        System.out.println("Save to hard disk drive! Data: "+data);
    }
}

class OperatingSystem {
    public String name;
    StorageDevice[] devices;
    public OperatingSystem(String name, StorageDevice[] devices) {

        this.name = name;
        this.devices = devices.clone();

        System.out.println("Running OS " + this.name);
        System.out.println("List with storage devices available:");
        for (StorageDevice s: devices) {
            System.out.println(s);
        }

    }

    public void saveSomeDataToStorageDevice (StorageDevice storage, String data) {
        storage.saveData(data);
    }
}

public class Main {

    public static void main(String[] args) {

        StorageDevice fdd0 = new FDD();
        StorageDevice hdd0 = new HDD();     
        StorageDevice[] devs = {fdd0, hdd0};        
        OperatingSystem os = new OperatingSystem("Linux", devs);
        os.saveSomeDataToStorageDevice(fdd0, "blah, blah, blah...");    
    }
}

o mesmo pode ser feito com a classe abstrata StorageDevice e as classes FDD e HDD que estendem a classe StorageDevice. mas se usarmos a classe abstrata, não podemos tirar proveito da herança múltipla.
Vladimir Georgiev
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.