상속(Inheritance)
상속
- 객체와 객체를 연관시키고 계층구조를 만들어 코드를 재사용
- 부모 클래스, 상위 클래스, 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");
}
}