7. 상속

7.7 타입변환

매우 중요한 파트!

타입변환이란 타입을 다른 타입으로 변환하는 것을 말한다. 기본타입 변환은 2장에서 학습한 바잇다
클래스도 마찬가지로 타이변환이 잇는데 클래스의 타입변환느은 상속관계에 잇는 클래스 사이에서 발생한다.

7.7.1 자동타입변환

자동 타입 변환은 의미그대로 자동적으로 타입이 변환되는 것을 의미함.
부모타입 변수 = 자식타입 객체; / 원래는 넓은 범위 = 좁은 범위 부모=넓음 자식=좁은 이라고 생각
예를들어 Animal var = new Dog(){} 이 됨
Cat cat = new Cat(); //자식객체만들면 부모객체도 생성됨 이용
Animal animal = cat; 사진참조 //둘다 cat을 참조하게 되는거임.
cat == animal true

public class PromotionExample {

public static void main(String[] args) {
    B b = new B();
    C c = new C();
    D d = new D();
    E e = new E();

    A a1 = b; // 자동 타입 변환 (상속관계에있음)
    A a2 = c;
    A a3 = d;
    A a4 = e;

    B b1 = d;
    C c1 = e;

    //B b3 = e; 상속관계에 있지 않아 에러
    //C c2 = d;

부모 타입으로 자동 타입 변환된 이후에는 부모 클래스에 선언된 필드와 메소드만 접근 가능하다.
비록 변수는 자식 객체를 참조하지만 변수로 접근 가능한 멤버는 부모클래스 멤버로 한정된다.
그러나 자식클래스에서 오버라이딩된 메소드가 잇다면 부모 메소드 대신 오버라이딩된 메소드가 호출된다. 이것은 '다형성' 과 관련되어 있기 때무에 잘알아야한다.
타입변환을 했음에도 불구하고 오버라이딩된게 실행된다.

package ch07.sec07.exam2;

public class Parent {
//메소드 선언
public void method1() {
    System.out.println("Parent-method1()");
}

public void method2() {
    System.out.println("Parent-method2()");
}
}

package ch07.sec07.exam2;

public class Child extends Parent{

//메소드 오버라이딩
@Override
public void method2() {
    System.out.println("Child-method2()");
}

//메소드 선언
public void method3() {
    System.out.println("Child-method3()");
}

package ch07.sec07.exam2;

public class ChildExample {

public static void main(String[] args) {
    // 자식객체 생성
    Child child = new Child();

    //자동타입변환
    Parent parent = child;

    //메소드 호출
    parent.method1();
    parent.method2();
    //parent.method3(); 호출불가능 parent타입이기때문에 사용불가.
    }
}

7.7.2 강제타입변환

자식타입은 부모 타입으로 자동변환되지만 반대로 부모 타입은 자식 타입으로 자동벼환안되지만 캐스팅 연산자로 강제 타입 변환이 가능하다.
자식타입 변수 = (자식타입) 부모타입객체;
(캐스팅연산자)
무조건 가능한 것은 아니고 자식 객체가 부모 타입으로 자동변환된후 다시 자식 타입으로 변환할때 강제 타입 변환을 사용할 수 잇다.
Parent parent = new Child(); // 자동타입변환
Child child = (Child) parent(); //강제 타입 변환
자식객체가 부모타입으로 자동변환되면 부모 타입에 선언된 필드와 메소드만 사용가능하다는 제약사항이 생김.
만약 자식타입에 선언된 필드와 메소드를 꼭 사용해야한다면 강제타입 변환을 행한다.

package ch07.sec07.exam3;

public class Parent {

//필드선언
public String field1;

//메소드 선언
public void method1() {
    System.out.println("Parent-method1()");
}

public void method2() {
    System.out.println("Parent-method2()");
}
}

package ch07.sec07.exam3;

public class Child extends Parent{

//필드선언
public String field2;

//메소드 선언
public void method3() {
    System.out.println("Child-method3()");
}

package ch07.sec07.exam3;

public class ChildExample {

public static void main(String[] args) {
// 객체 생성 및 자동타입변환
Parent parent = new Child();

//Parent 타입으로 필드와 메소드 사용
parent.field1 = "data1";
parent.method1();
parent.method2();

//parent.field2 = "data2"; // 자식꺼라 불가능
//parent.method3() // 자식꺼라 불가능

//강제타입변환
Child child = (Child) parent;

//Child 타입으로 필드와 메서드 사용
child.field2 = "data2";
child.method3();
}
}

7.8 다형성

매우중요! 자바프로젝트에서 매우 많이나옴. 완전히 이해필요

메소드 재정의, 타입변환을 잘 이해해야함.
다형성이란 사용방법은 동일하지만 식행 결고가 다양하게 나온느 성질을 말한다.
자동차 의 부품을 교환하면 성능이 다르게 나오듯이 객체느느 부품과 같아서 프로그램을 구성하는 객체를 바구면 프로그램이 실행성능이 다르게 나올수잇다.

다형성을 위해서는 상속이 필요하다. 부수적으로 메소드 재정의와 타입변환
자동차 - 타이어 대입 가능 자식객체 만들어서 대입해도 됨.
자동차 -자식타이어 자동차 -자식타이어 가능
다형성을 위해서는 자동타입변환과 메소드 재정의가 필요하다.


위그림에서 한국타이어와 금호타이어는 타이어타입(부모)으로 자동 타입 변환이 될수잇고 타이어와 메소드를 재정의하고잇다.

7.8.1 필드다형성

필드 다형성은 필드타입은 동일하지만(사용방법은 동일하지만) 대입되는 객체가 달라져서 실행결고가 다양하게 나올수있는것을 말한다.
Car 클래스에 Tire필드가 선언되어있다.
먼저 Car 객체를 생성한후 타이어를 장착하기 위해 다음과 같이 한국과 금호를 tire필드에 대입할수잇다.

package ch07.sec08.exam01;

public class Car {
//필드선언
public Tire tire; //tire라는 변수 선언 -> Tire를 정의해주기 위해 Tire객체 만듬

//메소드 선언
public void run()
{
    //타이어 객체의 roll()메소드 호출
    tire.roll();
}
}

package ch07.sec08.exam01;

public class Tire {
//메소드선언
public void roll()
{
    System.out.println("회전합니다.");
}
}

package ch07.sec08.exam01;

public class HankookTire extends Tire{

//메소드 오버라이딩
@Override
public void roll() {
    System.out.println("한국 타이어가 회전합니다.");
}
}

package ch07.sec08.exam01;

public class KumhoTire extends Tire {
//메소드 정의
@Override
public void roll() {
    System.out.println("금호타이어가 회전합니다.");
}
}

package ch07.sec08.exam01;

public class CarExample {
public static void main(String[] args) {
// car객체생성
Car myCar = new Car();

//car객체 밑에 tire필드값있는데 null로 되잇음 tire에 일반타이어 장착
//Tire 객체생성
myCar.tire = new Tire(); 
myCar.run();

//HankookTire 객체 장착
myCar.tire = new HankookTire();
myCar.run();

//KumhoTire 객체 장착
myCar.tire = new KumhoTire();
myCar.run();
}
}

7.8.2 매개변수 다형성

다형성은 필드보다는 메소드를 호출할때 많이 발생한다. 메소드가 클래스타입의 매개변수를 가지고잇을경우
호출할때 도일한 타이븨 객체를 제공하는 것이 정석이지만 자식 객체를 제공할수도잇다. 여기서 다형성이 필요하다.

package ch07.sec08.exam02;

public class Vehicle {
//메소드 선언
public void run()
{
    System.out.println("차량이 달립니다.");
}
}

 package ch07.sec08.exam02;

public class Bus extends Vehicle {
//메소드 재정의(오버라이딩)
@Override
public void run() {
    System.out.println("버스가 달립니다.");
}
}

 package ch07.sec08.exam02;

public class Taxi extends Vehicle{
//메소드 재정의
@Override
public void run() {
    System.out.println("택시가 달립니다.");
}
}

package ch07.sec08.exam02;

public class Driver {
//메소드 선언 (클래스 타입의 매개변수를 가지고있음.)
public void drive(Vehicle vehicle)
{
    vehicle.run();
}
  }

 package ch07.sec08.exam02;

public class DriverExample {
public static void main(String[] args) {
//드라이버 객체생성
Driver driver = new Driver();

//매개값으로 Bus객체를 제공하고 driver()메소드 호출
Bus bus = new Bus();
driver.drive(bus);

//매개값으로 Taxi객체를 제공하고 driver()메소드 호출
Taxi taxi = new Taxi();
driver.drive(taxi);
}
}

7.9 객체 타입 확인

매개변수의 다형성에서 실제로 어떤 객체가 매개값으로 제공되었는지 확인하는 방법이있다.
꼭 매게변수가 아니더라도 변수가 참조하는 객체의 타입을 확인하고자 할때 instanceof연산자를 사용할수있다.
boolean result = 객체 instanceof 타입;
Bus bus = new Bus();
Vehilcle v = bus;
v instanceof Bus v라는 변수가 참조하는 객체가 Bus타입으로 만든 객체냐? -> true임.

   package ch07.sec09;

public class Person {
    //필드선언
    public String name;

    //생성자선언
    public Person (String name)
    {
        this.name = name;
    }

    //메소드 선언
    public void walk()
    {
        System.out.println("걷습니다.");
    }
}

package ch07.sec09;

public class Student extends Person{
//필드선언
public int studentNo;

//생성자선언
public Student (String name, int studentNo)
{
    super(name);
    this.studentNo = studentNo;
}

//메소드 선언
public void study()
{
    System.out.println("공부를 합니다.");
}
}

package ch07.sec09;

public class InstanceofExample {

//main()메소드에서 바로 호출하기 위해 정적 메소드 선언
public static void personInfo(Person person)
{
    System.out.println("name: " + person.name);
    person.walk();

    if (person instanceof Student)
    {
        //Student 객체일경우 강제 타입 변환
        Student student = (Student) person;
        //Student 객체만 가지고있는 필드 및 메소드 사용
        System.out.println("studentNo: " + student.studentNo);
        student.study();
    }

    /* person이 참조하는 객체가 Student타입일경우
       student 변수에 대압(타입변환발생) 자바12부터 사용가능
     if (person instanceof Student student)
     {
         System.out.println("studentNo: " + student.studentNo);
        student.study();
     }
     */
}

public static void main(String[] args) {

    //Person 객체를 매개값으로 제공하고 personinfo()메소드 호출
    Person p1 = new Person("홍길동");
    personInfo(p1);

    System.out.println();

    //Student 객체를 매개값으로 제공하고 personinfo()메소드 호출
    Person p2 = new Student("홍길동", 10);
    personInfo(p2);
}

}

7.10 추상클래스

추상이란 실체가 아닌것? 실체 간에 공통되는 특성을 추출한 것을 의미한다.
추상클래스란? 객체를 생성할 수 있는 클래스를 실체 클래스라고 한다면 이 클래스들의 공통적인 필드나 메소드를 추출해서 선언한 추상클래스라고 한다.
추상클래스는 실체클래스의 부모 역할을 한다. 따라서 실체클래스는 추상클래스를 상속해서 공통적인 필드나 메소드를 물려받을수있다.
A B C를 먼저 만들었더니 겹치는게 잇음. 겹치는 것만 모아서 추상클래스로 부모를 만들어서 사용하면 좀 더 편하다.
보통은 부모가 먼저 있고 자식들이 그걸 이용해서 만드는 건데 반대의 상황이 됨.
추상클래스는 새로운 실체 클래스를 만들기 위한 부모 클래스로만 사용된다. 즉 추상 클래스는 extends뒤에만 올 수있다.

7.10.1 추상클래스 선언

클래스 선언에 abstract키워드를 붙이면 추상클래스 선언이 된다. 추상클래스는 new연산자를 이요해서 객체를 직접만들지 못하고 상속을 통해 자식클래스만 만들수잇다.
public abstract class 클래스명 {필드 생성자 메소드}

package ch07.sec10.exam01;

public abstract class Phone {
//필드선언
String owner;

//생성자선언
Phone (String owner)
{
    this.owner = owner;
}

//메소드 선언
void trunOn() {
    System.out.println("폰 전원을 켭니다.");
}
void trunOff() {
    System.out.println("폰 전원을 끕니다.");
}
}

  package ch07.sec10.exam01;

public class SmartPhone extends Phone{
//생성자 선언
SmartPhone(String owner)
{
    //phone생성자 호출
    super(owner);
}

//메소드 선언
void internetSearch()
{
    System.out.println("인터넷 검색을 합니다.");
}
}

 // Phone phone = new Phone(); 불가능
SmartPhone smartphone = new SmartPhone("홍길동");

smartphone.trunOn();
smartphone.internetSearch();
smartphone.trunOff();

7.10.2 추상메소드와 재정의

자식클래스들이 가지고 있는 공통메소드를 뽑아내어 추상클래스로 작성할때 메소드 선언부(리턴타입 메소드명 매개변수)만 동일하고 실행내용은 자식클래스마다 달라야하는 경우가 많다.
예를들어 동물은 소리를 내기때문에 Animal 추상클래스에서 sound()라는 메소드를 선언할싱ㅅ지ㅏㅁㄴ 실행내용은 동물마다 다르기때문에 춧아클래스에서 통일하면안된다.
이런경우를 위해 추상클래스는 다음과 같이 추상메소드를 선언할 수있다.
abstract 리턴타입 메소드명(매개변수, ...);

package ch07.sec10.exam02;

public abstract class Animal {
//메소드 선언
public void breath()
{
    System.out.println("숨을 쉽니다.");
}

//추상 메소드 선언
public abstract void sound();
}

package ch07.sec10.exam02;

public class Cat extends Animal {
//추상메소드 재정의
@Override
public void sound() {
    System.out.println("야옹");
}
}

 package ch07.sec10.exam02;

public class Dog extends Animal {
//추상메소드 재정의
@Override
public void sound() {
    System.out.println("멍멍");
}
}

package ch07.sec10.exam02;

public class AbstractMethodExample {

public static void main(String[] args) {
    Dog dog = new Dog();
    dog.sound();

    Cat cat = new Cat();
    cat.sound();

    //매개변수의 다형성
    animalSound(new Dog());
    animalSound(new Cat());
}
public static void animalSound(Animal animal) //자동타입변환 
{
    animal.sound();
}
}

7.11 봉인된 클래스

자바 15부터 추가가되었음.
무분별한 자식클래스 생성을 방지하기 위해서 생김
final로 걸면 자식 못만드는데? 누구는 부모하고 몇개는 안하고 싶을때?
특정만 제외하고 가능하도록 만든것
public sealed Class Person permits Employee, Manager {}
자식은 final을 붙이거나 sealed를 또 붙임. non-sealed로 봉인을 풀어야함.

package ch07.sec11;

public sealed class Person permits Employee, Manager {
//필드
public String name;

//메소드
public void work()
{
    System.out.println("하는 일이 결정되지 않았습니다.");
}
}

  package ch07.sec11;

public final class Employee extends Person{

@Override
public void work() {
    System.out.println("제품을 생산합니다.");
}
}

package ch07.sec11;

public non-sealed class Manager extends Person {
@Override
public void work() {
    System.out.println("생산 관리를 합니다.");
}
}

package ch07.sec11;

public class Director extends Manager{
@Override
public void work() {
    System.out.println("제품을 기획합니다.");
}
}

Person p = new Person();
Employee e = new Employee();
Manager m = new Manager();
Director d = new Director();

p.work();
e.work();
m.work();
d.work();

2022.11.19 리뷰

공부는 했는데 블로그에 작성하는 것을 잊어 20일 작성한다.
매우 매우 어렵게 느꼈다.
상속이라는 개념 자체는 이해하는데 자동타입변환 등 다양한 개념이 나와서 힘들게 느껴졌다.
오히려 다음 장인 인터페이스를 보고 복습을 하며 정리하니 더 쉽게 느껴지는 것 같다.
클래스와 상속을 연타석으로 공부하고 멘탈이 깨져서 마음이 꺾일뻔했다.
그러나 항상 중요한 것은 꺾이지 않는 마음이다!

'기초단계 > JAVA' 카테고리의 다른 글

2022.11.20-2 JAVA 인터페이스 2  (0) 2022.11.20
2022.11.20-1 JAVA 인터페이스 1  (2) 2022.11.20
2022.11.19-1 JAVA 상속 1  (0) 2022.11.20
2022.11.18-1 JAVA 클래스 4  (0) 2022.11.18
2022.11.17-3 JAVA 클래스 3  (0) 2022.11.17

+ Recent posts