추상 메서드(abstract method)
•
추상 메서드는 자식 클래스에서 반드시 오버라이딩해야만 사용할 수 있는 메서드로, 자바에서 추상 메서드를 선언하면 해당 메서드를 포함하는 클래스를 상속받는 자식 클래스가 반드시 해당 추상 메서드를 구현하도록 하기 위함이다.
•
모듈처럼 중복되는 부분이나 공통적인 부분들은 미리 만들어진 것을 사용하고, 이를 받아서 사용하는 쪽에서 필요한 부분만 재정의하여 사용함으로써 생산성을 높이고 배포를 쉽게하기 위해서 사용된다.
•
이런 특성상 추상 메서드는 선언부만 존재하며, 구현부는 작성되면 안된다.
abstract void abstractMethod();
Java
복사
추상 클래스(abstract class)
•
자바에서 하나 이상의 추상 메서드를 포함하는 클래스를 추상 클래스라고 부르며, 다형성을 가지는 메서드 집합을 정의할 수 있도록 해준다.
•
반드시 사용되어야 하는 메서드를 추상 메서드로 선언해 놓아서, 해당 클래스를 상속받는 모든 클래스에서 이 추상 메서드를 반드시 재정의해 사용하도록 만들 수 있다.
abstract class abstractClass {
...
abstract void abstractMethod();
...
}
Java
복사
•
추상 클래스는 정의되지 않은 추상 메서드를 포함하고 있기 때문에, 자기 자신의 인스턴스를 생성할 수 없다. 상속을 통해 자식 클래스를 만들고, 자식 클래스에서 모든 추상 메서드를 오버라이딩하고 나서야 자식 클래스의 인스턴스를 생성할 수 있다.
abstract class Animal { abstract void cry(); }
class Cat extends Animal { void cry() { System.out.println("냐옹냐옹!"); } }
class Dog extends Animal { void cry() { System.out.println("멍멍!"); } }
public class Polymorphism02 {
public static void main(String[] args) {
// Animal a = new Animal(); // 추상 클래스는 인스턴스를 생성할 수 없음.
Cat c = new Cat();
Dog d = new Dog();
c.cry();
d.cry();
}
}
Java
복사
•
자바에서 추상 메서드를 선언하여 사용하는 목적은 상속 받는 클래스에서 반드시 해당 메서드를 구현하도록 하기 위해 사용된다. 만약 이를 일반 메서드로 구현한다면, 자식 클래스에서는 구현을 할 수도 있고 안 할 수도있다.
인터페이스란
•
자식 클래스가 여러 부모 클래스를 상속받아 사용할 수 있다면, 다양한 동작을 수행할 수 있다는 장점을 가질 수 있다. 다중 상속을 할 경우 메서드 출처의 모호성 등 여러 문제로 인해, 자바에서는 클래스를 통한 다중 상속을 허용하지 않는다.
•
자바에서 이러한 이점을 사용하고 싶으면 인터페이스를 통해 다중 상속을 받아 사용하면 된다. 인터페이스란 다른 클래스를 작성할 때 기본 틀을 제공하며 다른 클래스 사이의 중간 매개 역할까지 담당하는 일종의 추상 클래스이다.
•
자바에서 추상 클래스는 추상 메서드와 생성자, 필드, 일반 메서드를 포함할 수 있지만, 인터페이스에서는 오직 추상 메서드와 상수만 포함할 수 있다.
인터페이스의 선언
•
인터페이스는 interface 키워드를 접근 제어자와 함께 사용하여 선언할 수 있다.
private interface Shape {
public static final origin = 0;
...
public abstract int getArea(int width, int height);
...
}
Java
복사
•
인터페이스에서는 클래스와 달리 모든 필드를 public static final로 선언해야하며, 모든 메서드를 public abstract로 선언해야한다.
인터페이스의 구현
•
인터페이스는 추상 클래스와 마찬가지로 자신이 직접 인스턴스를 생성할 수 없고, 아래처럼 인터페이스를 구현하는 구현 클래스를 작성해야한다.
class Square implements Shape {
...
public int getArea(int width, int height) {
return width * height;
}
}
Java
복사
•
구현 클래스는 인터페이스의 모든 추상 메서드를 구현해야하고, 추상 메서드를 구현하지 않으려면 abstract
키워드를 사용하여 추상 클래스로 선언해야한다.
interface Animal { public abstract void cry(); }
class Cat implements Animal {
public void cry() {
System.out.println("냐옹냐옹!");
}
}
class Dog implements Animal {
public void cry() {
System.out.println("멍멍!");
}
}
public class Polymorphism03 {
public static void main(String[] args) {
Cat c = new Cat();
Dog d = new Dog();
c.cry(); // "냐옹냐옹!"
d.cry(); // "멍멍!"
}
}
Java
복사
인터페이스를 활용한 다중 상속
interface Animal { public abstract void cry(); }
interface Pet { public abstract void play(); }
class Cat implements Animal, Pet {
public void cry() {
System.out.println("냐옹냐옹!");
}
public void play() {
System.out.println("쥐 잡기 놀이하자~!");
}
}
class Dog implements Animal, Pet {
public void cry() {
System.out.println("멍멍!");
}
public void play() {
System.out.println("산책가자~!");
}
}
public class Polymorphism04 {
public static void main(String[] args) {
Cat c = new Cat();
Dog d = new Dog();
c.cry(); // 냐옹냐옹!
c.play(); // 나비야~ 쥐 잡기 놀이하자~!
d.cry(); // 멍멍!
d.play(); // 바둑아~ 산책가자~!
}
}
Java
복사
•
이처럼 두 개 이상의 인터페이스를 다중 상속하여 구현 클래스를 작성할 수 있다.
인터페이스의 장점
•
다중 상속을 받는 클래스를 구현할 수 있다.
•
일관되고 정형화된 개발을 위한 표준화가 가능하여 대규모 프로젝트 개발 시 효율적으로 작업할 수 있다.
•
클래스의 작성과 인터페이스의 구현을 동시에 진행할 수 있어 개발 시간을 단축할 수 있다.
•
클래스와 클래스 간의 관계를 인터페이스로 연결하면, 클래스마다 독립적인 프로그래밍이 가능해진다.
디폴트 메서드(default method)
•
Java 8부터는 인터페이스에도 디폴트 메서드를 제공하여 인스턴스 메서드를 구현 형태로 제공할 수 있게 되었다.
public interface Vehicle {
default void print() {
System.out.println("I am a vehicle!");
}
}
Java
복사
•
이런 디폴트 메서드의 사용 방법은 3가지가 있다.
◦
구현 없이 인터페이스의 디폴트 메서드를 그대로 사용하는 방법
◦
디폴트 메서드를 override하는 방법
◦
인터페이스를 상속 받은 후 디폴트 메서드를 추상 메서드로 만들어 추상 클래스를 생성하는 방법
•
인터페이스에 디폴트 메서드를 추가하면, 다중 상속할 때 메서드의 이름이 같을 때 다음과 같이 모호함 문제가 발생한다.
public interface Vehicle {
default void print() {
System.out.println("I am a vehicle!");
}
}
public interface FourWheeler {
default void print() {
System.out.println("I am a four wheeler!");
}
}
public class Car implements Vehicle, FourWheeler {
}
Java
복사
// error 메세지
Duplicate default methods named print with the parameters () and () are inherited from the types Vehicle and FourWheeler
Java
복사
•
이와 같은 모호함 문제를 해결하기 위해서는 2가지 방법이 있다.
◦
구현 메서드를 통해 override 하는 방법
public class Car implements Vehicle, FourWheeler {
public void print() {
System.out.println("I am a four wheeler car vehicle!");
}
}
Java
복사
◦
사용할 부모 인터페이스를 지정하여 사용하는 방법
public class Car implements Vehicle, FourWheeler {
public void print() {
Vehicle.super.print();
}
}
Java
복사