버글버글

Java 수업 기록 (10) 상속 본문

java/java 수업 기록

Java 수업 기록 (10) 상속

Bugle 2022. 8. 1. 19:00
반응형

 

▶ 상속(Interitance) 

1. 어떤 클래스의 필드와 메소드를 다른 클래스가 물려 받아 사용하는 것

2. 부모클래스가 자식클래스에게 필드와 메소드를 물려 줌

3. 자바에서는 부모클래스는 "슈퍼클래스(super)", 자식클래스를 "서브클래스(sub)"라고 함

4. 상속의 장점

  1) 동일한 메소드를 클래스마다 여러 번 정의할 필요가 없음

  2) 클래스를 계층(부모-자식) 관계로 관리할 수 있음

  3) 클래스의 재사용과 확장이 쉬움

  4) 새로운 클래스의 작성 속도가 빠름

** 상속 클래스를 설계를 못하는건 문제가 안되지만, 해석을 못하는건 큰 문제다 **

▶ Is a 

Student is a Person
Student 자식
is a extends
Person 부모

extends 자리에 is a를 넣었을때 말이 되면 맞는 코드(?) 이다.

 

 

예시)

Person
(슈퍼클래스)
먹는다 잔다 걷는다    
Student
(서브클래스)
먹는다 잔다 걷는다 공부한다  
Professor
(서브클래스)
먹는다 잔다 걷는다 연구한다 수업한다

 

// 슈퍼클래스
public class Person {

	public void eat() {
		System.out.println("먹는다.");
	}
	
	public void sleep() {
		System.out.println("잔다.");
	}
	
	public void walk() {
		System.out.println("걷는다.");
	}
}
// 서브클래스
// extends라는 키워드를 사용한다.
// 슈퍼클래스 Person의 모든 메소드를 자기것처럼 사용할 수 있다.

public class Student extends Person {

	public void study() {
		System.out.println("공부한다.");
	}
}

* public class Student extends Person

public class StudentMain {

	public static void main(String[] args) {

		Student student = new Student();
		
		student.eat();		// 먹는다.
		student.sleep();	// 잔다.
		student.walk();		// 걷는다.
		student.study();	// 공부한다.
	}

}

상속관계에서의 생성관계에서는 총을 생성해서 넣을 수 있는 방ㅂ...ㅓㅂ..이..업.ㅅ..다....

▶ has a 

1. has a 관계는 살짝 어색하다.

예시)

public class Gun {
	
	// 필드
	private String model;
	private int bullet;	
	private final int MAX_BULLET = 15;
	
	// 메소드
	public String getModel() {
		return model;
	}
	public void setModel(String model) {
		this.model = model;
	}
	public int getBullet() {
		return bullet;
	}
	public void setBullet(int bullet) {
		this.bullet = bullet;
	}
	
	// 장전
	public void reload(int bullet) {
		if(this.bullet == MAX_BULLET) {
			return;
		}
		this.bullet += bullet;
		this.bullet = (this.bullet > MAX_BULLET) ? MAX_BULLET : this.bullet;	
	}
	
	// 총쏘기
	public void shoot() {
		if(bullet == 0) {
			return;
		}
		bullet--;
	}

}
public class Soldier {
	
	// 필드
	private Gun gun;	// 총을 가지고 있다.

	// 메소드
	public Gun getGun() {
		return gun;
	}

	public void setGun(Gun gun) {
		this.gun = gun;
	}
	
	public void reload(int bullet) {		// 군인이 총알을 받으면 그 총알을 총에 넣는다.
		gun.reload(bullet);
	}
	
	public void shoot() {
		gun.shoot();
	}
}
public class SoldierMain {

	public static void main(String[] args) {

		Gun gun = new Gun();
		gun.setModel("K2");
		gun.setBullet(9);
		
		Soldier soldier = new Soldier();
		soldier.setGun(gun);
		
		// soldier가 총을 쏜다.
		soldier.shoot();
		
		// soldier가 장전한다.
		soldier.reload(1);
		
		// soldier가 가지고 있는 gun의 모델명
		System.out.println(soldier.getGun().getModel());
		System.out.println(soldier.getGun().getBullet());
	}

}

▶ 상속 관계에 있는 객체의 생성 

1. 서브클래스의 객체 생성

 - 서브클래스의 객체는 슈퍼클래스의 메소드를 사용할 수 있음

 - 서브클래스의 객체를 생성할 때 슈퍼클래스의 객체가 먼저 생성됨.

    = 슈퍼클래스의 생성자가 먼저 호출되고, 서브클래스의 생성자가 나중에 호출된다.

    = 서브클래스는 슈퍼클래스의 생성자를 "반드시" 호출해야 한다.

     (자식이 태어나려면, 부모가 먼저 태어나야 한다.)

- 개발자가 생성자를 호출하지 않으면 자동으로 JVM이 호출한다. (매개변수가 없는 - default 것만 자동으로 진행된다.)

예시)  매개변수가 디폴트 일때의 예시

* super는 spuer class 호출

public class Person {
	
	// 매개변수가 없는 생성자.
	public Person() {
		System.out.println("Person 생성");
	}
// 서브클래스는 슈퍼클래스의 생성자를 "반드시" 호출해야 한다.
// 자식이 태어나려면, 부모가 태어나 있어야 한다.

public class Student extends Person {
	
	// 개발자가 슈퍼클래스의 생성자를 호출하지 않으면
	// 자동으로 JVM이 호출한다.
	public Student() {
		System.out.println("Student 생성");
	}

메인 메소드에서, 서브클래스만 호출

public class StudentMain {

	public static void main(String[] args) {

		Student student = new Student(); // 서브클래스 생성자 호출

	}

예시)  매개변수가 디폴트가 아닐때의 예시

- 서브클래스가 슈퍼클래스를 부를때 extends를 사용하면 오류가 뜬다.

- 빨리 슈퍼클래스를 호출하라는 말이다. (빨리 constructor를 만들어라)

- 매개변수가 디폴트가 아니기 때문에.

public class Person {
	
	// 필드
	private String name;
	
	// 생성자	// 전달받은 매개값을 필드값으로 전달 해 주는 생성자를 만듬.
	public Person(String name) {
		this.name = name;
	}
	
	
	//getter , setter
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
public class Student extends Person {
	
	// 필드값
	private String school;
	
	// 생성자
	// public Person(String name) 을 여기서 가져다 주는거다.
	// String school은 Student 필드값을 가져오는거다.
	// super = Person 슈퍼클래스의 생성자를 지정하는 일.
	public Student(String name, String school) {
		super(name);
		this.school = school;
	}
			

	public String getSchool() {
		return school;
	}


	public void setSchool(String school) {
		this.school = school;
	}
public class Alba extends Student {
	
	// 필드
	private String company;
	
	// 생성자
	public Alba(String name, String school, String company) {
		super(name, school);
		this.company = company;
	}

	// get,set
	public String getCompany() {
		return company;
	}

	public void setCompany(String company) {
		this.company = company;
	}
public class StudentMain {

	public static void main(String[] args) {

		Student student = new Student("tom", "goodee");
		
		System.out.println(student.getName());
		System.out.println(student.getSchool());
		
		System.out.println();
		
		Alba alba = new Alba("Jessica", "seoul univ", "library");
		
		System.out.println(alba.getName());
		System.out.println(alba.getSchool());
		System.out.println(alba.getCompany());

	}

▶ 메소드 오버라이딩(Method Overriding) 

1. 메소드 덮어쓰기

2. 슈퍼클래스의 메소드를 서브클래스에서 재정의하는 것.

3. 슈퍼클래스의 메소드를 서브클래스가 사용하지 못하는 경우 메소드 오버라이딩이 필요함.

4. 반드시 슈퍼클래스의 메소드와 동일한 원형(반환타입, 메소드명, 매개변수)으로 만들어야 함.

5. 오버라이드 된 메소드 앞에는 @ Override 에너테이션을 작성해서 오버라이드 된 메소드임을 알림.

* @ override (@ : 에너테이션 = 사람한테 알려주는게아니라 java한테 알려주는거다.)

 - java가 규칙에 맞게 했는지 검사 해 줌. (부모클래스의 메소드와 동일한 형인지) (오류검사)

* ctrl + space bar를 서브클래스에서 누르면 자동으로 오버라이드가 생김.

public class Coffee {
	
	// 커피 원두를 의미함
	
	public void taste() {
		
	}
public class Espresso extends Coffee {
	@Override		
    
    // override를 안했을때 taste가 오타가 난 경우, 오류인식을 안함.
    // @override를 안해도 자동 override가 되지만, 권장하지 않음. 오류를 잡아주지 않기 때문
	
	public void taste() {
		System.out.println("쓰다.");
	}
public class Americano extends Espresso{

	private int extraWater;
	
	@Override
	public void taste() {
		// TODO 해야 할 일을 적어 둠
		System.out.println("덜 쓰다");
	}
public class EspressoMain {

	public static void main(String[] args) {

		Espresso espresso = new Espresso();
		espresso.taste();
		
		Americano americano = new Americano();
		americano.taste();
	}

▶ 업캐스팅(Up-Casting) 

1. 간단하지만 중요한 문법.

2. 서브클래스 객체를 슈퍼클래스 타입으로 변환하는 것.

3. 자동으로 타입이 변환되는 promotion 방식으로 처리됨

4. 업캐스팅된 서브클래스 객체는 슈퍼클래스의 메소드만 호출 가능

 

▶ 업캐스팅과 메소드 오버라이드 

1. 업캐스팅된 서브클래스 객체는 슈퍼클래스의 메소드만 호출할 수 있음

2. 따라서 슈퍼클래스에 서브클래스의 메소드를 정의해 주고 서브클래스가 오버라이드 하는 방식으로 서브클래스의 메소드를 호출함.

public class Person {
	
	public void eat() {
		System.out.println("먹는다.");
	}
	
	// 서브클래스의 메소드. 하는 일은 없어도 된다.
	// Person타입의 객체가 호출할 수 있도록 추가해 둔 메소드
	public void study() {}			// 모든 사람이 공부하는건 아니기 때문에 빈칸
	public void work() {}

}
public class Student extends Person {
	
	@Override
	public void study() {
		System.out.println("공부한다");	
		}
public class Alba extends Student {
	
	@Override
	public void work() {
		System.out.println("일한다.");
	}
public class Main {

	public static void main(String[] args) {
		
		// Up Casting
		// 자식은 언제나 부모타입으로 저장 할 수 있다.
		// 슈퍼클래스 객체 = new 서브클래스();
		
		Person alba = new Alba();
		alba.eat();	
		alba.study();
		alba.work();
     		// 실행은 Person의 메소드 실행, 그 뒤에 new Alba를 보고 Alba 메소드 출력
		
		
		// 이와같이 구성해야 하는 이유..?
		// new Student()와 new Alba()는 모두
		// Person 타입으로 처리할 수 있다.
		
		// 한 교실에 Student와 Alba가 섞여 있다.
		// 어떻게 처리할 것인가?
		// Person 타입의 배열을 이용해서 모두 처리할 수 있다.
		
		System.out.println();
		
		// 아래는 예시
		Person[] people = new Person[10];
		
		people[0] = new Alba();
		people[1] = new Alba();
		people[2] = new Student();
		
		for(int i = 0; i < people.length; i++) {
			if(people[i] != null) {
			people[i].eat();
			people[i].study();
			people[i].work();			// student는 일 안함.
			System.out.println();
			}
		}
		
		// 위와 동일한 코드. 향상 for문...
		for(Person person : people) {
			if(person != null) {
				person.eat();
				person.study();
				person.work();
			}
		}


	}

▶ 다운캐스팅(Down-Casting) 

1. 업캐스팅 된 서브클래스 객체를 다시 서브클래스 타입으로 변환하는 것.

2. 강제로 타입을 변환하는 casting 방식으로 처리해야 함

3. 업캐스팅의 문제를 해결하기 위한 또 다른 방법임

** 캐스팅은 항상 조심히 써야함. 무조건 바꿔주기 때문에.. (캐스팅은 오류를 못찾는다)

 

▶ instanceof 연산자

1. 특정 인스턴스가 어떤 클래스타입인지 점검하는 연산자
2. 어떤 클래스타입인지 점검을 해서, 해당 클래스 타입이면 true 반환, 아니면 false 반환

public class Person {

	public void eat() {
		System.out.println("먹는다.");
	}
public class Student extends Person {
	
	public void study () {
		System.out.println("공부한다.");
	}
public class Alba extends Student {

	public void work() {
		System.out.println("일한다.");
	}
	public static void main(String[] args) {

		// 클래스타입 : Person
		// 객체(인스턴스) : p
		
		Person p = new Alba();		// 업캐스팅
		Person s = new Student();
		
		// instanceof 연산자
		// 특정 인스턴스가 어떤 클래스타입인지 점검하는 연산자
		// 어떤 클래스타입인지 점검을 해서, 해당 클래스 타입이면 true 반환, 아니면 false 반환

		System.out.println(p instanceof Person);
		System.out.println(p instanceof Student);
		System.out.println(p instanceof Alba);
		
		System.out.println(s instanceof Person);
		System.out.println(s instanceof Student);
		System.out.println(s instanceof Alba);
		
		
		
		// s가 Student타입의 인스턴스이면 study() 메소드를 호출할 수 있다.
		if(s instanceof Student) {	// student가 맞다면 study를 호출할 수 있다.
			((Student) s).study();	// s. 하고 자동완성하면 복잡한 문구가 완성. 이것이 다운캐스팅 이다.
									// s를 먼저 Student로 다운캐스팅 하고, 스터디 호출
		}
반응형