자바는 다중 상속이 불가능하지만 인터페이스는 다중 상속 가능하다

 

추상 클래스와 메소드

자식 클래스에 반드시 오버라이딩을 해야 사용할 수 있는 메소드이다

추상메소드를 선언하여 자식 클래스에서 상속받아 필요한 부분을 재정의하여 사용한다

abstract class 클래스이름{
      abstract 반환타입 메소드이름();
}

 

 

선언부만 존재하는 추상메소드를 일단 선언

abstract class Time{
	abstract void Am(); //추상메소드의 선언부 (구현부가 없는 메서드이다.)
}

 

자식 클래스에 추상메소드를 오버라이딩 하고 구현부를 작성함으로써 재정의를 한다.

class Room extends Time{ //Time 추상 클래스로부터 직접적으로 상속받음
	public void Am() { //추상메소드 오버라이딩해야 인스턴스 생성가능
		System.out.println("오전 10시 청소 시작"); //재정의 (추상메소드의 구현부)
	}
	public void vacuum() {
		System.out.println("그릇 설거지");
	}
}
public class Polymorphism2 {

	public static void main(String[] args) {
		//추상 클래스는 인스턴스 생성불가
		Room room = new Room(); //오버라이딩 후 인스턴스 생성가능
		room.Am();
		room.vacuum();
	}
}
오전 10시 청소 시작
그릇 설거지

 

추상 클래스의 특징

  • 추상 클래스는 하나 이상의 추상 메소드를 포함하며
  • 추상메소드, 일반메소드 모두 포함시킬 수 있다.
  • 대신 추상 메소드는 구현부가 없는 메소드이며 일반 메소드는 구현부가 있는 메소드이다. 
  • 인터페이스와의 차이점은 미리 구현된 메소드를 가지고 있느냐의 차이
  • 인터페이스와의 공통점은 직접 객체를 생성할 수 없다(new연산자 사용X) 
  • 왜냐면 아직 정의되지 않은 추상메소드가 존재하기 때문이다.

 

 

 

다중상속

자바는 하나의 자식클래스가 여러 부모 클래스를 동시에 상속받는 다중 상속을 지원하지 않는다.

클래스는 단일상속만!!

하지만 다중상속이 불가능하나 아래처럼 다중 상속을 대체할 유연한 상속 구조를 구성할 수 있다.

 

자식 Room 클래스는 Time 추상메소드를 직접적으로 상속 받고있어서 

ParentB 클래스의 메소드를 상속을 못받으니 ParentB 인스턴스를 생성하여 해당 메소드의 기능을 사용한다

package com.example.demo;

//추상클래스와 추상메소드 (다중상속 불가능)
abstract class Time{
	abstract void Am(); //추상메소드의 선언부 (구현부가 없는 메서드이다.)
}

class Room extends Time{ //Time 추상 클래스로부터 직접적으로 상속받음
	public void Am() { //추상메소드 오버라이딩해야 인스턴스 생성가능
		System.out.println("오전 10시 청소 시작"); //재정의 (추상메소드의 구현부)
	}
	public void vacuum() {
		System.out.println("그릇 설거지");
	}
}

class ParentB{
	void methodParentB() {
		System.out.println("메소드 B");
	}
}

public class Polymorphism2 {

	public static void main(String[] args) {
		//추상 클래스는 인스턴스 생성불가
		Room room = new Room();
		room.Am();
		room.vacuum();
		System.out.println();
		
		// 자바는 이미 상속을 받고 있는데 다른 클래스 상속을 받을 수 없다 (다중상속이 불가능)
		// Room 클래스는 이미 Time 추상 클래스를 이미 상속받고 있지만 다른 클래스의 메소드를 사용하고 싶을때  
		ParentB pB = new ParentB(); // 인스턴스 생성하여 메소드 호출하기
		pB.methodParentB();
	}
}
오전 10시 청소 시작
그릇 설거지
메소드 B

 

 

 

 

인터페이스

-인터페이스는 다중상속이 가능하다

클래스를 통한 다중 상속은 메소드 출처의 모호성 등의 여러가지 문제때문에 지원하지 않지만 다중상속의 이점이 크기 때문에 인터페이스를 통해 다중 상속을 지원한다

 

-인터페이스 다른 클래스를 작성할때 기본이 되는 틀을 제공하면서 다른 클래스 사이의 중간 매개 역할까지 담당하는 일종의 추상 클래스를 의미

 

추상클래스 - 추상메소드, 생성자, 필드, 일반 메소드 포함

인터페이스 - 추상메소드, 상수만 포함

 

 

인터페이스 선언 (공통적으로 적용)

접근제어자 interface 인터페이스이름 {
   public static final 타입 상수이름 = 값;
   
   public abstract void 메소드이름();
}

인터페이스의 모든 필드는  public static final

인터페이스의 모든 메소드는 추상 메소드 public abstract 

* 접근 제어자는(public) 자바 컴파일러가 자동으로 추가해줘서 생략해도 기본적으로 적용이 된다.

 

 

이렇게 모든 메소드는 선언만 됐을뿐 어떤 기능을 할지 정의되지 않은 상태이기 때문에 '추상 메소드' 라고 부른다.

그래서 abstract 를 적지 않아도 모두 추상 메소드로 간주된다.

그렇기 때문에 인터페이스는 추상 클래스보다 한단계 더 추상화 된 클래스라고 생각하면된다.

 

 

인터페이스는 직접 인스턴스 생성(new 연산자 사용X)은 못하고 인터페이스에 포함하고 있는 추상 메소드(abstract)를 구현해줄 클래스를 작성해야한다.

class 클래스이름 implements 인터페이스 이름 { }

 

▼ 인터페이스의 예시

//인터페이스
interface Cleaning{
	public abstract void wipe();
}

//인터페이스 상속받는 클래스
class Room implements Cleaning{
	public void wipe(){
    	 System.out.println("바닥 닦기");
    }
}

class Kitchen implements Cleaning{
    public void wipe(){
     System.out.println("냉장고 닦기");
    }
}

public class Poltmorphism03{
	public static void main(String[] args){
    	Room r = new Room();
        Kitchen k = new Kitchen();
        
        r.wipe();
        k.wipe();
    }
}

 

 

 

다중 상속 = 여러 인터페이스를 상속받을 수 있다

class 클래스이름 implements 인터페이스 이름1, 인터페이스 이름2 { }

 

 

 

먼저 클래스를 이용한 인터페이스의 다중 상속의 문제점을 예시를 살펴보자

 

Kitchen, LivingRoom 두개의 클래스가 Time()  클래스를 상속을 받고 Am()메소드를 오버라이딩을 했다

class Time{
	public void Am() {
		System.out.println("오전 청소");
	}
}

class Kitchen extends Time{
	public void Am() {
		System.out.println("오전 10시 청소 시작");
	}
	public void dishWash() {
		System.out.println("그릇 설거지");
	}
}

class LivingRoom extends Time{
	public void Am() {
		System.out.println("오전 8시 시작");
	}
	public void floorClean() {
		System.out.println("빗자루 쓸기");
	}
}

 

 

Person 클래스가 Kitchen,LivingRoom 클래스를 상속을 받을때! 문제가 되는데

class Person extends Kitchen,LivingRoom{}
public class School{
	
	public static void main(String[] args) {
		Person person = new Person();
		person.Am();
        //Kitchen,LivingRoom 둘 중 어떤 Am() 메소드인지 구분못함 = 이런 이유로 자바에서는 다중 상속을 지원하지 않는다.
	}
}

 

 

▼ 전체코드

//자바가 다중 상속을 지원하지 않는 이유
class Time{
	public void Am() {
		System.out.println("오전 청소");
	}
}

class Kitchen extends Time{
	public void Am() {
		System.out.println("오전 10시 청소 시작");
	}
	public void dishWash() {
		System.out.println("그릇 설거지");
	}
}

class LivingRoom extends Time{
	public void Am() {
		System.out.println("오전 8시 시작");
	}
	public void floorClean() {
		System.out.println("빗자루 쓸기");
	}
}

// 두개의 클래스를 동시에 상속받는다면?
class Person extends Kitchen,LivingRoom{}

public class School{
	
	public static void main(String[] args) {
		Person person = new Person();
		person.Am();//Kitchen,LivingRoom 둘 중 어떤 Am() 메소드인지 구분못함 = 이런 이유로 자바에서는 다중 상속을 지원하지 않는다.
	}
}

 

Person person = new Person();

person.Am() 

 

Am() 메소드를 호출했을때 Am() 메소드는 어떤 클래스(Kitchen, LivingRoom)에서 상속받은 메소드인지 구분을 못하는 모호성을 가지게 돼서 클래스를 이용한 다중상속을 지원하지 않는다.

이럴때 인터페이스를 사용하여 다중상속을 한다.

 

 

 

▼ 인터페이스의 다중 상속 예시

 

Person, Person2 클래스는 Kitchen, LivingRoom 두개의 인터페이스를 다중 상속받아 구현하고 있는 코드

 

Time 인터페이스를 상속하는 Kitchen, LivingRoom 두개의 인터페이스를

class Person implements Kitchen,LivingRoom {}

class Person2 implements Kitchen,LivingRoom {}

Person, Person2 클래스가 상속받아 오버라이딩(재정의)를 해준다

package com.example.demo;

//인터페이스 (다중상속)
interface Time{
	public abstract void Am();
}

interface Kitchen extends Time{
	public abstract void Am();
	public abstract void dishWash();
}

interface LivingRoom extends Time{
	public abstract void Am();
	public abstract void floorClean();
}

//두개의 인터페이스(Kitchen,LivingRoom) 다중 상속
class Person implements Kitchen,LivingRoom{  //class 클래스 이름 implements 인스턴스 이름
	public void Am() {			// 오버라이딩
		System.out.println("오전 10시 시작");
	}
	public void dishWash() {	// 오버라이딩
		System.out.println("그릇 설거지");
	}
	
	public void floorClean() {	// 오버라이딩
		System.out.println("거실 청소기 돌리기");
	}
}

class Person2 implements Kitchen,LivingRoom{
	public void Am() {				// 오버라이딩
		System.out.println("오전 9시 시작");
	}
	public void dishWash() {		// 오버라이딩
		System.out.println("설거지 물기 닦기");
	}
	
	public void floorClean() {		// 오버라이딩
		System.out.println("방 청소기 돌리기");
	}
}

public class Inferface {

	public static void main(String[] args) {
		Person p1 = new Person();
		Person2 p2 = new Person2();
		
		p1.Am();
		p1.dishWash();
		p1.floorClean();
		
		System.out.println();
		
		p2.Am();
		p2.dishWash();
		p2.floorClean();
	}
}
오전 10시 시작
그릇 설거지
거실 청소기 돌리기

오전 9시 시작
설거지 물기 닦기
방 청소기 돌리기

 

따라서 인터페이스는 구현된 메소드가 없기 때문에 다중상속이 가능하다

반대로 추상클래스는 이미 구현된 메소드가 있기때문에 다중상속이 불가능하

 

 


  • 이렇게 인터페이스와 추상클래스를 미리 선언해두면 개발시 기능 구현에만 집중할 수 있어 개발자가 비즈니스 로직에 집중할 수 있다는 장점이있다.
  • 공통의 인터페이스와 추상클래스를 선언해두면 선언과 구현을 구분할 수 있다.
  • 인터페이스를 선언할 때 공통적인 기능을 미리 구현해두면 좋다
  • 미리 구현해두면 좋은 기능은 일반 메서드를 생성하는데 추상클래스를 이용하고
  • 그렇지 않은 메서드는 추상메서드에 남겨둔다.

 

 

 

 

 

 extends , implements 의 차이

 

둘 다 부모의 상속을 받지만

  • extends는 오버라이딩(재정의)를 하지않아도 부모에 구현된 메소드나 변수까지 사용가능
    • interface가 interface 상속을 받을때
    • class가 class 상속을 받을때 
    • extends는 단일 상속만 가능
  • implemets 는 부모의 메소드를 오버라이딩(재정의) 해야한다
    • class가 interface 상속을 받을때
    •  다중 상속도 가능 > implemts 인터페이스 이름1, 인터페이스 이름2 {}
반응형
LIST

'공부' 카테고리의 다른 글

메이븐 프로젝트 설정, JPA 설정  (0) 2023.07.31
클래스 멤버  (0) 2023.07.20
다형성  (0) 2023.06.22
접근 제한자 | 지역변수, 전역변수와 static  (0) 2023.06.22
생성자  (0) 2023.06.20

+ Recent posts