상속, 다형성

Java

목록 보기
10/26
post-thumbnail

1.상속

1-1. 객체지향 프로그램

  • 자식(하위, 파생) 클래스가 부모(상위)클래스의 멤버를 물려받는것
  • 자식이 부모를 선택해서 물려받음
  • 상속 대상 : 부모의 필드메소드
  • 부모에서 수정하면, 자식의 상속된 부분도 자동으로 수정됨!

1-2. 상속

  • 다중 상속 불가
class 자식클래스 extends 부모클래스 { ... }
class 자식클래스 extends 부모클래스1, 부모클래스2 { ... }
  • 부모로부터 물려받은 것도 this로 쓸 수 있군
public class CellPhone {
String model;
String color;           }
prublic class DmbCellPhone extends CellPhone {
int channel;

DmbCellPhone(String model, String color, int channel) {
this.model = model;
this.color = color;
this.channel = channel;}
}

1-3. 부모객체 자식객체 (아 sibal 생성자 형!!)

  • 부모없는 자식 없다.
  • 자식 객체를 생성할 때는 부모 객체부터 생성되고 자식 객체가 생성된다.
    super 내가 안 쓰면 컴파일러가 자동으로 해줌.
  • 자식객체를 생성할 때, 부모 생성자를 선택해서 호출할 수 있다.
자식클래스(매개변수 선언, ...) {
super(매개값, ...);
}
  • super(...) 구문은 반드시 자식생성자의 첫 줄에 위치해야 함.
  • 만약, 부모생성자에 기본(매개변수 없는) 생성자가 없다면(근데 자식클래스에서 매개변수 없는 생성자를 만들어야한다면) 부모생성자에도 필수적으로 작성해야하한다.
    이게 존나존나 어려운데, 일단 이해하는대로 다 적어보겠음.
    만약 부모 클래스에서 생성자가 없다면, ==> CellPhone() {} 이런 생성자가 있는걸로 쳐지겠지?

    이게 부모클래스의 상황인거고
    그럼 이 상태에서는 자식클래스는 super없이도 다양한 생성자를 만들 수 있음. 이렇게 ▼

    그런데! 만약 부모 클래스에 매개타입이 있는 생성자가 선언돼있다면? 이렇게?▼

    자식클래스는 super(매개변수,매개변수)를 필수적으로 호출해야하게 됨.이렇게▼



그렇기 때문에, 부모생성자에 (매개타입, 매개타입,...)이 있는 생성자가 있다면, 자식클래스는 거기에 맞춰서 (그와 형식이 비슷한, 또는 그 형식을 포함하는) 생성자를 만들어야한다는 뜻임.
또 이해가 안된다면 이 강의를 계속 다시 돌려볼 것...
또 있는데,

이 경우에는 부모 클래스에 () 생성자와 (String ...) 생성자가 있음.
이럴 땐 자식 클래스에서 (String ...)으로 생성자를 선언해도 됨. 왜냐면 super()로 커버되니까.
여기서 만약

부모클래스를 이렇게 선언하면 자식클래스는

이렇게 오류 남.

  • 자바의 정석
    근데 또 이건 됨...ㅅㅂ 뭐하자는건지 모르겠음

1-4. 매소드 재정의(Override)

  • 부모클래스의 상속 메소드를 수정해서 자식 클래스에서 재정의하는 것.
  • 접근제한을 더 강하게 오버라이딩할 수 없다.
    - public을 default나 private으로 수정할 수 없다
    • 반대로 default는 public으로 수정할 수 있다.
  • 새로운 예외(Exception)를 throws할 수 없다 >>>>❓❓❓❓❓
  • @Override 애너테이션으로 검사 가능.
  • 부모의 메소드는 숨겨지는 효과 발생 (재정의된 자식 메소드가 실행됨)
public class Calculator {

	double areaCircle(double r) {
		System.out.println("카큘레이터 객체의 아리아써클 실행");
		return 3.14159 * r * r;
	}
}
public class Computer extends Calculator {

	@Override
	double areaCircle(double r) {
		System.out.println("카큘레이터 객체의 아리아써클 실행");
		return Math.PI * r * r;
	}
}

방법1) SOurce > Overrid/implement Method
방법2) 걍 일일히 복붙하기
방법3) ctrl + space 상속받을 메소드 하나 선택(더블클릭)

1-4. 매소드 재정의(Override) - 부모 메소드 사용(spuer)

  • 자식 클래스에서 수정되기 전의 부모 메서드를 호출하고자 할경우 super를 사용.
    중요한 것은, 바로 이 자식 클래스 안에서만 쓸 수 있다는 거예요.
    super.method();

    public class Airplane {
    	
    	public void land() {
    		System.out.println("착륙합니다");
    	}
    	public void fly() {
    		System.out.println("일반비행합니다");
    	}
    	public void takeOff() {
    		System.out.println("이륙합니다");
    	}
    }
    public class SupersonicAirplane extends Airplane {
    	
    	public static final int NOMAL = 1;
    	public static final int SUPERSONIC = 2;
    	public int flyMode=1;
    
    	@Override
    	public void fly() {
    		if (flyMode ==SUPERSONIC ) {
    			System.out.println("초음속 비행합니다.");
    		} else {
    			super.fly();
    		}
    	}
    }

    오답노트)✅✅✅✅✅✅✅✅
    무조건❗❗❗ 재정의된 메소드가 호출된다❗❗❗

1-5. final 클래스와 final 메소드

  • final 클래스: 부모로 사용할 수 없는 클래스
    ex) String 클래스
  • final 메소드 : 자식이 재정의할 수 없는 메소드

1-6. protected 접근 제한자

  • 상속과 관련된 접근 제한자
    • 같은 패키지: default와 동일
    • 다른 패키지: 자식 클래스만 접근 허용

2. 타입변환과 다형성

2-1 1) 개념

  • 자식타입이 부모타입에 대입될 수 있는 현상
    ✔ 무슨 말? ▼

    모르겠으면 종류로 생각하면 됨! 고양이는 동물로 설명될 수 있고 강아지도 동물로 설명될 수 있으니까.
부모 클래스 : animal 자식 클래스 : cat
Cat cat = new Cat();
Animal animal = cat;
cat == animal		>>true 

2-2. 2) 자동타입 변환된 이후의 효과

  • Parent 객체가 호출 가능한 것은 method1과 method2 뿐
  • child 객체가 호출 가능한 것은 재정의 된 method2와, method3

ex) 👍 매우 중요해요 이해하세요.

Chile chile = new Child();

Parent parent = child;
parent.method1();			>>Ok
parent.method2();			>>Ok (재정의된 method2가 호출 됨)
parent.method3();			>> X   (Parent에는 method3이 없으니)

2-3. 필드의 다형성

  • 다형성을 구현하는 기술적 방법
    1) 부모 타입으로 자동변환
    2) 자식클래스에, 재정의된 메소드가 있어야함(오버라이딩)
public class Tire {
	
	public int maxRotation;					
	public int accumulatiedRotation;		
	public String location;					
	
	
	public Tire(String location, int maxRotation) {
		this.location = location;
		this.maxRotation = maxRotation;
	}
	
	public boolean roll() {
		++accumulatiedRotation;
		if (accumulatiedRotation < maxRotation) {
			System.out.println(location + "Tire 수명" + (maxRotation - accumulatiedRotation));
			return true;
		} else {
			System.out.println("***" + location + "Tire 펑크***");
			return false;
		}
	}
}
public class HankookTire extends Tire {

	public HankookTire(String location, int maxRotation) {
		super(location, maxRotation);
	}

	@Override
	public boolean roll() {
		++accumulatiedRotation;
		if (accumulatiedRotation < maxRotation) {
			System.out.println(location + "한국Tire 수명" + (maxRotation - accumulatiedRotation));
			return true;
		} else {
			System.out.println("***" + location + "한국Tire 펑크***");
			return false;
		}
	}
}
public class KumhoTire extends Tire {

	public KumhoTire(String location, int maxRotation) {
		super(location, maxRotation);
		// TODO Auto-generated constructor stub
	}

	@Override
	public boolean roll() {
		++accumulatiedRotation;
		if (accumulatiedRotation < maxRotation) {
			System.out.println(location + "금호Tire 수명" + (maxRotation - accumulatiedRotation));
			return true;
		} else {
			System.out.println("***" + location + "금호Tire 펑크***");
			return false;
		}
	}
}
public class Car {
	
	Tire frontLeftTire = new Tire("앞 왼쪽", 6);
	Tire frontrightTire = new Tire("앞 왼쪽", 2);
	Tire backLeftTire = new Tire("앞 왼쪽", 3);
	Tire backrigntTire = new Tire("앞 왼쪽", 4);
	
	int run() {
		System.out.println("자동차가 달립니다");
		if(frontLeftTire.roll() == false) {stop();return 1;}
		if(frontrightTire.roll() == false) {stop();return 2;}
		if(backLeftTire.roll() == false) {stop();return 3;}
		if(backrigntTire.roll() == false) {stop();return 4;}
		return 0;
	}
	void stop() {
		System.out.println("자동차가 멈춥니다");
	}
}
public class CarExample {

	public static void main(String[] args) {
		Car car = new Car();
		
		for (int i =0; i<=5; i++) {
			int problemLocation = car.run();
			switch(problemLocation) {
			case 1:
				System.out.println("앞 왼쪽 HankookTire로 교체");
				car.frontLeftTire = new HankookTire("앞 왼쪽",15);
				break;
			case 2:
				System.out.println("앞 왼쪽 HankookTire로 교체");
				car.frontrightTire = new HankookTire("앞 왼쪽",15);
				break;
			case 3:
				System.out.println("앞 왼쪽 HankookTire로 교체");
				car.backLeftTire = new HankookTire("앞 왼쪽",15);
				break;
			case 4:
				System.out.println("앞 왼쪽 HankookTire로 교체");
				car.backrigntTire = new HankookTire("앞 왼쪽",15);
				break;
			}
		}
	}
}

2-4. 배열로 객체 관리

  • 배열로도 타입변환을 선언할 수 있다!
class Car {
Tire[] tires = {
new Tire("앞왼쪽",6),
new Tire("앞왼쪽",6),
new Tire("앞왼쪽",6),
new Tire("앞왼쪽",6) };
}
tire[1] = new KumhoTire("앞오른쪽", 13);

배열에 넣기만 해도 자동 타입 변환이 되는구나!

	Tire[] tires = {
		new Tire("앞왼쪽",6),	
		new Tire("앞오른쪽",6),
		new Tire("뒤왼쪽",6),
		new Tire("뒤오른쪽",6),
	};

2-5. 매개변수의 다형성(매개변수가 클래스 타입인 경우)

  • 해당 클래스의 객체 또는 해당 클래스의 자식 객체가 대입된다.
class Driver(Vehicle vehicle) {
vehicle.run();
} }                          >> vehicle 또는 그 자식객체이 들어온다고 선언한 것.

2-7. 강제 타입 변환(부모타입->자식타입 조건有✅)

  • 자식 타입이 부모 타입으로 자동 변환된 이후, 다시 자식타입으로 변환할 때만 유효하다! 그냥 바로 부모-> 자식 되는게 아님! 자식-> 부모 된 후 부모->자식만 되는거임!
    ✅✅

2-8. 객체 타입 확인(instanceof)

  • 부모 타입이면 모두 자식 타입으로 강제 타입 변환할 수 있는 것이 아니다.
    - ClassCastException 예외 발생
Parent parent = new Parent();
Child child = (Child) parent;
  • 먼저, 자식 타입인지 확인 후 강제 타입을 해야 한다.
    boolean result - 좌항(객체) instanceof 우항(타입)

3. 추상클래스

3-1. 추상클래스

  • 실체 클래스들의 공통되는 필드와 메소드를 정의한 클래스
  • 추상 클래스는 단독으로 객체 생성을 할 수 없고, 부모 클래스로만 사용된다
    Animal animal = new Animal();
  • 그럼 왜 만드는가? : 실체 클래스의 공통된 필드와 메소드의 이름을 통일할 목적
  • 선언 방법
public abstrat class 클래스 {
...
}

*** 부모 클래스 객체 안 만들고(=못 만들고) 바로 메소드 접근하는거니까...그래서 사용하는건가...

  • 그치만! 추상클래스의 자식클래스에서 생성자를 선언하려면 당연히 추상클래스에도 생성자가 선언되어 있어야함. 추상클래스로 객체를 직접적으로 못 만든다고 해서 (추상클래스에) 생성자 없이 자식클래스에서 생성자 선언을 마음대로 할 수 있는 것은 아니다. 여기 22:00

3-2. 추상 메소드와 오버라이딩(재정의)

  • 자식 객체를 부모 객체로 타입변환한 후 (추상)메서드를 실행해도, 자식객체 고유의 메서드로 실행된다
public class AnimalExample {

	public static void main(String[] args) {
		Dog dog = new Dog();
		Cat cat = new Cat();
		
		dog.sound();
		cat.sound();
		
		Animal animal = null;
		animal = new Dog();
		animal.sound();
		
		Animal animal2 = null;
		animal = new Cat();
		animal2.sound();
		
		animalSound(new Dog());
		animalSound(new Cat());		
	}	
	public static void animalSound(Animal animal) {
		animal.sound();
	}
}
  • 추상 메서드는 {....}이 없다!
	public abstract void sound();

0개의 댓글