상속 01

오늘·2021년 3월 9일
0

Java

목록 보기
16/42

상속의 개념

객체지향 프로그램에서 상속
: 자식이 부모를 선택해 물려받는다
: 프로그램에서는 부모 클래스를 상위 클래스라고 부르기도 하고, 자식 클래스를 하위 클래스 또는 파생 클래스라고 부른다.

상속대상
: 부모의 필드와 메소드


클래스 상속

자식(하위) 클래스 선언시 어떤 부모(상위) 클래스를 상속받을 것인지 결정한다.

선언시 extends+부모 클래스명으로 작성해준다

class 자식클래스 extends 부모클래스 {
	// 필드
    	// 생성자
        // 메소드
}

ex) 
class Child extends Parent{
// 클래스 Child는 상속받는다 Parent를

1. 부모의 필드와 메소드 사용할 수 있다

-Child 클래스를 보면 필드값을 지정 안해줬음에도 age와 name을 사용할 수 있으며, Parent 를 new 해주지 않았음에도 불러올 수 있다.

Child클래스가 Parent를 상속 받았기 때문이다.

class Parent{
	// 필드
	String name;
	int age;
	
	// 메소드
	void cal() {  }
	
	// 생성자
	// 기본 생성자
	Parent(){ }	
	//명시적 생성자
	Parent(String name, int age){
		this.name = name;
		this.age = age;
	}
}

//클래스 child는 parent를 상속받는다
class Child extends Parent{
	void childMethod() {
		// 부모의  필드와 메소드 사용
        	// 변수를 생성해주지 않았음에도 오류없이 사용할 수 있음
		age = 20;
		name = "홍길동";
		cal();
		
		// 객체 생성
		new Parent();
		new Parent("김자바", 20);
		
		// 그냥 일반 객체 생성도 가능
		new Child1();
	}
}

-상속 관계라해도 부모 클래스의 모든 필드와 메소드들을 물려받는 것은 아니다. 부모 클래스가 필드와 메소드에 private 접근 제한을 걸었다면, 그건 상속 대상에서 제외된다


2. 자바에서 다중 상속 x

-부모 클래스를 여기저기서 상속 받는 것은 상관없지만,
하나의 부모 클래스를 받아온 자식 클래스는 또 다른 부모 클래스를 만들 수 없다.
-상속받는 것은 단일 상속

// 가능한 모습
class Child extends A {		}
class Child1 extends B{		}

// 여러 클래스를 부모 클래스로 가져오는 건 불가능 합니다.
class Child2 extends A extends B{ }
class Child3 extends A, B{ }

3.형제 클래스는 서로 연관이 없음

-각자 다른 클래스로 처리된다
-서로 자료를 공유한다던가 그러지 않음


4. 상속을 사용하는 이유

-각 클래스에서 공통인 부분을 부모 클래스에 만들어놓고 사용
: 이미 잘 개발된 클래스를 재사용해 새로운 클래스를 만들기 때문에 코드의 중복을 줄여준다

-> 공통된 부분을 상위(부모)클래스로 만들고 각자 필요한 부분만 자식(하위)클래스에서 작성해 부모를 상속받으면 되는 것

1) 부모 클래스 작성

class P {
	String name;
	String tel;
	
	// 명시적 생성자
	// P p = new P("부모 클래스", "000"); 을 처리하기 위해 만들어줌
	public P(String name, String tel) {
		this.name = name;
		this.tel = tel;
	}
	// 기본 생성자
	public P() {
		System.out.println("이곳은 부모 클래스 부분");
	}
	
	// Getter Setter
	public String getName() { return name; }
	public void setName(String name) { this.name = name; }
	
	public String getTel() { return tel; }
	public void setTel(String tel) { this.tel = tel; }
}

2) 상속을 받는 부분
공통적인 이름과 번호 부분을 부모에 만들어 줬으니
각 클래스에서 필요한 국어, 영어, 토익, 역사 점수만 각자 작성해준다.

class A extends P {
	int kor;
	
	void a() {
		name = "김자바";
		tel = "123";
		kor = 80;
	}
	public int getKor() {return kor;}
	public void setKor(int kor) {this.kor = kor;}
	
	//A클래스의 기본 생성자
	A(){
		System.out.println("이곳은 자식 클래스 A의 기본 생성자 부분");
	}
}

class B extends P {
	int eng;
	
	void b() {
		name = "이자바";
		tel = "234";
		eng = 80;
	}
	public int getEng() {return eng;}
	public void setEng(int eng) {this.eng = eng;}
}

class C extends P {
	int toeic;
	
	void c() {
		name = "정자바";
		tel = "345";
		toeic = 800;
	}
	public int getToeic() {return toeic;}
	public void setToeic(int toeic) {this.toeic = toeic;}
}

class D extends P {
	int history;
	
	void d() {
		name = "최자바";
		tel = "456";
		history = 95;
	}
	public int getHistory() {return history;}
	public void setHistory(int history) {this.history = history;}
}

3) 출력하는 메인 작성하기

public class InherianceEx1{
	public static void main(String[] args) {
		// 부품 설계 후 조립하기
		A a = new A();
		a.a();
		System.out.println(a.getName());
		System.out.println(a.getTel());
		System.out.println(a.getKor());
		System.out.println("---------------------");
		
		B b = new B();
		b.b();
		System.out.println(b.getName());
		System.out.println(b.getTel());
		System.out.println(b.getEng());
		System.out.println("---------------------");
		C c = new C();
		c.c();
		System.out.println(c.getName());
		System.out.println(c.getTel());
		System.out.println(c.getToeic());
		System.out.println("---------------------");
		D d = new D();
		d.d();
		System.out.println(d.getName());
		System.out.println(d.getTel());
		System.out.println(d.getHistory());
		System.out.println("---------------------");
		
		
		// 부모 클래스 객체 생성하기
		P p = new P("부모 클래스", "000");
		System.out.println(p.name);
		System.out.println(p.tel);
		// System.out.println(p.getKor);  //부모 클래스는 자식 클래스를 사용할 수 없음, 호출할 수 없음
		
	}
}

4. 상속 받은 자식 클래스를 부모로 둬도 괜찮음

// 부모 클래스
class Parent{	}

// 자식 클래스
class Child extends Parent{ }

// Parent의 자식 클래스인 Child의 자식 클래스
class Child2 extends Child2{ }

5. 부모 클래스는 자식 클래스에게서 아무것도 가져올 수 없다

-자식 클래스만이 부모 클래스의 것을 가져온다

class Parent1 {
	String name;
	int age;

	Parent1() {
	}

	/*
    	불가능한 부분
	void cal() {
	dept="작곡과";
	}
	*/
}

class Child3 extends Parent1 {
	String dept = "작곡가";
}


부모 생성자 호출

자식 객체를 생성하면, 부모 객체가 먼저 메모리에 올라가고 (= 생성되고) 자식 객체는 그 다음에 생성된다.

// class Child extends Parent

// 객체 생성
Child ch = new Child();

이 경우 Child 클래스만 객체 생성 한 것 같지만 메모리를 확인해보면
상위 클래스인 Parent가 먼저 올라간뒤
하위 클래스인 Child가 올라가는 모습을 확인할 수 있다

1. 상속 사용시 메모리에 올라가는 순서

/*
자식 클래스를 객체 생성하면
부모의 기본생성자를 자동호출 하고 (메모리에 먼저 올리고)
그 다음 자식 객체의 생성자를 호출한다
		
몇 개를 연결해도 그 순서는 같다
가장 위에 있는 부모부터 순서대로 자동호출 한다.
		
자식 클래스가 객체 생성될 때는 부모 클래스의 기본 생성자로 객체화 한다
즉 부모 클래스에 기본 생성자가 없으면 에러남
 */

public class InherianceEx2 {
	public static void main(String[] args) {

		Bb bb = new Bb();
	}
}

class Per {
	String name;
	String tel;

	// 기본 생성자
	public Per() {
		System.out.println("이곳은 부모 클래스 부분");
	}
}

class Aa extends Per {
	// A클래스의 기본 생성자
	Aa() {
		System.out.println("이곳은 P의 자식 클래스 A의 기본 생성자 부분");
	}
}

class Bb extends Aa {
	// B클래스의 기본 생성자
	Bb() {
		System.out.println("이곳은 A의 자식 클래스 B의 기본 생성자 부분");
	}
}

실행 결과


2. 프로그램 실행 순서(1)

우리는 프로그램 실행순서가 아래와
static{} -> 인스턴스{} -> 생성자{}

그럼 상속이 있을때는?
부모 클래스의 static -> 자식 클래스의 static -> 부모클래스의 인스턴스
-> 부모클래스의기본생성자 -> 자식 클래스의 인스턴스 -> 자식 클래스의 기본생성자

// 자식 클래스에서 부모 클래스의 static을 사용할 수 있는가
// 네

1) 상속 관계를 볼 수 있는 클래스 설정

class PP{
	// 먼저 메모리에 올라가는 정적 변수
	static int a;
	// 인스턴스 변수
	int aa;
	static {
		a=1;
//		b 사용 불가능
//		System.out.println("static 블록 " +a +b);
//		Ab.b 가능
		System.out.println("static 블록  " +a + " "+ Ab.b);
//		불가능. 변수 올라가기 전에 static블록이 먼저 올라가서
//		System.out.println("static 블록 " +a + aa);
	}
	{
		a=3;
//		불가능
//		부모 클래스에서 자식 클래스의 인스턴스 변수를 사용할 수 없습니다
//		System.out.println("인스턴스 블록~ " +a + b);		
//		가능
//		변수 값을 static으로 지정해줬기 때문에, 메모리에 먼저 올라간다
//		그런 값들은 자식 클래스의 것이라도 부모 클래스에서도 불러 사용 가능
		System.out.println("인스턴스 블록~ " +a + " "+ Ab.b);		
//		가능
		System.out.println("인스턴스 블록~ " +a + " "+ aa);

	}
	PP() {
		a=4;
		System.out.println("부모 클래스의 기본 생성자 " +a);
	}
}

class Ab extends PP{
	static int b;
	int bb;
	static {
		b=100;
		a=2;
		//부모의 변수 사용 가능
		System.out.println("이곳은 자식클래스의 static "+b);	
	}
	{
		b=200;
		a=5;
		System.out.println("이곳은 자식 클래스의 인스턴스~ " +b);
	}
	Ab() {
		b=300;
		a=6;
		System.out.println("이곳은 자식클래스의 기본 생성자 " +b);
	}
}

2) 확인할 출력(메인)클래스 작성

public class Inheritance3 {
	public static void main(String[] args) {
		// 부모 클래스 객체 생성
		//PP p = new PP();
		
		//자식 클래스 객체 생성
		Ab aa = new Ab();
	}
}

실행결과


3. 상속 관계를 보자 (2)

상속을 사용하는 관계에서도 this로 다른 메소드 참조 가능

1) 부모 클래스(PPP)와 자식 클래스(Abb)

class PPP{
	static int a;	// 먼저 메모리에 올라가는 정적 변수
	int aa;			// 인스턴스 변수
}

class Abb extends PPP{
	static int b;
	int bb; 
	
	Abb(){
		this(1000);
		System.out.println("자식 클래스의 기본 생성자 부분  " + b + " " + bb);
	}

	Abb(int b){
		// 생성자에서 또 다른 생성자 호출
		this(100, 200);
		System.out.println("자식 클래스의 명시적 생성자 부분  " + b + " " + bb);
	}
	Abb(int b, int bb) {
		
		this.b = b;
		this.b = bb;
		System.out.println("자식클래스의 또 다른 명시적 생성자 부분 "
        				+ b + " " + bb);
	}
}

2) 출력하기 위한(불러올) 메인 클래스

public class Inheritance4 {
	public static void main(String[] args) {
		// 객체 생성
		Abb aa = new Abb();
	}
}



/*
코드중
this(1000) 실행시 Abb(int b) 메소드를 불러와 사용하는 것
this(100, 200) 실행시 Abb(int b, int bb) 메소드 불러와 사용하는 것
으로 확인할 수 있다
*/

실행 결과


0개의 댓글