안녕하세요. J4J입니다.
이번 포스팅은 추상 클래스와 인터페이스에 대해 적어보는 시간을 가져보려고 합니다.
사용 이유
추상 클래스와 인터페이스를 사용하는 이유는 클래스를 작성할 때 사용 용도에 맞는 필수적인 요소들을 포함시키기 위해 사용합니다.
예를 들어 핸드폰을 만들 때 핸드폰에는 필수적으로 알람 소리, 벨소리 등이 포함되는데 알람 소리와 벨소리들에 대해 정의하는 것을 포함시키지 않고 핸드폰 제작하는 것을 방지하기 위해 사용합니다.
이처럼 프로그래밍을 할 때도 A라는 클래스를 만들 때 클래스에 필요한 메서드들을 사전에 모두 정의하여 A클래스를 작성할 때 필수적인 메서드들 모두 정의할 수 있도록 도와줍니다.
추상 클래스
추상 클래스는 일반 클래스와 달리 abstract라는 키워드를 이용하여 클래스를 작성합니다.
그리고 메서드를 작성할 때 선언과 동시에 내용물을 정의하는 일반 클래스들과는 달리 선언까지만 한 추상 메서드들을 포함하고 있습니다.
추상 클래스는 아래 코드와 같이 작성할 수 있습니다.
package abstract_interface;
public abstract class AbstractPhone {
int intVal; // 일반 변수
public void alarm() { // 일반 메서드
System.out.println("띠리리리리리링");
}
public abstract void bell(); // 추상 메서드
}
위의 코드처럼 일반 클래스와 같이 변수를 선언해 둘 수 있고 메서드도 정의할 수 있지만 메서드 앞에 abstract라는 키워드를 붙인 추상 메서드를 포함시킬 수도 있습니다.
그럼 이렇게 선언된 추상 클래스를 어떻게 사용할까요?
다음 코드를 봅시다.
package abstract_interface;
public class Phone1 extends AbstractPhone {
@Override
public void bell() {
System.out.println("또로로로로로로롱");
}
public static void main(String[] args) {
Phone1 phone1 = new Phone1();
phone1.alarm(); // 띠리리리리리링
phone1.bell(); // 또로로로로로로롱
phone1.intVal = 32;
System.out.println(phone1.intVal); // 32
}
}
추상 클래스는 상속에 사용되는 extends라는 키워드를 통해 사용될 수 있습니다.
일반 클래스에서는 메서드들이 모두 정의가 되어야 하기 때문에 선언만 되어 있던 bell() 메서드를 정의해야만 하고 이미 정의되어 있던 alarm() 메서드는 정의하지 않고 사용할 수 있습니다.
또한 일반 클래스와 동일하게 변수도 값을 넣은 뒤 사용할 수 있습니다. (abstract 키워드는 변수에 사용 못합니다.)
인터페이스
인터페이스도 추상 클래스와 유사하지만 추상 클래스와 달리 메서드를 정의하지 못하기 때문에 추상 메서드만 사용할 수 있습니다.
즉, 모든 메서드들이 선언만 되어야 한다는 의미입니다.
아래 코드를 확인해봅시다.
package abstract_interface;
public interface InterfacePhone {
int intVal = 32; // public static final int intVal = 32, 상수
public void alarm(); // 추상 메서드
public abstract void bell(); // 추상 메서드
}
위의 코드처럼 abstract class대신에 interface라는 키워드를 이용하여 인터페이스를 작성할 수 있습니다.
그리고 말씀드린 것처럼 메서드들이 모두 추상 메서드이기 때문에 abstract키워드를 사용 안 해도 추상 메서드로 인식합니다.
또한 상수값만 사용이 가능하며 public static final을 생략하고 작성해도 자동으로 입력이 됩니다.
이렇게 정의된 인터페이스를 사용해봅시다.
package abstract_interface;
public class Phone2 implements InterfacePhone {
@Override
public void alarm() {
System.out.println("띠라띠라띠라디라띠라");
}
@Override
public void bell() {
System.out.println("또로로로멘또롱");
}
public static void main(String[] args) {
Phone2 phone2 = new Phone2();
phone2.alarm(); // 띠라띠라띠라디라띠라
phone2.bell(); // 또로로로멘또롱
System.out.println(Phone2.intVal); // 32
}
}
인터페이스는 추상 클래스와 달리 extends를 사용하지 않고 implements라는 키워드를 사용합니다.
인터페이스에 선언된 메서드들을 모두 정의해줘야 메서드들을 사용할 수 있고 상수는 static으로 선언된 상수값이기 때문에 phone2라는 인스턴스 대신에 클래스 자체인 Phone2를 통해 사용될 수 있습니다.
구분 이유
코드들을 확인해보면 추상 클래스든 인터페이스든 사용 방법은 비슷하다는 것을 확인하실 수 있을 겁니다.
그럼 이 둘을 구분한 이유가 무엇일까요?
그 이유는 다중 상속 때문입니다.
추상 클래스는 단일 상속만 가능, 인터페이스는 다중 상속까지 가능. 정말 쉽죠?
말 그대로 추상 클래스는 하나의 부모만 상속을 받을 수가 있는데 그 이유를 아래 코드로 보여드리겠습니다.
package abstract_interface;
public abstract class AbstractClass1 {
public void output1() {
System.out.println("AbstractClass1의 출력물입니다.");
}
public abstract void output2();
}
package abstract_interface;
public abstract class AbstractClass2 {
public void output1() {
System.out.println("AbstractClass2의 출력물입니다.");
}
public abstract void output2();
}
위의 코드처럼 만약 하나의 클래스가 위에 정의된 두 추상 클래스를 상속받는다고 할 때 output의 결과물은 무엇이 나와야 될까요?
명확하게 무엇이 나와야 되는지 결론을 내릴 수가 없고 이런 일들을 방지하고자 자바에서는 다중 상속을 금지시켰습니다.
하지만 코드를 작성하다 보면 다중 상속이 필요한 데 그럴 때 인터페이스를 사용하게 되는 겁니다.
인터페이스도 우선 코드를 확인해 봅시다.
package abstract_interface;
public interface Interface1 {
public void output1();
public abstract void output2();
}
package abstract_interface;
public interface Interface2 {
public void output1();
public abstract void output2();
}
package abstract_interface;
public class MainClass implements Interface1, Interface2 {
@Override
public void output1() {
System.out.println("output1의 출력물입니다.");
}
@Override
public void output2() {
System.out.println("output2의 출력물입니다.");
}
public static void main(String[] args) {
MainClass mainClass = new MainClass();
mainClass.output1(); // output1의 출력물입니다.
mainClass.output2(); // output2의 출력물입니다.
}
}
이처럼 인터페이스는 똑같은 메서드명을 선언하더라도 정의하지 않았기 때문에 다중 상속을 받더라도 서로 구분될 필요가 없습니다.
추상 클래스가 해주지 못하는 다중 상속을 인터페이스가 해줌으로 써 추상화를 위해 사용된다는 공통점을 가지고 있음에도 불구하고 구분되어 사용이 되는 것입니다.
정리
이상으로 추상 클래스와 인터페이스에 대해 간단하게 알아보는 시간이었습니다.
읽어주셔서 감사합니다.
'Language > Java' 카테고리의 다른 글
[Java] 자바기초 - 객체지향(OOP) - 캡슐화(Encapsulation) (0) | 2020.12.22 |
---|---|
[Java] 자바기초 - 오버라이딩과 오버로딩(overriding/overloading) (0) | 2020.12.21 |
[Java] 자바기초 - 접근 제한자 (0) | 2020.12.16 |
[Java] 자바기초 - 생성자(Constructor) (0) | 2020.12.14 |
[Java] 자바기초 - Wrapper Class (0) | 2020.12.13 |
댓글