티스토리 뷰
7.1 상속 개념
- 부모 클래스의 필드와 메소드를 자식 클래스에게 물려줄 수 있음
- 잘 개발된 클래스를 재사요해서 새로운 클래스를 만들기 때문에 중복 코드를 줄일 수 있음
- 부모 클래스만 수정하면 되기 때문에 수정을 최소화할 수 있음
7.2 클래스 상속
- 자식이 상속 받으려고 하는 부모 클래스를 선택
- 다중 상속을 허용하지 않음
7.3 부모 생성자 호출
자식 객체를 생성하면 부모 객체가 먼저 생성된 다음에 자식 객체가 생성 된다.
부모 생성자는 자식 생성자의 맨 첫줄에 숨겨져 있는 super() 에 의해 호출된다.
public class SmartPhoneDemo {
public static void main(String[] args) {
SmartPhone smartPhone = new SmartPhone("아이폰", "은색");
System.out.println(smartPhone.color); // 은색 출력
// 부모 메서드 호출
smartPhone.bell();
// 자식 메서드 호출
smartPhone.internet();
}
}
// 부모 클래스
class Phone {
public String model;
public String color;
// 기본 생성자는 암묵적으로 제공
public void bell(){
System.out.println("벨이 울립니다");
}
}
// Phone를 상속 받은 자식 클래스
class SmartPhone extends Phone {
public boolean wifi;
// 부모 클래스에서 상속받은 필드로 생성자 선언
public SmartPhone(String model, String color) {
// 기본 생성자만 있을 경우 super() 생략 가능 컴파일러가 자동으로 추가
this.model = model;
this.color = color;
}
public void internet(){
System.out.println("인터넷 연결합니다");
}
}
// 부모 클래스
class Phone2 {
public String model;
public String color;
// 부모 클래스에 매개변수가 있는 생성자가 있을 경우
public Phone2(String model, String color) {
this.model = model;
this.color = color;
}
}
// Phone를 상속 받은 자식 클래스
class SmartPhone2 extends Phone2 {
public boolean wifi;
public SmartPhone2(String model, String color) {
// 부모 클래스에 매개변수가 있는 생성자가 있을 경우에는 반드시 호출해줘야 한다.
super(model, color);
}
}
7.4 메소드 재정의
메소드 오버라이딩
- 부모 클래스의 메소드를 자식 클래스에서 재정의해서 사용하는 것
- 메소드가 오버라이딩 되었다면 해당 부모 메소드는 숨겨지고 자식 메소드가 우선적으로 사용
- 부모 메소드의 선언부(리턴 타입, 메소드 이름, 매개변수) 동일
- 접근 제한을 더 강하게 오러바이딩할 수 없음 (public -> private 변경 불가)
- 새로운 예외를 throws할 수 없음
public class OverridingDemo {
public static void main(String[] args) {
Child child = new Child();
child.method1(); // 부모 메소드 1 출력
child.method2(); // 자식 메소드 2로 오버라이딩 출력
}
}
class Parent {
public void method1(){
System.out.println("부모 메소드 1");
}
public void method2(){
System.out.println("부모 메소드 2");
}
}
class Child extends Parent {
@Override // 컴파일 시 정확히 오버라이딩 되었는지 체크해주며 생략 가능
public void method2() {
System.out.println("자식 메소드 2로 오버라이딩");
}
}
부모 메소드 호출
- 부모 메소드의 일부만 변겨된다 하더라도 중복된 내용을 자식 메소드도 가지고 있어야 한다.
- super. 사용하면 숨겨진 부모 메소드를 호출할 수 있음
7.5 final 클래스와 final 메소드
- 클래스를 선언할 때 final를 사용하면 더 이상 상속할 수 없는 클래스가 된다. -> 자식 클래스를 만들 수 없음
- 메소드를 선언할 때 final를 사용하면 오버라이딩할 수 없는 메소드가 된다.
7.6 protected 접근 제한자
- 같은 패키지에서는 접근 가능
- 다른 패키지에서는 자식 클래스만 접근 가능
- 단 다른 패키지에서는 new연산자를 사용해 생성자를 직접 호출할 수는 없고 super()를 사용해야 한다.
7.7 타입 변환
자동 타입 변환: 부모 타입 변수 = 자식 타입 객체
- 자식은 부모의 특징과 기능을 상속 받기 때문에 부모와 동일하게 취급될 수 있음
- 바로 위의 부모가 아니더라도 상속 계층에서 상위 타입이라면 자동 타입 변환 가능
- 부모 타입으로 자동 타입 변환된 이후에는 부모 클래스에 선언된 필드와 메소드만 사용 가능
- 그러나 자식 클래스에서 오버라이딩된 메소드가 있다면 부모 메소드 대신 오버라이딩된 자식 메소드가 호출 된다.
package beginnerJava.src.ch07;
public class ChildDemo {
public static void main(String[] args) {
// 자식 객체 생성
Child2 child2 = new Child2();
// 부모 타입으로 자동 타입 변환
Parent2 parent2 = child2;
parent2.method1(); //부모 메소드 1 출력
parent2.method2(); //자식 메소드 2로 오버라이딩 출력
// 호출 불가능
// parent2.method3();
}
}
class Parent2 {
public void method1(){
System.out.println("부모 메소드 1");
}
public void method2(){
System.out.println("부모 메소드 2");
}
}
class Child2 extends Parent2 {
@Override
public void method2() {
System.out.println("자식 메소드 2로 오버라이딩");
}
public void method3(){
System.out.println("자식 메소드 3");
}
}
강제 타입 변환: 자식 타입 변수 = (자식 타입) 부모 타입 객체
- 부모 타입은 자식 타입으로 자동 변환되지 않고 자식 타입의 캐스팅 연산자를 사용해 강제 타입 변환을 할 수 있음
- 자식 객체가 부모 타입으로 자동 변환된 후 다시 자식 타입으로 변환될 때 강제 타입 변환 사용 가능
package beginnerJava.src.ch07;
public class ChildDemo2 {
public static void main(String[] args) {
// 부모 타입으로 자동 타입 변환
Parent3 parent3 = new Child3();
parent3.method1();
parent3.method2();
// 자식 타입 메소드 사용 불가능
// parent3.method3();
// 자식 타입으로 강제 타입 변환
Child3 child3 = (Child3) parent3;
// 자식 타입 메소드 사용 가능
child3.method3();
}
}
class Parent3 {
public void method1(){
System.out.println("부모 메소드 1");
}
public void method2(){
System.out.println("부모 메소드 2");
}
}
class Child3 extends Parent3 {
@Override
public void method2() {
System.out.println("자식 메소드 2로 오버라이딩");
}
public void method3(){
System.out.println("자식 메소드 3");
}
}
7.8 다형성
- 다형성이란 사용 방법은 동일하지만 실행 결과가 다양하게 나오는 성질
- 자동 타입 변환 + 메소드 오버라이딩 -> 다형성
필드 다형성
- 필드 타입은 동일하지만 (사용 방법은 동일하지만)
- 대입되는 객체가 달라져서 실행 결과가 다양하게 나올 수 있는 것
public class CarDemo {
public static void main(String[] args) {
Car hankookCar = new Car();
hankookCar.tire = new HankookTire();
Car kumhoCar = new Car();
kumhoCar.tire = new HankookTire();
// run() 함수를 호출하는 것은 한국도 금호도 동일하다. (사용 방법 동일)
// 하지만 대입되는 객체가 다르기 때문에 실행 결과가 다르게 나온다. (실행 결과 다름)
hankookCar.run(); // 한국타이어가 회전 출력
kumhoCar.run(); // 금호타이어가 회전 출력
}
}
class Car {
Tire tire;
public void run(){
tire.roll();
}
}
class Tire {
public void roll(){
System.out.println("타이어가 회전");
}
}
class HankookTire extends Tire {
@Override
public void roll() {
System.out.println("한국 타이어가 회전");
}
}
class KumhoTire extends Tire {
@Override
public void roll() {
System.out.println("금호 타이어가 회전");
}
}
메서드 다형성
- 메소드가 클래스 타입의 매개변수를 가지고 있을 때,
- 매개 변수 타입의 자식 객체를 제공할 수도 있다는 것 = 어떤 자식 객체를 제공하냐에 따라 실행 결과가 달라짐
public class DriverDemo {
public static void main(String[] args) {
Driver busDriver = new Driver();
Bus bus = new Bus();
Driver taxiDriver = new Driver();
Taxi taxi = new Taxi();
// 똑같은 Vehicle 타입을 매개변수로 삼고 있지만
// bus 객체냐 taxi 객체냐에 따라 그 실행 결과가 달라지는 것
busDriver.drive(bus); // 버스가 달립니다 출력
taxiDriver.drive(taxi); // 택시가 달립니다 출력
}
}
class Driver {
public void drive(Vehicle vehicle) {
vehicle.run();
}
}
class Vehicle {
public void run(){
System.out.println("달립니다");
}
}
class Bus extends Vehicle {
@Override
public void run() {
System.out.println("버스가 달립니다");
}
}
class Taxi extends Vehicle {
@Override
public void run() {
System.out.println("택시가 달립니다");
}
}
7.9 객체 타입 확인
- instanceof 연산자: 변수가 참조하는 객체의 타입을 확인하고자 할 때 사용
public class InstanceofDemo {
public static void personInfo(Person person) {
System.out.println("이름은 " + person.name);
if (person instanceof Student) {
System.out.println("이 사람은 학생입니다");
}
}
public static void main(String[] args) {
Person person = new Person("김자바");
personInfo(person); // 이름은 김자바 까지만 출력
Student student = new Student("이학생", "1234567890");
personInfo(student);
//이름은 이학생
//이 사람은 학생입니다 2 줄 출력
}
}
class Person {
public String name;
public Person(String name) {
this.name = name;
}
}
class Student extends Person {
public String number;
public Student(String name, String number) {
super(name);
this.number = number;
}
}
7.10 추상 클래스
- 추상: 실체 간에 공통되는 특성을 추출한 것
- 실체 클래스: 객체를 생성할 수 있는 클래스
추상 클래스
- 추상 클래스: 실체 클래스의 공통적인 필드나 메소드를 추출해서 선언한 클래스로 실체 클래스의 부모 역할
- 추상 클래스는 new연산자를 사용해서 객체를 직접 생성할 수 없음
- 부모 클래스로만 사용 = extends 뒤에만 올 수 있음 = 상속을 통해 자식 클래스만 만들 수 있음
- abstract 키워드 사용
- 필드, 메소드, 생성자 선언 가능
추상 메소드
- 메소드 선언부(리턴 타입, 메소드명, 매개변수)만 동일하고 실행 내용은 자식 클래스마다 달라야 하는 경우 있음
- 이런 경우를 위해서 추상 클래스는 추상 메소드 선언 가능
- abstract 키워드 사용하고 {} 가 없음 = 실행 내용은 없음 -> 따라서 자식 클래스에서 반드시 오버라이딩해서 실행 내용을 채워야 한다.
public class AbstractDemo {
public static void main(String[] args) {
Dog dog = new Dog();
dog.breathe();
dog.sound();
Cat cat = new Cat();
cat.breathe();
cat.sound();
}
}
// 추상 클래스
abstract class Animal {
String name;
public void breathe(){
System.out.println("숨을 쉽니다");
}
// 추상 메소드로 animal의 공통 메소드
abstract void sound();
}
class Dog extends Animal {
// 실제로 각각의 객체에서 어떻게 사용할지는 오버라이딩을 통해 정해진다
@Override
void sound() {
System.out.println("멍멍");
}
}
class Cat extends Animal {
@Override
void sound() {
System.out.println("냥냐");
}
}
7.11 봉인된 클래스
- final 클래스를 제외한 모든 클래스는 부모 클래스가 될 수 있음
- 무분별한 자식 클래스 생성 방지를 위해 sealed 클래스 도입
public class SealedDemo {
}
// Person2는 Employee와 Manager에만 상속할 수 있음 = 다른 클래스에는 상속 불가
sealed class Person2 permits Employee, Manager {
}
// student클래스는 상속을 받을 수 없음
// class Student extends Person2 {}
// 더 이상 상속 할 수없음
final class Employee extends Person2{
}
// 봉인을 해제하고 상속할 수 있음
non-sealed class Manager extends Person2 {
}
class Director extends Manager {
}
'도서 및 강의 > 이것이 자바다' 카테고리의 다른 글
이것이 자바다 3판 챕터 9 (0) | 2024.09.18 |
---|---|
이것이 자바다 3판 챕터 8 (2) | 2024.09.17 |
이것이 자바다 3판 챕터 6 (0) | 2024.08.26 |
이것이 자바다 3판 챕터 5 (0) | 2024.08.25 |
이것이 자바다 3판 챕터 4 (0) | 2024.08.25 |
최근에 올라온 글