Qual a diferença entre Classe Abstrata e Interface em Java?

Uma classe abstrata é basicamente um conjunto de métodos e/ou variáveis que podem ser usados para criar outras classes.

Quando falamos de algo abstrato, estamos falando sobre algo que não é concreto nem real, que não tem existência como objeto, como coisa ou como realidade palpável, algo irreal.

Algo abstrato também pode ser definido como algo que possui um alto grau de generalização. E algo genérico podemos definir como algo geral, indeterminado ou vago.

E isso tem tudo a ver com o propósito das classes abstratas.

Imagine que você precise ter várias classes que representam diferentes tipos de carros no seu sistema.

Essas classes terão coisas em comum assim como terão coisas incomum.

Então podemos criar uma classe chamada Carro, observe que carro é algo extremamente genérico, afinal, de que carro estamos falando?


public class Carro {
	
}

Sabendo disso, permitir a criação de um objeto a partir da classe carro não seria uma boa prático, no quesito organização. Nós precisamos saber se esse carro é uma Ferrari ou um Fusca, por exemplo.

Então, para resolver esse problema nós transformamos a classe Carro em uma classe abstrata.


public abstract class Carro {
	
}

Agora, depois dessa mudança, não será mais possível criar um objeto a partir da classe Carro.

Mas podemos criar uma classe Fusca e uma classe Ferrari e fazer com que essas classes recebam por herança a classe Carro.


public class Fusca extends Carro{

}

Agora podemos criar um método chamado passarMarcha na classe Carro e implementá-lo.


public abstract class Carro {
	
	public void passarMarcha() {
		System.out.println("Passando marcha manual.");
	}
	
}

Eu não entendo quase nada sobre carros mas sei que existem carros com câmbio automático ou câmbio manual, nesse exemplo vamos supor que a Ferrari tem um câmbio automático, e o Fusca… você já sabe né, rsrs.

Sabendo disso, vamos fazer uma reflexão, será mesmo que criar um método passarMarcha e implementá-lo é mesmo uma boa ideia?

Não é, para isso podemos criar um método passarMarcha na classe carro usando a palavra reservada abstract, assim nasce um método abstrato.


public abstract class Carro {
	
	// Agora que esse método é abstrato já não podemos implementá-lo.
	public abstract void passarMarcha();
	
}

Os métodos abstratos servem para definir o que as subclasses devem ter, ou seja, que métodos as subclasses devem ter mas não define o que esses métodos devem fazer.

A implementação dos métodos abstratos é responsabilidade das subclasses.

As subclasses são obrigadas a implementar os métodos abstratos da superclasse.


public class Fusca extends Carro{

	@Override
	public void passarMarcha() {
		System.out.println("Passando marcha manual.");		
	}

}

Se eu pudesse te dar um único motivo para criar uma classe abstrata seria que as classes abstratas te ajudam a organizar o seu sistema, elas ajudam a criar classes que possuem características em comum.

Se as classes comuns são moldes para objetos, as classes abstratas são moldes para outras classes.

A classe comum define o que um objeto tem, a classe abstrata define o que a subclasse tem e/ou o que a subclasse é obrigada a ter.

Se você cria um método não abstrato em uma classe abstrata, esse método já implementado é passado por herança para as subclasses. Todas as subclasses já terão esse método, todas terão esse mesmo comportamento.

Se você cria um método abstrato, todas as subclasses serão forçadas a implementa-lo, ainda que todas implementem esse método de uma forma diferente todas o terão. Isso deixa o seu código organizado. Organização é um dos principais motivo para se criar uma classe abstrata.

Para criar uma classe abstrata só basta incluir a palavra reservada abstract a classe.

Entenda que, se uma classe tem um método abstract, então a própria classe deve ser abstract.

Classes abstratas não possuem restrições em modificadores de acesso, enquanto que, em uma interface, todos são públicos por padrão.

Podemos ter blocos de inicialização de instância e blocos de inicialização estáticos em uma classe abstrata, enquanto nunca podemos tê-los na interface.

Classes abstratas também podem ter construtores que serão executados durante a instanciação do objeto filho.

O Java 8 introduziu interfaces funcionais, uma interface com restrição de não mais que um método abstrato declarado.

Qualquer interface com um único método abstrato diferente dos métodos estáticos e padrão é considerada uma interface funcional.

Podemos usar esse recurso para restringir o número de métodos abstratos a serem declarados.

Enquanto em classes abstratas, nunca podemos ter essa restrição no número de declaração de métodos abstratos.

Uma interface não pode ter métodos já implementados (métodos com as chaves), no lugar das chaves é colocado o ponto e vírgula e a classe que implementa a interface é que tem a responsabilidade de implementá-los.

Já nas classes abstratas podemos ter métodos já implementados e métodos não implementados (abstratos) trabalhando juntos.

Para criar uma interface usamos a palavra reservada interface.


public interface CarStuff {

}

Todos os métodos em uma interface já são abstratos, com a interface você não tem nem a possibilidade de criar métodos não abstratos, ainda que a palavra abstract não seja usada, todos os métodos de uma interface já são abstratos.

E ai está uma das principais diferenças entre classes abstratas e interfaces. Com classes abstratas você pode ter métodos abstratos ou não, já na interface você só tem métodos abstratos.

Ou seja, todos os métodos em interfaces não possuem implementação.


public interface CarStuff {

	void correr();
	
}

Para usar uma interface é preciso a palavra reservada implements.


public class Fusca implements CarStuff{

	@Override
	public void correr() {
		System.out.println("Correndo.");
	}

}

Observe que a palavra “implements” faz todo o sentido, porque todos o métodos da interface serão obrigatóriamente implementados, pois todos já são por padrão abstratos.