Language/Java

상속(Inheritance)

뚜sh뚜sh 2023. 7. 3. 15:10

상속

  • 객체와 객체를 연관시키고 계층구조를 만들어 코드를 재사용

- 부모 클래스, 상위 클래스, parent class, super class

- 자식 클래스, 하위 클래스, child class, sub class

- 오직 한 클래스만을 상속할 수 있다

 

 

 

형식

1. 상속 형식

  • class 클래스명(자식 클래스) extends 상속 클래스명(부모 클래스)

- 모든 클래스의 부모 클래스 -> Object

- 상위 클래스의 접근지정자에 따라 접근이 제한

 

 

 

멤버 상속

1. 상위 클래스에 지정된 private 멤버는 해당 클래스에서만 사용할 수 있고 하위 클래스에서는 사용할 수 없다

package first;

public class first {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		A TestA = new A();
		TestA.PrintB();
		
		B TestB = new B();
		TestB.PrintC(); // error 발생
	}

}

class A {
	private int m_nVar1 = 11;
	
	private void PrintA() {
		System.out.println("AAAAAA");
	}
	
	public void PrintB() {
		PrintA();
	} // private 속성은 클래스 안에서만 사용 가능
}

class B extends A {
	void PrintC() {
		PrintA(); // 상위 private 속성, error 발생
		System.out.println(m_nVar1); // 상위 private 속성, error 발생
	}
}

 

2. 상위 클래스에 지정된 public 멤버는 해당 클래스뿐만 아니라 하위 클래스에서도 사용할 수 있으며 외부에서도 언제든지 사용할 수 있다

package first;

public class first {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		B TestB = new B();
		TestB.PrintC();
		TestB.PrintA();
		System.out.println(TestB.m_nVar1);
	}

}

class A {
	public int m_nVar1 = 11;
	public void PrintA() {
		System.out.println("AAAAAA");
	}
	
	public void PrintB() {
		PrintA();
	} 
}

class B extends A {
	public void PrintC() {
		PrintA(); 
		System.out.println(m_nVar1); 
	}
}

 

3. protected의 상위 멤버는 같은 패키지일 때는 public 멤버처럼 사용하지만 다른 패키지인 경우는 상위 멤버를 하위 클래스 안에서만 사용할 뿐 외부 사용은 할 수 없다

package test;

public class C {
	protected int m_nVar1 = 30;
	protected void Print() {
		System.out.println(m_nVar1);
	}

}
package test2;
import test.C;

// protected 사용 예
// 1. 같은 패키지 안에서 protected 멤버의 사용
// 2. 다른 패키지의 protected 멤버 사용

public class test2 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		B Test = new B();
		Test.PrintA(); // 같은 패지, 상위 멤버 호출
		Test.m_nVar1 = 13;
		Test.PrintC();
		System.out.println(Test.m_nVar1);
		
		D Test2 = new D(); // 서로 다른 패키지
		Test2.PrintD(); // 하위 클래스 안에서만 호출
		// Test2.m_nVar1 = 40; error 발생
		// Test2.Print();
		// System.out.println(Test2.m_nVar1); error 발생
	}
}

class A {
	protected int m_nVar1 = 11;
	protected void PrintA() {
		System.out.println("A Class : " + m_nVar1);
	}
}

class B extends A {
	public void PrintC() {
		System.out.println("B Class : " + m_nVar1);
	}
}

class D extends C {
	public void PrintD() {
		System.out.println("D Class : " + m_nVar1);
	}
}

 

4. 상위 클래스에서 default 멤버들은 같은 패키지 안에 있을 때는 public 멤버처럼 사용할 수 있지만 패키지가 다른 경우는 하위 클래스에서 상위 클래스 default 멤버를 사용할 수 없고 외부에서도 사용할 수 없다

package test;

public class C {
	int m_nVar = 11;
}
package test2;
import test.*;

// protected 사용 예
// 1. 같은 패키지 안에서 protected 멤버의 사용
// 2. 다른 패키지의 protected 멤버 사용

public class test2 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 같은 패키ㅣ지 안에서 상위 default 멤버 사용
		B Test1 = new B();
		Test1.m_nVar = 20;
		Test1.Print();
		
		D Test2 = new D(); // 서로 다른 패키지
		// Test2.m_nVar = 30; error 발생
		// Test2.Print(); // error 발생
	}
}

class A {
	int m_nVar = 7;
	
}

class B extends A {
	public void Print() {
		System.out.println("B Class : " + m_nVar);
	}
}

class D extends C {
	public void Print() {
		// m_nVar = 20; // error 발생
		// System.out.println("D Class : " + m_nVar);
	}
}

 

 

 

오버라이딩

- 부모 클래스의 메소드를 자식 클래스에서 다시 재정의하는 것

- 주의사항

  • 함수명이 같아야 한다
  • 함수의 매개변수가 같아야 한다
  • 리턴형이 같아야 한다
package test2;

public class test2 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		B Test = new B();
		System.out.println(Test.Set(11));
	}
}

class A {
	protected int m_nVar;
	public int Set(int nVar) {
		m_nVar = nVar;
		return m_nVar;
	}
	
}

class B extends A {
	public int Set(int nVar) {
		m_nVar = nVar + 1;
		return m_nVar;
	}
}

 

 

 

final

1. final이 클래스와 메소드에 붙는 경우

- 상속과 오버라이딩 불가

- 클래스와 메소드의 맨 앞쪽에 위치

final class A {
	protected int m_nVar;
	public int Set(int nVar) {
		m_nVar = nVar;
		return m_nVar;
	}
	
}

class B extends A { //error
	public int Set(int nVar) {
		m_nVar = nVar + 1;
		return m_nVar;
	}
}
class A {
	final void Print() {
	System.out.println("hihi");
	}
	
}

class B extends A { 
	public void Print() { // error
		System.out.println("gg");
	}
}

 

2. final이 변수에 사용되는 경우

public class test2 {
	static final float m_nVar = 3.14f;
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		m_nVar = 0.5f; // error
	}
}

 

 

 

상속관계에서 생성자의 호출 순서

1. 상위 클래스 생성자에서부터 하위 클래스 생성자 호출

package test2;

public class test2 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		C Test = new C();
	}
}

class A {
	public A() {
	System.out.println("AAAAAAA");
	}
	
}

class B extends A { 
	public B() {
		System.out.println("BBBBBBB");
	}
}

class C extends B {
	public C() {
		System.out.println("CCCCCCC");
	}
}

 

2. 생성자에 매개변수가 있는 경우 자동호출 안됨 -> super 키워드 사용

 

 

 

super

  • 하위 클래스에서 상위 클래스를 참조하여 접근할 때 사용

1. 형식

- super.멤버 변수명

- super.메소드명(매개변수)

 

2. 사용

- 하위 클래스에서 상위 클래스의 메소드나 변수를 호출할 때 사용

package test2;

public class test2 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		B Test = new B();
		Test.Print();
	}
}

class A {
	protected void Print() {
	System.out.println("AAAAAAA");
	}
	
}

class B extends A { 
	public void Print() {
		super.Print();
		System.out.println("BBBBBBB");
	}
}

 

- 하위 클래스에서 상위 클래스의 생성자를 호출할 때 super(매개변수) 또는 super()와 같이 사용

※ 하위 클래스의 생성자 맨 첫줄에 있어야 한다

package test2;

public class test2 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		B Test1 = new B();
		Test1.Print();
		
		D Test2 = new D();
		Test2.Print();
	}
}

class A {
	int m_nVar;
	public A(int nVar) {
		m_nVar = nVar;
	System.out.println("AAAAAAA");
	}
	
}

class B extends A { 
	public B() {
		super(7);
	}
	
	public void Print() {
		System.out.println("super class A : " + m_nVar);
	}
}

class C {
	int m_nVar;
	public C() {
		m_nVar = 11;
		System.out.println("CCCCCCC");
	}
}

class D extends C {
	public D() {
		super();
	}
	
	public void Print() {
		System.out.println("super class C : " + m_nVar );
	}
}

 

 

 

참조 변수를 이용한 형 변환과 호출

- 캐스트 연산자 사용 ()

- 형 변환의 규칙

1. 하위 클래스에서 상위 클래스로 형 변환할 수 있으며 접근지정자에 따라 접근이 결정된다

package test2;

public class test2 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		C C_Test = new C();
		B B_Test = new C();
		
		A A_Test = (A)C_Test;
		A_Test.Print1();
		B_Test.Print2();
	}
}

class A {
	public void Print1() {
		System.out.println("AAAAAAA");
	}
	
}

class B extends A { 
	public void Print2() {
		System.out.println("BBBBBBB");
	}
}

class C extends B {
	public void Print3() {
		System.out.println("CCCCCCC");
	}
}

 

2. 생성된 하위 클래스에서 상위 클래스 형 변환을 통해 하위 클래스의 멤버에 접근할 수 없다

package test2;

public class test2 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		C C_Test = new C();
		A A_Ref = C_Test; // 또는 (A)C_Test;
		// A_Ref.Print3(); // 에러 접근불가
		A_Ref.Print1();
	}
}

class A {
	public void Print1() {
		System.out.println("AAAAAAA");
	}
	
}

class B extends A { 
	public void Print2() {
		System.out.println("BBBBBBB");
	}
}

class C extends B {
	public void Print3() {
		System.out.println("CCCCCCC");
	}
}

 

3. 상위 클래스의 메소드가 하위 클래스에 오버라이딩(재정의)된 경우에 상위 클래스 참조변수에서 오버라이딩된 메소드를 호출하면 하위 클래스의 메소드가 실행

package test2;

public class test2 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		C C_Test = new C();
		A A_Test = C_Test;
		A_Test.Print();
	}
}

class A {
	public void Print() {
		System.out.println("AAAAAAA");
	}
	
}

class B extends A { 
	public void Print() {
		System.out.println("BBBBBBB");
	}
}

class C extends B {
	public void Print() {
		System.out.println("CCCCCCC");
	}
}