상속

Life is ninanino·2022년 9월 19일
0

JAVA

목록 보기
10/15

상속, 부모클래스와 자식클래스

프로그래밍에서 상속은 "클래스의 멤버를 물려준다"
물려주는 클래스를 "부모 클래스", 물려받는 클래스를 "자식 클래스"

public class Main {

	public static void main(String[] args) {
		Parent p = new Parent();
		Child c = new Child();
		
		p.print();
		c.print();
	}

}

// Parent 클래스 정의
class Parent {
		
	public int iInt;
	
	public void print() {
		System.out.println("Parent Class");
	}
}

// Child 클래스 정의
class Child extends Parent{

}

extends 구문을 통해 상속을 나타낸다.
클래스를 정의할 때 클래스 이름 옆에 extends구문을 붙여준 후 부모 클래스의 이름을 적어주면
자식 클래스는 부모 클래스를 상속하게 된다
자식 클래스는 부모 클래스의 private 멤버를 제외한 나머지 멤버를 본인의 멤버처럼 사용할 수 있다
Child 클래스 내부에 아무것도 정의되어 있지 않아 이 클래스는 아무 역할도 하지 않는다고 생각할 수 있지만
Child클래스는 Parent 클래스로부터 멤버를 상속 받았으므로 ilnt 변수와 print() 메소드를 Child 클랫의 멤버로 사용할 수 있다.

상속을 사용할 때 다음 내용에 유의해야한다

  • 자식 클래스는 부모 클래스로부터 물려받은 멤버 외에 다른 멤버를 추가로 가질 수 있다
  • 자식 클래스에서 정의된 멤버는 부모클래스 객체에서는 사용할 수 없다
  • 자식 클래스 객체가 생성될 때는 부모클래스의 생성자가 무조건 콜 된다. 콜되는 순서는
    1) 부모클래스 생성자
    2) 자식클래스 생성자 순 이다

접근제한자 : protectd

public - 제한 없음
protected - 자식 클래스에게는 public 그 외에는 private
NOT USE - 같은 패키지에서는 public 그 외에는 private
private - 본인 객체 내에서만 사용 가능

부모 클래스에서 protected로 선언된 멤버는 자식 클래스에서 상속 받아 public처럼 사용할 수 있다
단, 본인 클래스 혹은 자식 클래스 외의 장소에서 사용헐 경우 해당 멤버는 private와 동일하게 동작한다.
private 접근제한자는 본인 객체 내에서만 사용가능한 멤버이므로, 부모 클래스에서 private로 선언된 멤버는 자식 클래스에서도 사용할 수 없다

오버라이딩(overriding)

부모 클래스의 멤버를 자식 클래스에서 재정의하여 사용하는 것을 말한다

public class Main {

	public static void main(String[] args) {
		Parent p = new Parent();
		Child c = new Child();
		
		p.print();
		c.print();
	}

}

// 부모 클래스 정의
class Parent {
		
	public int iInt;
	
	public void print() {
		System.out.println("Parent Class");
	}
}

// 자식 클래스 정의
class Child extends Parent{

	public void print() {
		System.out.println("Child Class");
	}
}

자식 클래스에서 부모 클래스에서 정의된 print 메소드를 다시 정의했다.
부모 클래스의 멤버를 상속 받았지만, 자식 클래스에서 해당 멤버의 내용을 수정했으므로 자식 클래스 객체에서는 바뀐 내용이 적용된다. 단, 부모 클래스에는 전혀 영향을 주지 않는다
이처럼 부모로부터 상속받은 멤버를 자식에서 재정의하는 것을 "오버라이딩"이라고 한다

추상화 & 추상클래스

추상화는 상속에서만 사용될 수 있는 개념이다.
"추상적이다" 라는 뜻은 "구체적이지 않다"라는 말과 일맥상통하다.
즉 추상화랑 구체적으로 무언가를 만드는 것이 아니다. 부모클래스에서 추상적으로 메소드를 만들어 놓으면, 자식 클래스에서 해당 메소드를 다시 구체화 한다

public class Main {
	public static void main(String[] args) {
		
		//Animal animal = new Animal("동물"); 불가능합니다.
		
		Lion lion = new Lion("사자");
		lion.Growl();
		
		Cat cat = new Cat("고양이");
		cat.Growl();
	}
}

abstract class Animal {
	
	String Name;
	
	public Animal(String name) {
		Name = name;
	}
	
	abstract public void Growl(); 
}

class Lion extends Animal {

	public Lion(String name) {
		super(name);
	}

	public void Growl() {		
		System.out.println("어흥");
	}
}

class Cat extends Animal {
	public Cat(String name) {
		super(name);
	}
	
	public void Growl() {		
		System.out.println("야옹");
	}
}

Animal 클래스는 생성자와 Growl 메소드를 가진 클래스인데, Growl 메소드에 abstract가 명시된 메소드를 추상화 메소드라고 하며, 추상화 메소드는 내용을 정의하지 않는다. 추상화 메소드는 상속된 후 자식 클래스에서 내용을 정의하여 사용할 수 있다.
추상화 메소드를 가진 클래스를 추상 클래스라고 하며, 추상 클래스에서도 abstract를 명시해주어야 한다. main메소드에 주석으로 설명되어 있듯이 추상 클래스는 객체화 할 수 없다.
Lion 클래스와 Cat 클래스는 Animal 클래스를 상속받은 자식 클래스다. 부모 클래스인 Animal 클래스에서 Growl 메소드를 정의하지 않았으므로, 자식 클래스인 Lion 클래스와 Cat클래스에서 Growl 메소드를 오버라이딩 해야한다.
오버라이딩을 하지 않으면, Lion 클래스와 Cat 클래스 또한 abstract 클래스가 된다
super는 부모 클래스를 지칭하는 문구이다. super(name)이 Animal(name)과 동일하다

interface

자바에서는 다른 프로그래밍 언어에서 사용할 수 있는 다중 상속 기능을 제한하고있다.
즉 extends 뒤에 작성할 수 있는 클래스는 단 하나만 가능하다. 하지만 상황에 따라 다중 상속이 필요한 경우가 있는데 이럴때 자바에서 interface라는 기능을 통해 다중 상속을 구현할 수 있다.
interface는 추상화 클래스보다 좀 더 추상화된 클래스다.

interface Example {
	public static final int iVariable;
	// int iVariable만 써도 동일함.
	
	abstract public void method();
	// void method()만 써도 동일함.
}

interface는 class와 비슷하다. 하지만 class 대신 interface라는 구문을 사용하여, 멤버 변수를 public static final 형태만 사용할 수 있고 메소드도 abstract public 형태만 가능하다
알맹이는 하나도 없이 뼈대만 세워진 클래스라는 것을 알 수 있다.
public static final과 absract public 은 interface 내에서 생략 가능하다.

public class Main {
	public static void main(String[] args) {
		MP3Player_Ver1 mp3_ver1 = new MP3Player_Ver1();
		mp3_ver1.Play();
		mp3_ver1.Stop();
		//mp3_ver2.Next(); 불가능 합니다.
		//mp3_ver2.Prev(); 불가능 합니다.
		
		MP3Player_Ver2 mp3_ver2 = new MP3Player_Ver2();
		mp3_ver2.Play();
		mp3_ver2.Stop();
		mp3_ver2.Next();
		mp3_ver2.Prev();
	}
}

class MP3Player_Ver1 implements PlayFunction, StopFunction {
	public void Play() {
		System.out.println("Play_Ver1!");
	}

	public void Stop() {
		System.out.println("Stop_Ver1!");
	}
}

class MP3Player_Ver2 implements PlayFunction, StopFunction, NextFunction, PrevFunction {
	public void Play() {
		System.out.println("Play_Ver2!");
	}

	public void Stop() {
		System.out.println("Stop!_Ver2");
	}
	
	public void Next() {
		System.out.println("Next!_Ver2");
	}
	
	public void Prev() {
		System.out.println("Prev!_Ver2");
	}
}

interface PlayFunction {
	abstract public void Play();
}

interface StopFunction {
	abstract public void Stop();	
}

interface NextFunction {
	abstract public void Next();
}

interface PrevFunction {
	abstract public void Prev();
}

interface로부터 상속받을 시 extends를 사용하지 않고 implements를 사용한다
interface에 정의된 메소드는 모두 abstract형이므로 두 메소드를 모두 오버라이딩한다.

interface를 사용하는 방법은 추상 클래스와 크게 다르지 않지만 추상 클래스는 일부 멤버만 추상화 할 수 있지만 1개의 클래스만 상속할 수 있고, interface는 모든 멤버 메소드가 추상 메소드여야 하지만 여러개를 동시에 상속할 수 있다는 차이점을 가지고 있다.
프로그램 구조를 설계할 때 구조 간소화 및 모듈화에 많은 영향을 미치는 요소이다.

출처 : 구름edu

profile
백엔드 프로그래밍을 공부하고 있습니다. AWS, 클라우드 환경에 대해 관심이 많습니다.

0개의 댓글