부모 클래스는 제공하지만, 실제 생성되면 안되는 클래스를 추상 클래스라고 한다. 추상 클래스는 이름 그대로 추상적인 개념을 제공하는 클래스이다. 따라서 실체인 인스턴스가 존재하지 않는다. 대신에 상속을 목적으로 사용되고, 부모 클래스 역할을 담당한다.
abstract class AbstractAnimal {}
추상 클래스는 클래스를 선언할 때 앞에 추상이라는 의미의 abstract키워드를 붙여주면 된다. 추상 클래스는 기존 클래스와 완전히 같지만 new AbstractAnimal()과 같이 직접 인스턴스를 생성하지 못하는 제약이 추가 된것이다.
부모 클래스를 상속 받는 자식 클래스가 반드시 오버라이딩 해야하는 메서드를 부모 클래스에 정의할 수 있다. 이를 추상 메서드라고 하는데 이름 그대로 추상적인 개념을 제공하는 메서드로, 실체가 존재하지 않고 메서드 바디가 없다.
public abstract void sound();
abstract키워드를 붙여주면 된다.public abstract class AbstractAnimal {
public abstract void sound();
public void move() {
System.out.println("동물이 움직입니다.");
}
}
클래스 안에 abstract가 붙은 추상 메서드가 있으니깐 반드시 추상 클래스로 명시해줘야 한다. 그리고 당연히 sound()는 abstract가 붙은 추상 메서드이므로 자식이 반드시 오버라이딩 해야 한다. move()는 추상 메서드가 아니므로 오버라이딩 해줄 필요 없다.
public class Dog extends AbstractAnimal {
@Override
public void sound() {
System.out.println("나는 강아지다 멍멍");
}
}
public class Cat extends AbstractAnimal {
@Override
public void sound() {
System.out.println("나는 고양이다 냐옹");
}
}
public class AbstractMain {
public static void main(String[] args) {
// 추상 클래스 생성 불가
// AbstractAnimal animal = new AbstractAnimal();
Dog dog = new Dog();
Cat cat = new Cat();
cat.sound();
cat.move();
soundAnimal(cat);
soundAnimal(dog);
}
// 동물이 추가되어도 변하지 않는 코드
private static void soundAnimal(AbstractAnimal animal) {
System.out.println("동물 소리 테스트 시작");
animal.sound();
System.out.println("동물 소리 테스트 종료");
}
}
모든 메서드가 추상 메서드인 추상 클래스를 의미한다.
public abstract class AbstractAnimal {
public abstract void sound();
public abstract void move();
}
public class Dog extends AbstractAnimal {
@Override
public void sound() {
System.out.println("나는 강아지다 멍멍");
}
@Override
public void move() {
System.out.println("나는 강아지다 움직여라");
}
}
public abstract class AbstractAnimal {
public abstract void sound();
public abstract void move();
}
위 코드를
public interface InterfaceAnimal {
public abstract void sound();
public abstract void move();
}
여기서 public abstract는 생략해도 된다.
public interface InterfaceAnimal {
void sound();
void move();
}
인터페이스는 순수 추상클래스와 같지만, 약간의 편의 기능이 추가된다.
public, abstract이다.public abstract를 생략할 수 있다. 생략이 권장된다.public interface InterfaceAnimal {
public static final double MY_PI = 3.14;
}
인터페이스에서 멤버 변수는 public, static, final이 모두 포함되었다고 간주된다. final은 변수의 값을 한 번 설정하면 수정할 수 없다는 뜻이다.
자바에서 static final을 사용해 정적이면서 고칠 수 없는 변수를 상수라 하고, 관례상 상수는 대문자에 언더스코어(_)로 구분한다.
public interface InterfaceAnimal {
double MY_PI = 3.14;
}

클래스 상속 관계는 UML에서 실선을 사용하지만, 인터페이스 상속 관계는 UML에서 점선을 사용한다.
public interface InterfaceAnimal {
void sound();
void main();
}
그럼 이렇게 추상 클래스를 편하게 해주는 인터페이스가 있다고 하면 상속을 받을 때는 추상 클래스에선 extends를 사용하지만 인터페이스에선 implements를 사용한다.
public class Dog implements InterfaceAnimal {
@Override
public void sound() {
System.out.println("나는 강아지다 멍멍");
}
@Override
public void move() {
System.out.println("나는 강아지다 움직여라");
}
}