본문 바로가기

Java

JAVA Programming(Ch 14. 상속)

14-1 상속의 기본 문법 이해

( sw공학에서 자주 언급되는 내용. 아직 sw분야는 재활용이 어려움. 코드 레벨에서 얘기함)

--> 연괸된 일련의 클래스들에 대해 공통적인 규약을 정의할 수 있다.

Ex) A / B / C ( class ) -> 클래스들이 서로 다르면 어떤 규약 & 규칙을 적용하는데 어려움이 있음. class마다 적용될 규칙 & 규약이 다르다.
여기 상속을 적용하면 공통적인 규약 & 규칙을 적용할 수 있다.

 

l  상속의 가장 기본적인 특성

-      상속 (Code level) : 기존에 정의된 클래스에 메소드와 변수를 추가 à 새로운 클래스 정의

-      class Man {
    String
name; // 인스턴스 변수
       
public void tellYourName() { // 인스턴스 메소드
           
System.out.println("My name is " + name);
       
}
    }

 

< 위의 클래스를 물려 받아서 새로운 클래스를 정의 >

public class BusinessMan extends Man { // Man을 상속하는 BusinessMan
   
String company;
   
String position;
    public void
tellYourInfo() {
        System.
out.println("My company is " + company);
       
System.out.println("My position is " + position);
       
tellYourName(); // Man 클래스를 상속했기 때문에 호출 가능! 메소드 & 인스턴스 변수 등
   
}
}

 

 

 

 

l  상속과 생성자

à기본적으로 클래스 안에 존재하는 인스턴스 변수를 초기화 하는 것이 목적

 

< Man클래스에 인스턴스 변수의 초기화를 위한 생성자 정의 >

class Man {
    String
name; // 인스턴스 변수
   
public Man(String name) {
       
this.name = name; // 생성자 내에서 위 name을 적절히 초기화 하도록 정의
       
// String name private로 선언되지 않았기 때문에 직접 접근 가능
   
}
       
public void tellYourName() { // 인스턴스 메소드
           
System.out.println("My name is " + name);
   
}
}

 

< Business 클래스에 인스턴스 변수의 초기화를 위한 생성자 정의 >

public class BusinessMan extends Man { // Man을 상속하는 BusinessMan
   
String company;
   
String position;
   
// 모든 인스턴스 변수를 적절히 초기화하도록 아주 잘 정의되어 있음.
    // -->
회사랑 직급은 초기화가 되는데 이름 정보가 초기화가 안된다.
    //
생성자 내에서 name에 접근하는 코드를 만들어놓지 X.
   
public BusinessMan(String company, String position) {
       
this.company = company;
        this
.position = position;
   
}
   
public void tellYourInfo() {
        System.
out.println("My company is " + company);
       
System.out.println("My position is " + position);
       
tellYourName(); // Man 클래스를 상속했기 때문에 호출 가능! 메소드 & 인스턴스 변수 등
   
}
}
// --> 모든 멤버의 초기화는 이루어진다. 그러나 생성자를 위한 초기화 원칙에는 어긋남.

 

-      상위 클래스 Man, 그리고 이를 상속하는 하위 클래스인 BusinessMan에도 적절한 생성자가 정의 되어 있다.

-      문제 ) BusinessMan의 인스턴스 생성 -> 그 안에는 Man 클래스의 상속으로 인해 name변수가 초기화되지 않는 문제가 발생한다.

-      String name;-->상속으로 인해 BusinessMan 클래스의 멤버가 된 변수

< BusinessMan생성자에서 위 변수의 초기화 진행 >

 

l  MyBusinessMan

l  class Man {
    String
name; // 인스턴스 변수
   
public void tellYourName() {
        System.
out.println("My name is " + name);
   
}
}

class BusinessMan extends Man { // Man을 상속하는 BusinessMan
   
String company;
   
String position;

   
// man의 멤버 name을 초기화할 수 있는걸 인자로 받아버림.
   
public BusinessMan(String name, String company, String position) {
       
this.name = name; // String name을 초기화해주는 코드를 넣음
       
// this --> 이 인스턴스의 멤버 name
       
this.company = company;
        this
.position = position;
   
}

   
public void tellYourInfo() {
        System.
out.println("My company is " + company);
       
System.out.println("My position is " + position);
       
tellYourName(); // Man 클래스를 상속했기 때문에 호출 가능! 메소드 & 인스턴스 변수 등
   
}
}

class MyBusinessMan {
   
public static void main(String[] args) {
        BusinessMan man =
new BusinessMan("YOON", "Hybrid ELD", "Staff Eng.");
       
man.tellYourInfo();
   
}
}

 

< 상속 관계에 있는 생성자의 호출 관계 >

class SuperCLS {
   
public SuperCLS() {  // 생성자
       
System.out.println("I'm Super Class");
   
}
}

class SubCLS extends SuperCLS {
   
public SubCLS() { // 생성자
       
System.out.println("I'm Sub Class");
   
}
}

class SuperSubCon {
   
public static void main(String args[]) {
       
new SubCLS();
   
}
}

 

-> 하위 클래스의 인스턴스 생성 상위 클래스, 하위 클래스의 생성자 모두 호출.

-> 하위 클래스의 인스턴스 생성 시 상위 클래스의 생성자가 먼저 호출된다.

 

-      아래 코드에서 SuperCLS()SuperCLS의 생성자가 이 순간에 호출됨을 의미.

class SubCLS extends SuperCLS {
   
public SubCLS() {
        SuperCLS()
; // 상위 클래스의 생성자가 이 순간에 호출됨을 의미.
       
System.out.println("I'm Sub Class");
   
}
}

 

-      하위 클래스의 생성자에서 상위 클래스의 생성자를 명시적으로 호출하지 않으면,
인자를 받지 않는 생성자가 자동으로 호출.



상위 클래스의 생성자는 어떻게 명시적으로 호출? (다음)

-      super : 상위 클래스의 생성자 호출  

< super 클래스를 사용하여 상위 클래스의 명시적 호출 >

class SuperCLS {
   
public SuperCLS() {
        System.
out.println("Con : SuperCLS()" );
   
}
   
public SuperCLS(int i) {
        System.
out.println("Con : SuperCLS(int i)");
   
}
   
public SuperCLS(int i, int j) {
        System.
out.println("Con : SuperCLS(int i, int j)");
   
}
}

class SubCLS extends SuperCLS {
   
public SubCLS() {
        System.
out.println("Con : SubCLS()");
   
}
   
public SubCLS(int i) {
       
super(i); // 상위 클래스의 생성자 지정 및 호출
       
System.out.println("Con : SubCLS(int i)");
   
}
   
public SubCLS(int i, int j){
       
super(i,j); // 상위 클래스의 생성자 지정 및 호출
       
System.out.println("Con : SubCLS(int i , int j)");
   
}
}

public class SuperSubCon2 {
   
public static void main(String args[]) {
        System.
out.println("1. ");
        new
SubCLS();
       
System.out.println();

       
System.out.println("2. ");
        new
SubCLS(1);
       
System.out.println();

       
System.out.println("3. ");
        new
SubCLS(1, 2);
       
System.out.println();
   
}
}

 

-      super(1); -> 1을 인자로 전달받을 수 있는 생성자 호출

-      super(1, 2); -> 12를 인자로 전달받을 수 있는 생성자 호출

 

è 상위 클래스의 생성자는 하위 클래스 생성자의 몸체 부분에 앞서 실행되어야 함

super를 이용한 상위 클래스의 생성자 호출문은 생성자의 첫 문장으로 등장 해야함.

 

< 컴파일 오류가 발생하는 경우 >

1.     Super 위치

public SubCLS(int i) {
    System.
out.println(~~~);
    super
(i); // super가 이 위치에 있으면 컴파일 오류 발생
}

 

2.     생성자 호출을 생략한 경우 à 생성자 호출문이 자동으로 삽입

public SubCLS() {
    System.
out.println("Con : SubCLS()");
}

è  

 

public SubCLS() {
   
super(); // 자동으로 삽입이 된 문장
   
System.out.println("Con : SubCLS()");
}

 

 

 

l  < 상속 관계에 있는 두 클래스의 적절한 생성자 정의 >

-      자바는 상속 관계에 있어도, 상위 클래스의 멤버는 상위 클래스의 생성자를 통해서 초기화하도록 유도.
(
하위 클래스의 인스턴스 생성 과정 중 상위 클래스의 생성자가 호출되는 이유가 여기 있음)

< MyBusinessMan2 > : super(변수로 받는 것)

class Man {
    String
name;

    public
Man(String name){
       
this.name = name;
   
}
   
public void tellYourName() {
        System.
out.println("My name is " + name);
   
}
}

class BusinessMan extends Man {
    String
company;
   
String position;

    public
BusinessMan(String name, String company, String position) {
       
super(name); // 상위 클래스의 생성자 호출
       
this.company = company;
        this
.position = position;
   
}
   
public void tellYourInfo() {
        System.
out.println("My company is" + company);
       
System.out.println("My position is" + position);
       
tellYourName();
   
}
}

public class MyBusinessMan2 {
   
public static void main(String args[]) {
        BusinessMan man =
new BusinessMan("YOON", "Hybrid ELD", "Staff Eng.");
       
man.tellYourInfo();
   
}
}

 

 

-      상속 관계에 있을지라도 인스턴스 변수는 각 클래스의 생성자를 통해서 초기화 진행

 

< 단일 상속만을 지원하는 자바 >

--> 이는 다음과 같이 하나의 클래스가 상속할 수 있는 클래스의 수가 최대 하나라는 것.
과도하게 복잡해지는 것을 막기 위해서 !