1.  상속  inheritance

✏️  부모가 자식에게 물려주는 행위를 말함

  

  👾  상속은 이미 잘 개발된 클래스를 재사용해서 새로운 클래스를 만들기 때문에 중복되는 코드를 줄여 개발 시간을 단축시킨다.

  👾  자식 클래스에 새로운 코드가 추가되어도 부모 클래스는 아무런 영향을 받지 않는다.

         but, 조상클래스가 변경되면 자손클래스는 자동적으로 영향을 받게 됨. ( = 조상 클래스의 모든 멤버를 상속 받음 )

  👾  부모 클래스를 확장(extend) 한다는 의미로 상속에 사용되는 키워드가 'extends'이다.

  👾  자식 클래스의 인스턴스를 생성하면 부모 클래스의 멤버와 자손 클래스의 멤버가 합쳐진 하나의 인스턴스로 생성됨

class Person { // 사람 클래스
    void breath() {
        System.out.println("숨쉬기");
    }

    void eat() {
        System.out.println("밥먹기");
    }

    void say() {
        System.out.println("말하기");
    }
}

class Student extends Person{ // 사람 클래스를 상속한 학생 클래스
    void learn(){
        System.out.println("배우기");
    }
}

class Teacher extends Person{ // 사람 클래스를 상속한 선생 클래스
    void teach(){
        System.out.println("가르치기");
    }
}
public class Test {
    public static void main(String[] args) {
        Student student = new Student(); // 학생 인스턴스 student 생성
        student.breath(); // 사람 클래스의 breath 메서드를 상속 받았음.
        student.learn();
        student.say();

        Teacher teacher = new Teacher(); // 선생 인스턴스 teacher 생성
        teacher.eat(); // 사람 클래스의 eat 메서드를 상속 받았음
        teacher.teach();
        teacher.say();

        Person person = new Person();
        person.breath();
   //     person.learn(); // 자식 클래스의 메서드나 멤버 변수는 사용하지 못함.
    }
}

 


1)  클래스 상속

  ⚒️  자식 클래스를 선언할 때 어떤 부모로부터 상속받을 것인지를 결정하고, 부모 클래스를 extends 뒤에 기술

  ⚒️  다른 언어와 달리 자바는 다중 상속 허용 X. 단 하나의 부모 클래스만 상속 받을 수 있다!

public class Phone {
	//필드 선언
	public String model;
	public String color;

	//메소드 선언
	public void bell() {
		System.out.println("벨이 울립니다.");
	}

	public void sendVoice(String message) {
		System.out.println("자기: " + message);
	}
	
	public void receiveVoice(String message) {
		System.out.println("상대방: " + message);
	}

	public void hangUp() {
		System.out.println("전화를 끊습니다.");
	}
}
public class SmartPhone extends Phone {
	//필드 선언
	public boolean wifi;

	//생성자 선언
	public SmartPhone(String model, String color) {
		this.model = model;
		this.color = color;
	}

	//메소드 선언
	public void setWifi(boolean wifi) {
		this.wifi = wifi;
		System.out.println("와이파이 상태를 변경했습니다.");
	}

	public void internet() {
		System.out.println("인터넷에 연결합니다.");
	}
}
public class SmartPhoneExample {

	public static void main(String[] args) {
		//SmartPhone 객체 생성
		SmartPhone myPhone = new SmartPhone("갤럭시", "은색");

		//Phone으로부터 상속받은 필드 읽기
		System.out.println("모델: " + myPhone.model);
		System.out.println("색상: " + myPhone.color);

		//SmartPhone의 필드 읽기
		System.out.println("와이파이 상태: " + myPhone.wifi);

		//Phone으로부터 상속받은 메소드 호출
		myPhone.bell();
		myPhone.sendVoice("여보세요.");
		myPhone.receiveVoice("안녕하세요! 저는 홍길동인데요.");
		myPhone.sendVoice("아~ 네, 반갑습니다.");
		myPhone.hangUp();
		
		//SmartPhone의 메소드 호출
		myPhone.setWifi(true);
		myPhone.internet();
	}
}

 


2)  부모 생성자 호출

  ⚒️  자식 객체를 생성하면 부모 객체가 먼저 생성된 다음에 자식 객체가 생성된다.

 

  ⚡️ 부모 생성자는 자식 생성자의 맨 첫 줄에 숨겨져 있는 super()에 의해 호출된다.

  ⚡️ super()는 컴파일 과정에서 자동 추가되는데, 이것은 부모의 기본 생성자를 호출한다.

         ➡️  만약 부모 클래스에 기본 생성자가 없다면 자식 생성자 선언에서 컴파일 에러가 발생

         ➡️  기본 생성자는 없고 매개변수를 갖는 생성자만 있다면 super(매개값, ...) 코드를 직접 넣어야 함

// 자식 생성자 선언
public 자식클래스(...) {
  super(); // 생략 가능
  ...
}

public 자식클래스(...) {
  super(매개값, ...); // 생략 불가
  ...
}

 

기본 생성자를 가지고 있는 경우
public class Phone {
	//필드 선언
	public String model;
	public String color;

	//기본 생성자 선언
	public Phone() {
		System.out.println("Phone() 생성자 실행");
	}
}
public class SmartPhone extends Phone {
	//자식 생성자 선언
	public SmartPhone(String model, String color) {
		super();
		this.model = model;
		this.color = color;
		System.out.println("SmartPhone(String model, String color) 생성자 실행됨");
	}
}
public class SmartPhoneExample {

	public static void main(String[] args) {
		//SmartPhone 객체 생성
		SmartPhone myPhone = new SmartPhone("갤럭시", "은색");
			
		//Phone으로부터 상속 받은 필드 읽기
		System.out.println("모델: " + myPhone.model);
		System.out.println("색상: " + myPhone.color);
	}
}
// 실행 결과
Phone() 생성자 실행
SmartPhone(String model, String color) 생성자 실행됨
모델: 갤럭시
색상: 은색

 

매개변수를 갖는 생성자가 있는 경우
public class Phone {
	//필드 선언
	public String model;
	public String color;

	//매개변수를 갖는 생성자 선언
	public Phone(String model, String color) {
		this.model = model;
		this.color = color;
		System.out.println("Phone(String model, String color) 생성자 실행");
	}
}
public class SmartPhone extends Phone {
	//자식 생성자 선언
	public SmartPhone(String model, String color) {
		super(model, color);
		System.out.println("SmartPhone(String model, String color) 생성자 실행됨");
	}
}
public class SmartPhoneExample {
	
	public static void main(String[] args) {
		//SmartPhone 객체 생성
		SmartPhone myPhone = new SmartPhone("갤럭시", "은색");
		
		//Phone으로부터 상속 받은 필드 읽기
		System.out.println("모델: " + myPhone.model);
		System.out.println("색상: " + myPhone.color);
	}
}
// 실행 결과
Phone(String model, String color) 생성자 실행
SmartPhone(String model, String color) 생성자 실행됨
모델: 갤럭시
색상: 은색

 

 

 

* 내용 참고 - 책 '이것이 자바다'


 

1. 클래스 변수

🚀  클래스를 구현할 때 인스턴스마다 서로 다른 값을 가지는 경우에는 인스턴스 변수를 사용
🚀  모든 인스턴스 변수들은 self 키워드를 붙여서 사용
🚀  모든 인스턴스가 동일한 값을 사용할 때는 클래스 변수로 처리해서 모든 인스턴스들이 공유하도록 처리하는 것이 좋음
        ➡️  하나의 값을 모든 인스턴스가 공유하기 때문에 메모리 공간의 낭비를 막을 수 있음

     ⚡️  self
         - 관례적으로 모든 메서드의 첫 번째 매개변수 이름을 self로 지정.
         - self라는 명칭은 관례적으로 사용하는 단어.

# 클래스 변수 만들기
class 클래스 이름:
    클래스 변수 = 값
# 클래스 변수 접근
클래스 이름.변수 이름
class Korean:
    country = '한국'  # 클래스 변수 country

    def __init__(self, name, age, address):
        self.name = name  # 인스턴스 변수
        self.age = age
        self.address = address

print(Korean.country)  # 객체 생성전에도 사용 가능.

man = Korean('홍길동', 35, '서울')
print(man.name)
# print(Korean.name)  # AttributeError: type object 'Korean' has no attribute 'name'

print(man.country)  # 인스턴스 man을 통한 클래스 변수 접근
print(Korean.country)  # 클래스 Korean을 통한 클래스 변수 접근

print('객체 property 생성과 동일한 이름의 클래스 변수')
man.country = '중국'  # 객체의 인스턴스 변수 생성
print(man.country)  # 중국. 
# 클래스 변수가 아니라 인스턴스 변수를 불러옴. 
# man 객체의 country 라는 인스턴스 변수와 country 클래스 변수
print(man.__class__.country)  # 한국. 객체를 사용해서 클래스 변수 불러오기.
print(Korean.country)  # 한국.

print('객체를 이용해서 클래스 변수 값 변경')
man.__class__.country = '영국'
print(Korean.country)  # 영국

print('클래스를 이용해서 클래스 변수 값 변경')
Korean.country = '미국'  # 클래스 변수를 변경
print(Korean.country)  # 미국

man2 = Korean('홍길동2', 35, '서울')
print(man2.country)  # 미국
print(Korean.country)  # 미국

# 클래스 변수는 클래스를 통해서 접근하는 것이 권장사항

 


 

2. 클래스 메소드

🚀  클래스 변수를 사용하는 메소드를 의미
 

   ⚡️ 주요 특징
         a. 인스턴스 혹은 클래스로 호출
         b. 생성된 인스턴스가 없어도 호출할 수 있음
         c. @classmethod 데코레이터 decorator를 표시하고 작성
         d. 매개변수 self를 사용하지 않고 cls를 사용
         e. 클래스 메소드는 self를 사용하지 않기 때문에 인스턴스 변수에 접근할 수 없지만 cls를 통해서 클래스 변수에 접근할 수 있음

class Korean:
    country = '한국'  # 클래스 변수 country

    @classmethod
    def trip(cls, country):
        if cls.country == country:
            print('국내여행입니다.')
        else:
            print('해외여행입니다.')

Korean.trip('한국')  # 국내여행입니다.
Korean.trip('미국')  # 해외여행입니다.

 


 

3. 정적 메소드

🚀  인스턴스 또는 클래스로 호출
🚀  생성된 인스턴스가 없어도 호출 가능
🚀  @staticmethod 데코레이터 decorator를 표시하고 작성
🚀  반드시 작성해야 할 매개변수가  없음

 

    ⚡️  self와 cls를 모두 사용하지 않기 때문에 인스턴스 변수와 클래스 변수를 모두 사용하지 않는 메소드를 정의하는 경우에 적절
    ⚡️  정적 메소드는 클래스에 소속이 되어 있지만, 인스턴스에는 영향을 주지 않고 또 인스턴스로부터 영향을 받지도 않음

class Korean:
    country = '한국'  # 클래스 변수 country

    @staticmethod
    def slogan():
        print('Imagine your Korea')

Korean.slogan()  # Imagine your Korea

 


 

4. 상속  inheritance

 

1) 상속이란?

👾  어떤 클래스가 가지고 있는 기능을 그대로 물려받아서 사용할 수 있는 클래스를 만들 수 있다.
👾  다른 클래스의 기능을 물려받을 때 상속받는다는 표현을 사용
👾  상속 관계에 있는 클래스를 표현할 때 '부모 클래스와 자식 클래스'라는 말을 사용

    ⚡️ 부모 클래스 : 상속해 주는 클래스 / 슈퍼 클래스 super class , 기반 클래스 base class
    ⚡️ 자식 클래스 : 상속 받는 클래스 / 서브 클래스 sub class, 파생 클래스 derived class


2) 상속 관계 구현

👾  기본적으로 두 클래스가 상속 관계에 놓이려면 IS-A 관계가 성립해야 한다
👾  IS-A 관계란 '~은 ~ 이다'로 해설할 수 있는 관계를 의미
        ex. '학생은 사람이다 Student is a Person'처럼 해석되는 것이 IS-A 관계
                이때 Student 는 서브 클래스가 되고, Person은 슈퍼 클래스가 됨

👾  has-a 관계는  '그릇이 스쿱을 갖는다 Bowl has-a Scoop'
👾  has-a 관계는 상속이 아니라 구성 Composition으로 구현함

# 상속의 기본적인 형식
class 슈퍼 클래스:
    본문

class 서브 클래스(슈퍼 클래스):
    본문


  ⚡️  서브 클래스를 구현할 때는 괄호 안에 어떤 슈퍼 클래스를 상속 받는지 명시
  ⚡️  상속 관계에 놓인 서브 클래스는 마치 자신의 것처럼 슈퍼 클래스의 기능을 사용할 수 있음

 

class Person:  # 슈퍼 클래스
    def __init__(self, name):
        self.name = name

    def eat(self, food: str) -> None:
        print(f'{self.name}가 {food}를 먹습니다.')

class Student(Person):  # 서브 클래스
    def __init__(self, name: str, school: str) -> None:
        super().__init__(name)  # 슈퍼 클래스의 생성자 실행
        self.school = school

    def study(self) -> None:
        print(f'{self.name}는 {self.school}에서 공부를 합니다.')

potter = Student('해리포터', '호그와트')
potter.eat('감자')  # 해리포터가 감자를 먹습니다.
potter.study()  # 해리포터는 호그와트에서 공부를 합니다.

 

3) 서브 클래스의  __init__()

👾  서브 클래스의 생성자를 구현할 때는 반드시 슈퍼 클래스의 생성자를 먼저 호출하는 코드를 작성해야 함
👾  super라는 키워드는 슈퍼 클래스를 의미

class Computer:  # 슈퍼 클래스
    def __init__(self):
        print('슈퍼 클래스의 생성자가 실행되었습니다.')

class NoteBook(Computer):  # 서브 클래스
    def __init__(self):
        super().__init__()
        print('서브 클래스의 생성자가 실행되었습니다.')

 


 

4) 서브 클래스의 인스턴스 자료형

👾  슈퍼 클래스 객체는 슈퍼 클래스의 인스턴스
👾  그에 비해 서브 클래스 객체는 서브 클래스의 인스턴스이면서 동시에 수퍼 클래스의 인스턴스

 

    ⚡️ 서브 클래스 Student의 객체는 서브 클래스 Student의 인스턴스 이면서 동시에 슈퍼 클래스 Person의 인스턴스

👾  어떤 객체가 어떤 클래스의 인스턴스인지 확인하기 위해서 isinstance() 함수를 사용
        ➡️  객체가 인스턴스일 경우에는 True 아니면 False 반환

# isinstance(객체, 클래스)
print(isinstance(potter, Student))  # True
print(isinstance(potter, Person))  # True

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]

+ Recent posts