[혼공자] 4주차_07

다율·2024년 1월 26일
0

2024 혼공자

목록 보기
5/7
post-thumbnail

기본 미션: 클래스의 타입 변환에는 어떤 것이 있는지 정리하고 공유하기

  • 자동 타입 변환, 강제 타입 변환이 있고 본문에 자세히 정리해보겠습니다!

07 상속

07-1 상속

  • 이미 개발된 클래스를 재사용해서 새로운 클래스를 만들기 때문에 중복되는 코드와 모델링하는 시간을 줄여줌

1) 클래스 상속

  • 자식(클래스)이 부모(클래스)를 선택함
  • 자식 클래스를 선언할 때 상속받을 부모클래스를 extends 뒤에 작성
  • 자식 클래스는 자신의 필드와 메소드 뿐만 아니라 부모 클래스의 필드와 메소드 등 사용이 가능함
class 자식클래스 extends 부모클래스 {
	
    // 필드, 생성자, 메소드
    
}

자바에서 상속의 특징

  1. 다중상속을 허용하지 않아 여러개의 부모클래스를 상속받을 수 없음 (단 한개)
  2. 부모클래스 중 private 접근 제한을 갖는 필드와 메소드는 상속 대상에서 제외,
    마찬가지로 부모와 자식클래스가 다른 패키지에 존재한다면 default 접근 제한을 갖는 필드와 메소드도 제외됨

2) 부모 생성자 호출

  • 자식 객체 생성 시, 자식 생성자의 맨 첫줄에서 호출되어 부모 객체가 먼저 생성되고 자식 객체가 생성됨
  • 기본 생성자의 경우, 컴파일러는 자식 생성자 첫줄super()부모의 기본 생성자를 호출함
// 예시
// 부모(상위) 클래스
public class People {
	
	public String name;
	public String ssn;
	
	public People(String name, String ssn) {
		this.name = name;
		this.ssn = ssn;
	}
}


// 자식(하위) 클래스
public class Student extends People {
	public int studentNo;
	
	public Student(String name, String ssn, int studentNo) {
		super(name, ssn);		// 부모클래스의 생성자를 호출
		this.studentNo = studentNo;
	}
}

3) 메소드 재정의

  • 자식 클래스에서 부모 클래스의 메소드를 다시 정의하는 것 (메소드 오버라이딩)
  • 재정의한 메소드는 호출하면 재정의된 자식 메소드가 호출됨

메소드 재정의 방법 : 규칙

  1. 부모의 메소드와 동일한 시그너처(리턴 타입, 메소드 이름, 매개변수 목록)을 가져야 함
  2. 접근 제한을 더 강하게 재정의 할 수 없음 (public -> default 안됨)
  3. 새로운 예외(Exception)를 throws 할 수 없음
// 예시
// 부모 클래스
public class Calculator {
	double areaCircle(double r) {
		System.out.println("Calculator 객체의 areaCircle() 실행");
		return 3.14159 * r * r;
	}
}

// 자식 클래스
public class Computer extends Calculator {
	@Override	// @Override 어노테이션은 생략 가능하지만 메소드가 정확히 재정의 된 것인지 컴파일러가 확인하므로 실수를 줄여줌
	double areaCircle(double r) {
		System.out.println("Computer 객체의 areaCircle() 실행");
		return Math.PI * r * r;		// 자바 표준 API
	}
}

부모 메소드 호출

  • 자식 클래스 내부에서 부모 클래스에 있는 메소드를 호출할 때 사용
  • super.부모메소드() 형태
	@Override
	public void fly() {
		if(flyMode == SUPERSONIC) {
			System.out.println("초음속 비행합니다.");
		}
		else {
			super.fly();	// 부모 클래스에 있는 메소드 실행
		}

4) final 클래스와 final 메소드

상속할 수 없는 final 클래스

  • 최종적인 클래스이므로 상속할 수 없는 클래스가 됨
public final class 클래스이름 {   . . .   }

재정의할 수 없는 final 메소드

  • 최종적인 메소드이므로 재정의할 수 없는 메소드가 됨
public final 리턴타입 메소드([매개변수, ...]) {   . . .   }

(+) protected 접근 제한자

  • 같은 패키지, 자식 클래스만 접근 허용

07-2 타입 변환과 다형성

  • 다형성이란? : 사용방법은 동일하지만 다양한 객체를 이용하여 다양한 실행결과가 나오도록 하는 성질 (메소드 재정의 + 타입 변환 = 다형성)

1) 자동 타입 변환

  • 프로그램 실행중에 자동적으로 타입 변환이 일어나는 것
  • 클래스에도 상속관계에 있는 클래스 사이에서 발생
  • 바로 위의 부모가 아니더라도 상속 계층에서 상위타입일 경우 가능

    자식 -> 부모 타입으로 자동변환 가능

  • 변환된 이후에는 부모 클래스에 선언된 필드와 메소드만 접근 가능 (재정의 된 메소드는 아님)

2) 필드의 다형성

  • 필드의 타입을 부모 타입으로 선언하면 다양한 자식 객체들이 저장될 수 있기 때문에 결과(메소드 호출 등)가 다를 수 있는 것
    (예: 자동차의 더 좋은 타이어로 교체)

3) 매개 변수의 다형성

  • 메소드 호출 시, 매개값을 다양화하기 위해 매개변수에 자식 객체를 저장하는 것
  • 메소드 실행결과가 다양해질 수 있다는 것 (부모 메소드를 자식 객체가 재정의 했다면)
void 메소드이름(자식 객체) {
	자식객체.메소드();		// 자식 객체가 재정의한 메소드 실행
}

// 예시
public class DriverExample {

	public static void main(String[] args) {
		
		Driver dri = new Driver();
		Bus bus = new Bus();
		Taxi taxi = new Taxi();
		
		
		// 자동 타입 변환
		
		dri.drive(bus);
		// Vehicle vehicle = bus; 자식 객체의 메소드 실행
		
		dri.drive(taxi);
		// Vehicle vehicle = taxi; 자식 객체의 메소드 실행

	}

}

4) 강제 타입 변환

  • 부모 타입자식 타입으로 변환하는 것을 뜻함
  • 자식 타입 -> 부모타입 -> ( 강제 타입 변환 ) -> 자식 타입
  • 다시 자식의 필드와 메소드를 쓰고 싶다면 사용
Parent par = new Child();	// 자동 타입 변환 (자식 -> 부모)
Child chi = (Child) par;	// 강제 타입 변환 (부모 -> 자식)

// 예시
public class ChildExample1 {

	public static void main(String[] args) {
		
		Parent1 par1 = new Child1();
		par1.field1 = "data1";
		par1.method1();
		par1.method2();
		
//		부모 클래스 안에 있는 것만 사용 가능 (자동 타입 변환)
//		par1.field2 = "data2";
//		par1.method3();
		
		Child1 chi1 = (Child1) par1;	// 강제 타입 변환
		chi1.field2 = "yyy";
		chi1.method3();
		
	}

}

5) 객체 타입 확인

  • 처음부터 부모 타입으로 생성된 객체는 자식 타입으로 변환할 수 없음 (자식 타입이 부모 타입으로 변환되어 있는 상태에서만 가능)
Parent par = new Parent();
Child chi = (Child) par;	// 불가능

instanceof 연산자 사용하기

  • 객체가 어떤 클래스의 인스턴스인지 확인하기 위해 사용
  • 좌항의 객체가 우항의 타입으로 생성된 객체라면 true, 아니면 false를 return함
	boolean result = 좌항(객체) instanceof 우항(타입)
    
// 예시
public static void method1(Parent par) {
		if(par instanceof Child) {
			Child chi = (Child) par;
			System.out.println("method1 - Child로 변환 성공");
		}
		else {
			System.out.println("method1 - Child로 변환 실패");
		}
	}

07-3 추상 클래스

  • 객체를 직접 생성할 수 있는 실체 클래스들의 공통적인 특성(필드, 메소드)을 추출해 선언한 클래스
  • 실체 클래스와 상속 관계

1) 추상 클래스의 용도

1. 공통된 필드와 메소드의 이름을 통일할 목적

  • 이름이 달라 객체마다 사용방법이 달라지는 것을 방지함

2. 실체 클래스를 작성할 때 시간 절약

  • 공통적인 것들은 추상 클래스에 선언하고, 다른 점만 실체 클래스에 선언하므로 시간 절약

2) 추상 클래스 선언

  • abstract 키워드를 붙여야 함 (붙이면 new 연산자를 이용해 객체를 만들지 못하고 상속으로 자식 클래스만 만들 수 있음)
  • 필드, 생성자, 메소드 선언 가능

    상속받은 자식 클래스에서 객체를 생성할 때 super()를 호출해서 추상 클래스 객체를 먼저 생성하므로 생성자 필수

// 추상 클래스
public abstract class Phone {
	
	// 필드
	public String owner;
	
	// 생성자
	public Phone(String owner) {
		this.owner = owner;
}


// 자식 클래스
public class SmartPhone extends Phone{

	// 생성자
	public SmartPhone(String owner) {
		super(owner);
}	

3) 추상 메소드와 재정의

  • 추상 메소드란 abstract 키워드와 함께 메소드의 선언부만 있고 실행내용인 { }가 없는 메소드
  • 자식 클래스에서 반드시 재정의해야 함
[public | protected] abstract 리턴타입 메소드이름(매개변수, ...) 

깃허브 링크

https://github.com/dayul/SelfStudy_Java

profile
새싹 개발자 🌱

0개의 댓글