728x90

230724 객체지향 프로그래밍 - 다형성, 추상 클래스
- 다형성
- 추상클래스
- 추가) 바인딩 - 동적 바인딩, 정적 바인딩
다형성
다형성의 모습
`public class Person {
String name;
int age;
Person() {}
Person(String name) {
this.name = name;
}
public void eat () {
System.out.println("음식을 먹는다.");
}
}
public class Student extends Person {
String major;
public void study() {
System.out.println("공부를 한다.");
}
}
- 다형성이란 多形을 가질 수 있는 성질
- 상속관계에 있을 때 조상 클래스의 타입으로 자식 클래스 객체를 참조할 수 있다
메모리 상의 모습
= new Student
참조변수의 형 변환
- 자손타입 → 조상타입 (묵시적 형 변환)
- 형 변환 생략 가능
Student st = new Student();
Person p = st;
Person p = new Student();
Student st = (Student) p;
참조변수의 형 변환
Person p = new Person();
Student st = (Student) p;
instanceof 연산자
- 참조변수가 참조하고 있는 인스턴스의 타입을 확인하기 위해 사용
- 결과를 boolean으로 반환
- true가 반환되면 해당 타입으로 형 변환 가능
Person perseon = new Person();
if (person instanceof Student) {
Student student = (Studnet) person;
student.study();
}
참조 변수와 인스턴스 멤버의 관계
class Parent {
String x = "parent";
public Stirng method() {
return "parent method!!!!";
}
}
class Child extends Parne {
String x = "child";
@Override
public String method() {
return "child method!!!!";
}
}
public class BindingTest {
public static void main(String[] args) {
Parent p = new Child();
Child c = new Child();
System.out.println(p.x);
System.out.println(p.method());
System.out.println(c.x);
System.out.println(c.method());
}
}
- 상속관계에서 멤버 변수가 중복되면 참조 타입에 따라 연결이 달라짐
- 메서드가 중복될 때 무조건 자식 클래스의 메서드가 호출됨
static
메서드는 참조변수 타입의 영향을 받기 때문에 이를 방지하고자 클래스 이름으로 메서드 호출- 다형성의 활용 - 다른 타입의 객체를 다루는 배열
다형성의 활용 - 매개변수의 다형성
- 사람의 정보를 출력하려면
↓public String info(Teacher t) { } public String info(Student st) { }
public String info (Person p) { String s = String.valueOf(x); synchronized (this) { print(s); newLine(); } }
동적 바인딩… 공부하기
추상클래스 (abstract class)
추상클래스
상속을 강제하기 위한 것
메소드의 시그니처만 정의해 놓고 그 메소드의 실제 동작 방법은 이 메소드를 상속받은 하위 클래스의 책임으로 위임한다.
추상 클래스 정의
public class KFoodChef {
String name;
int age;
String speciality;
public void eat(){
System.out.println("음식을 먹는다.");
}
public void cook() {
System.out.println("한식을 요리한다.");
}
}
public class JFoodChef {
String name;
int age;
String speciality;
public void eat() {
System.out.println("음식을 먹는다.");
}
public void cook() {
System.out.println("일식을 요리한다.");
}
}
추상 클래스 정의
public class Chef {
String name;
int age;
String speciality;
public void eat() {
System.out.println("음식을 먹는다.");
}
public void cook() {
System.out.println("전공에 맞는 요리한다.");
}
}
public class KFoodChef extends Chef{
@Override
public void cook() {
System.out.println(“한식을 요리한다.");
}
}
public class JFoodChef extends Chef{
@Override
public void cook() {
System.out.println("일식을 요리한다.");
}
}
public class ChefTest {
public static void main(String[] args) {
Chef[] chefs = new Chef[2];
chefs[0] = new KFoodChef();
chefs[1] = new JFoodChef();
for(Chef chef : chefs) {
chef.eat();
chef.cook();
}
}
}
- 한식요리사, 일식요리사 모두
cook
메서드를 가지고 있음. - 조상 클래스 Chef에 선언하고 각 자손 클래스에서 override 예정
- 사용되지 않는 Chef 클래스에
cook()
메서드가 필요한가?
→ 요리사라는 객체를 만들 때 전공을 무조건 선택하게 한다면**= 자손 클래스에서 무조건 재정의**
Chef (cook()) 메서드는 필요 없지 않나?
public class Chef {
String name;
int age;
String speiciality;
public void eat() {
System.out.println("음식을 먹는다.");
}
public void cook() {
System.out.println("전공에 맞는 요리한다.");
}
}
for (Chef chef: chefs) {
chef.eat();
if (chef instanceof KFoodChef) {
KFoodChef k = (KFoodChef) chef;
k.cook();
} else if (chef instanceof JFoodChef) {
((JFoodChef) chef).cook();
}
}
cook()
메서드는 자손 클래스에서 반드시 재정의해서 사용되기 때문에 조상의 구현이 무의미- 하지만? “전공에 맞는 요리를 한다” 를 삭제했는데,
모두가 cook 메서드를 가지고 있지만 cook 메서드에 대한 강제성이 없음!cook
메서드가 없는 클래스가 존재할 수도 있음 - 메서드의 선언부만 남기고 구현부는
;
(세미콜론)으로 대체 ::: 미완성 method
미완성 method 자식 클래스에서 무조건 재정의해야 한다는 것을 의미
→ 자식 클래스에서 재정의하지 않으면 빨간 줄 나옴~
→ Chef 클래스도 미완성 클래스가 됨 - 구현부가 없으므로
abstract
키워드를 메서드 선언부에 추가 - 객체를 생성할 수 없는 클래스라는 의미로 클래스 선언부에
abstract
를 추가
public abstract class Chef {
String name;
int age;
String speciality;
public void eat() {
System.out.println("음식을 먹는다.");
}
public abstract void cook();
}
추상 클래스 특징
- abstract 클래스는 상속 전용의 클래스 → 인스턴스 생성 불가
- 클래스에 구현부가 없는 메서드가 있으므로 객체를 생성할 수 없음
- 상위 클래스 타입으로 자식을 참조할 수는 없음
//생성할 수 없음 Chef chef1 = new Chef(); Chef chef2 = new KFoodChef();
- 조상 클래스에서 상속받은
abstract
메서드를 재정의하지 않은 경우
클래스 내부에abstract
메서드가 있으므로 자식 클래스는abstract
클래스가 되어야 함
∴ 추상 클래스 사용하는 이유?
abstract
클래스는 구현의 강제를 통해 프로그램의 안정성 향상- 부모가 구현하고 싶은 내용이 없다고 해서 구현하지 않는다면, 동적 바인딩에 의해 자식의 오버라이딩된 함수가 실행되지 않음!!
- 아무것도 작성하지 않은
{}
를 만들어 놓으면 자식이 구현하든, 하지 않든 상관없음 abstract
로 만들어 두면 무조건 구현해야 하는 의무를 부여함
### 정리
추상클래스는 미완성의 설계도: 인스턴스를 생성할 수 없음
인스턴스를 생성할 때 미완성된 부분을 만들어 주면 됨!
익명 클래스 문법을 이용해서 1회 한정으로 구현하고 인스턴스를 만들 수 있게 도와준다
Chef c2 = new Chef() {
public void cook () {
System.out.println("아무요리나다해버림ㅎㅎ");
}
}
Binding 바인딩
바인딩이란?
- Association of method call to the method body: 메서드 호출과 메서드 본문의 연결
- 컴퓨터 프로그래밍에서 각종 값들이 확정되어 더이상 변경할 수 없는 구속(bind) 상태가 되는 것
- 프로그램 내에서 식별자(identifier)가 그 대상인 메모리 주소, 데이터형 또는 실제 값으로 배정되는 것
Static Binding 정적 바인딩
- 컴파일링 또는 링크 시에 확정되는 바인딩을 의미
- 실행 이전에 값이 확정되면 → 정적 바인딩
static
private
final
method: override 불가능하며 compile 시점에 타입이 결정된다.
Dynamic Binding 동적 바인딩
- 프로그램이 실행되는 과정에서 바인딩되는 것을 의미
- method overriding: 부모와 자식 클래스에 모두 동일한 메서드가 존재하고 오직 실행 시점에 타입이 결정되어 해당 타입의 method가 실행됨
728x90
'Java > 기본 문법' 카테고리의 다른 글
JAVA 객체지향 프로그래밍 - Collection (0) | 2023.08.12 |
---|---|
JAVA 객체지향 프로그래밍 - 인터페이스, 제네릭 (0) | 2023.08.11 |
JAVA 객체지향 프로그래밍 - 상속 (0) | 2023.08.10 |
JAVA 객체지향 프로그래밍 - 객체 (0) | 2023.08.09 |
JAVA 객체지향 프로그래밍 - 클래스와 메소드 (0) | 2023.08.09 |