Uma interface permite definir um contrato para determinados objectos, isto é, uma interface permite que o programador indique um conjunto de métodos que terão de ser respeitados por todas as classes que implementem a interface.
O mecanismo de interfaces encontra-se à parte do sistema normal de herança e de classes do Java, embora exista herança entre interfaces, devido às particularidades das interfaces, não funciona exactamente do mesmo modo. Além disso, as interfaces permite contornar, até certo ponto, a não existência de herança múltipla.
No fundo, uma interface é apenas um conjunto de métodos agrupados logicamente, que garantem ao programador que todas as classes que implementem a interface irão ter esses métodos definidos.
Uma interface apenas pode conter definições de métodos, atributos estáticos e tipos internos1). Por outras palavras, não podem existir atributos de instância, não pode existir código dentro dos métodos, não pode existir nada na interface para o qual seja necessário instanciar a interface. As interfaces não podem ser instanciadas.
Devido à natureza das interfaces, não podem existir elementos privados dentro da interface, isto implica que todos os métodos e atributos estáticos são públicos e a herança entre interfaces, embora possível, apenas passa as definições de métodos.
Uma classe pode implementar várias interfaces, tendo para isso que implementar todos os métodos que as interfaces definem. Se a classe não implementar todos os métodos terá de ser declarada como abstracta e os métodos deverão ser implementados pela primeira classe não abstracta que surja ao descer na hierarquia.
As interfaces surgem por vezes com o papel de marcadores. Estes marcadores são interfaces sem qualquer código, seja referente a definição de métodos ou atributos estáticos, e que são usados para identificar se uma determinada classe é de um determinado tipo. Por exemplo, a interface Serializable, não possui atributos estáticos, declarações de métodos ou tipos internos, é uma interface vazia, mas é usada pelo sistema de serialização. Todos os objectos que queriam ser serializados devem implementar esta interface, apesar dela não obrigar a implementar método algum2).
public interface ComandoUniversal { //Não é colocado modificador de acesso, todos os métodos são públicos void ligar(); void desligar(); void mudarCanal(int canal); void pause(); void start(); void stop(); void semBaterias(); } //Herança entre interfaces: todos os métodos definidos na interface ComandoUniversal são herdados por esta nova interface public interface ComandoUniversal2 extends ComandoUnivesal { int mostrarCanal(); } public class ComandoTelevisao implements ComandoUniversal { //aqui já estão definidos os modificadores de acesso public void ligar() { } public void desligar() { } public void mudarCanal(int canal) { } public void pause() { } public void start() { } public void stop() { } public void semBaterias() { } } public class ComandoBox implements ComandoUniversal2 { //métodos herdados pela interface ComandoUniversal2 public void ligar() { } public void desligar() { } void mudarCanal(int canal) { } void pause() { } public void start() { } public void stop() { } public void semBaterias() { } //método extra definido na interface ComandoUniversal2 public int mostrarCanal() { } } //Esta classe, sem a implementação dos métodos, provocará um erro de compilação. public class ComandoErrado implements ComandoUniversal { //sem qualquer implementação } //Nesta classe faltam dois métodos, logo terá de ser uma classe abstracta e os dois métodos em //falta terão de ser implementados numa sub-classe public class ComandoAbstracto implements ComandoUniversal { public void ligar() { } public void desligar() { } public void mudarCanal(int canal) { } public void pause() { } public void start() { } } //Esta sub-classe implementa os dois métodos em falta na classe mãe. //Devido ao mecanismo de herança, esta classe também implementa a interface ComandoUniversal public class Comando extends ComandoAbstacto { public void stop() { } public void semBaterias() { } }