한빛미디어의 <혼자 공부하는 자바>를 요약 정리했습니다.
업캐스팅(upcasting)
Parent p = new Child(); // 업캐스팅 (자동 변환)
p.parentMethod(); // 가능
// p.childMethod(); // 컴파일 오류 (자식 메서드 접근 불가)
다운캐스팅(downcasting)
(자식타입)
으로 캐스팅)if (p instanceof Child) {
Child c = (Child) p; // 다운캐스팅 (명시적 변환)
c.childMethod(); // 자식 클래스의 멤버 사용 가능
}
HttpServlet이라는 추상 클래스가 다음과 같이 선언되어 있습니다.
public abstract class HttpServlet {
public abstract void service();
}
다음 클래스를 실행하면 "로그인 합니다.", "파일 다운로드 합니다."가 차례대로 출력되도록 LoginServlet과 FileDownloadServlet 클래스를 선언해보세요.
public class HttpServletExample {
public static void main(String[] args) {
method(new LoginServlet()); // 로그인합니다.
method(new FileDownloadServlet()); // 파일 다운로드합니다.
}
public static void method(HttpServlet servlet) {
servlet.service();
}
}
HttpServlet 추상 클래스를 상속받아 각각의 서브 클래스(LoginServlet, FileDownloadServlet)에서 service() 메서드를 구현
LoginServlet
service()를 오버라이딩하여 "로그인 합니다." 출력
public class LoginServlet extends HttpServlet {
@Override
public void service() {
System.out.println("로그인 합니다.");
}
}
FileDownloadServlet
service()를 오버라이딩하여 "파일 다운로드 합니다." 출력
public class FileDownloadServlet extends HttpServlet {
@Override
public void service() {
System.out.println("파일 다운로드 합니다.");
}
}
부모 클래스의 멤버를 자식 클래스에게 물려주는 것
class 자식클래스 extends 부모클래스 {
// 필드
// 생성자
// 메소드
}
public class CellPhone {
// 필드
String model;
String color;
// 생성자
// 메소드
void powerOn { System.out.println("전원을 켭니다."); }
void powerOff { System.out.println("전원을 끕니다."); }
}
public class DmbCellPhone extends CellPhone {
// 필드
int channel;
// 생성자
DmbCellPhone(String model, String color, int channel) {
this.model = model;
this.color = color;
this.channel = channel;
}
// 메소드
void turnOnDmb() {
System.out.println("채널 " + channel + "번 DMB 방송 수신을 시작합니다.");
}
public class DmbCellPhoneExample {
public static void main(String[] args) {
// DmbCellPhone 객체 생성
DmbCellPhone dmbCellPhone = new DmbCellPhone("자바폰", "검정", 10);
// CellPhone 클래스로부터 상속받은 필드
System.out.println("모델: " + dmbCellPhone.model);
// DmbCellPhone 클래스의 필드
System.out.println("채널: " + dmbCellPhone.channel);
// CellPhone 클래스로부터 상속받은 메소드 호출
dmbCellPhone.powerOn();
dmbCellPhone.powerOff();
// DmbCellPhone 클래스의 메소드 호출
dmbCellPhone.turnOnDmb();
}
}
자식 객체를 생성하면, 부모 객체가 먼저 생성되고 그 다음에 자식 객체가 생성
DmbCellPhone dmbCellPhone = new DmbCellPhone();
public DmbCellPhone() {
super(); // 부모의 기본 생성자를 호출
}
명시적으로 부모 생성자를 호출 가능
자식클래스(매개변수선언, ...) {
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 Students(String name, String ssn, int studentNo) {
super(name, ssn);
this.studentNo = studentNo;
}
}
재정의된 부모 클래스의 메소드 호출
super.부모 메소드();
부모 클래스의 메소드가 자식 클래스가 사용하기에 적합하지 않은 경우, 상속된 일부 메소드를 자식 클래스에서 수정해서 사용
-> 메소드 재정의(오버라이딩: Overriding)
public class Calculator {
double areaCircle(double r) {
return 3.14159 * r * r;
}
}
public class Computer extends Calculator {
@Override // 생략 가능
double areaCircle(double r) {
return Math.PI * r * r;
}
}
final 키워드는 클래스, 필드, 메소드를 선언할 때 해당 선언이 최종 상태이고 수정될 수 없음을 뜻함
public final class 클래스 { ... }
public final 리턴타입 메소드([매개변수, ...]) { ... }
다형성은 사용 방법은 동일하지만 다양한 객체를 이용해서 다양한 실행결과가 나오도록 하는 성질
타입 변환은 타입을 다른 타입으로 변환하는 행위
자동 타입 변환(promotion)은 프로그램 실행 도중에 자동적으로 타입 변환이 일어나는 것
부모타입 변수 = 자식타입;
class Animal { ... }
class Cat extends Animal { ... }
Cat cat = new Cat();
Animal animal = cat;
// 가능
Animal animal = new Cat();
하지만 메소드가 자식 클래스에서 재정의되었다면 자식 클래스의 메소드가 대신 호출
필드의 타입을 부모 타입으로 선언하면 다양한 자식 객체들이 저장될 수 있기 때문에 필드 사용 결과가 달라질 수 있음
class Car {
// 필드
Tire frontLeftTire = new Tire();
Tire frontRightTire = new Tire();
Tire backLeftTire = new Tire();
Tire backRightTire = new Tire();
// 메소드
void run() { ... }
}
Car myCar = new Car();
myCar.frontRightTire = new HankookTire();
myCar.backLeftTire = new KumhoTire();
myCar.run();
자동 타입 변환은 필드의 값을 대입할 때에도 발생하지만, 주로 메소들르 호출할 때 많이 발생
class Driver {
void drive(Vehicle vehicle) {
vehicle.run();
}
}
Driver driver = new Driver();
Vehicle vehicle = new Vehicle();
driver.drive(vehicle);
// Vehicle의 자식 클래스인 Bus 객체를 drive() 메소드의 매개값으로 넘겨줌
Driver driver = new Driver();
Bus bus = new Bus();
driver.drive(bus); // 자동 타입 변환 발생 -> Vehicle vehicle = bus;
부모 타입을 자식 타입으로 변환하는 것
자식타입 변수 = (자식타입) 부모타입;
// example
Parent parent = new child(); // 자동 타입 변환
Child child = (Child) parent; // 강제 타입 변환
자식 타입이 부모 타입으로 자동 타입 변환하면, 부모에 선언된 필드와 메소드만 사용 가능하기 때문에, 자식에 선언된 필드와 메소드를 사용하기 위해 강제 타입 변환
객체가 어떤 인스턴스인지 확인하기 위해 instanceof 연산자 사용
public void method(Parent parent) {
if(parent instanceof Child) {
Child child = (Child) parent;
}
}
ClassCastException
발생
추상 클래스는 실체 클래스들의 공통적인 특성을 추출해서 선언한 클래스
클래스 선언에 abstract 키워드를 붙여서 선언하고, new 연산자를 이용해서 객체를 만들지 못함
public abstract class 클래스 {
// 필드
// 생성자
// 메소드
}
객체를 직접 생성 불가능
Animal animal = new Animal();
메소드의 선언만 통일하고, 실행 내용은 실체 클래스마다 달라야 하는 경우, 추상 메소드 선언
[public | protected] abstract 리턴타입 메소드이름(매개변수, ...);
sound() 메소드를 추상 메소드로 선언
public abstract class Animal {
public String kind;
public abstract void sound();
}
public class Dog extends Animal {
public Dog() {
this.kind = "포유류";
}
@Override
public void sound() {
System.out.println("멍멍");
}
}