상속
상속
- 상속이란 기존의 클래스를 재활용하여 새로운 클래스를 작성하는 자바의 문법 요소를 의미합니다.
- 상위 클래스의 멤버(필드, 메서드, 내부 클래스)를 하위 클래스와 공유하는 것을 의미합니다. 여기서 우리는 이 두 클래스를 서로 상속 관계에 있다고 하며, 하위 클래스는 상위 클래스가 가진 모든 멤버를 상속받게 됩니다.
-
두 클래스 간 상속 관계를 설정할 때 사용하는 extends 키워드 자체가 “~클래스로부터 확장되었다”는 표현이 그 역할과 기능을 생각했을 때 더 적절한 표현입니다.
- 코드를 재사용하여 보다 적은 양의 코드로 새로운 클래스를 작성할 수 있어 코드의 중복을 제거할 수 있습니다.
-
상속은 다형적 표현이 가능합니다.
- 자바의 객체지향 프로그래밍에서는 단일 상속(single inheritance)만을 허용한다는 것입니다. 다중 상속은 허용되지 않습니다.
class Person {
String name;
int age;
void learn(){
System.out.println("공부를 합니다.");
};
void walk(){
System.out.println("걷습니다.");
};
void eat(){
System.out.println("밥을 먹습니다.");
};
}
class Programmer extends Person { // Person 클래스로부터 상속. extends 키워드 사용
String companyName;
void coding(){
System.out.println("코딩을 합니다.");
};
}
class Dancer extends Person { // Person 클래스로부터 상속
String groupName;
void dancing(){
System.out.println("춤을 춥니다.");
};
}
class Singer extends Person { // Person 클래스로부터 상속
String bandName;
void singing(){
System.out.println("노래합니다.");
};
void playGuitar(){
System.out.println("기타를 칩니다.");
};
}
public class HelloJava {
public static void main(String[] args){
//Person 객체 생성
Person p = new Person();
p.name = "김코딩";
p.age = 24;
p.learn();
p.eat();
p.walk();
System.out.println(p.name);
//Programmer 객체 생성
Programmer pg = new Programmer();
pg.name = "박해커";
pg.age = 26;
pg.learn(); // Persons 클래스에서 상속받아 사용 가능
pg.coding(); // Programmer의 개별 기능
System.out.println(pg.name);
}
}
//출력값
공부를 합니다.
밥을 먹습니다.
걷습니다.
김코딩
공부를 합니다.
코딩을 합니다.
박해커
포함
- 포함(composite)은 상속처럼 클래스를 재사용할 수 있는 방법으로, 클래스의 멤버로 다른 클래스 타입의 참조변수를 선언하는 것을 의미합니다.
public class Employee {
int id;
String name;
Address address;
public Employee(int id, String name, Address address) {
this.id = id;
this.name = name;
this.address = address;
}
void showInfo() {
System.out.println(id + " " + name);
System.out.println(address.city+ " " + address.country);
}
public static void main(String[] args) {
Address address1 = new Address("서울", "한국"); //Address 클래스 포함
Address address2 = new Address("도쿄", "일본");
Employee e = new Employee(1, "김코딩", address1);
Employee e2 = new Employee(2, "박해커", address2);
e.showInfo();
e2.showInfo();
}
}
class Address {
String city, country;
public Address(String city, String country) {
this.city = city;
this.country = country;
}
}
// 출력값
1 김코딩
서울 한국
2 박해커
도쿄 일본
- 상속과 포함 구분법
클래스 간의 관계가 ‘~은 ~이다(IS-A)’ 관계인지 ~은 ~을 가지고 있다(HAS-A) 관계인지 문장을 만들어 생각해 보는 것입니다.
위의 예시로 예를 들어보면, Employee는 Address이다.라는 문장은 성립하지 않는 반면, Employee는 Address를 가지고 있다.는 어색하지 않은 올바른 문장임을 알 수 있습니다. 따라서 이 경우에는 상속보다는 포함관계가 적합합니다.
반면 Car 클래스와 SportCar라는 클래스가 있다고 할 때, SportsCars는 Car를 가지고 있다.라는 문장보다 SportsCar는 Car이다.라는 문장이 훨씬 더 자연스럽습니다. 따라서 이 경우에는 Car를 상위클래스로 하는 상속 관계를 맺어주는 것이 더 적합하다고 할 수 있습니다.
매서드 오버라이딩
-
메서드 오버라이딩(Method Overriding)은 상위 클래스로부터 상속받은 메서드와 동일한 이름의 메서드를 재정의하는 것을 의미합니다.
-
상위 클래스의 메서드를 오버라이딩하려면 다음의 세 가지 조건을 반드시 만족시켜야 합니다.
- 메서드의 선언부(메서드 이름, 매개 변수, 반환 타입)가 상위클래스의 그것과 완전히 일치해야 한다.
- 접근 제어자의 범위가 상위 클래스의 메서드보다 같거나 넓어야 한다.
- 예외는 상위 클래스의 메서드보다 많이 선언할 수 없다.
public class Main {
public static void main(String[] args) {
Bike bike = new Bike();
Car car = new Car();
MotorBike motorBike = new MotorBike();
bike.run();
car.run();
motorBike.run();
}
}
class Vehicle { // run() 메서드가 정의
void run() {
System.out.println("Vehicle is running");
}
}
class Bike extends Vehicle { // run() 메서드를 재정의함으로써 Vehicle 클래스의 run() 메서드를 오버라이딩
void run() {
System.out.println("Bike is running");
}
}
class Car extends Vehicle { // run() 메서드를 재정의함으로써 Vehicle 클래스의 run() 메서드를 오버라이딩
void run() {
System.out.println("Car is running");
}
}
class MotorBike extends Vehicle { // run() 메서드를 재정의함으로써 Vehicle 클래스의 run() 메서드를 오버라이딩
void run() {
System.out.println("MotorBike is running");
}
}
// 출력값
Bike is running
Car is running
MotorBike is running
super와 super()
super
- 복습
this는 자기 객체를 가리키는 참조 변수명으로, 메서드 내에서 멤버 변수와 지역 변수의 이름이 같을 때 구분하기 위한 용도로 사용되며, 생략 시 컴파일러가 자동으로 추가해줍니다. 반면 this() 메서드는 같은 클래스의 다른 생성자를 호출하는 데 사용되며, 생성자 내에서만 사용 가능하고, 항상 첫 줄에 위치해야 합니다.
한마디로 정리하면 this는 자신의 객체, this() 메서드는 자신의 생성자 호출을 의미합니다.
-
super 키워드는 상위 클래스의 객체, super()는 상위 클래스의 생성자를 호출하는 것을 의미합니다.
-
둘 다 상위 클래스의 존재를 상정하며 상속 관계를 전제로 합니다.
public class Example {
public static void main(String[] args) {
SubClass subClassInstance = new SubClass();
subClassInstance.callNum();
}
}
class SuperClass {
int count = 20; // super.count
}
class SubClass extends SuperClass {
int count = 15; // this.count
void callNum() {
System.out.println("count = " + count);
System.out.println("this.count = " + this.count);
System.out.println("super.count = " + super.count); // 인스턴스 변수 count 이름이 같지만, super. 키워드로 이 둘을 구분함. 부모객체의 값을 가져옴.
}
}
// 출력값
count = 15
count = 15
count = 20
super()
- this() 와 비슷합니다.
- 상위 클래스에 기본생성자가 없으면 에러가 발생하게 됩니다.
public class Test {
public static void main(String[] args) {
Student s = new Student();
}
}
class Human {
Human() {
System.out.println("휴먼 클래스 생성자");
}
}
class Student extends Human { // Human 클래스로부터 상속
Student() {
super(); // Human 클래스의 생성자 호출
System.out.println("학생 클래스 생성자");
}
}
// 출력값
휴먼 클래스 생성자
학생 클래스 생성자
클래스의 정점, Object 클래스
- Object 클래스는 자바의 클래스 상속계층도에서 최상위에 위치한 상위클래스입니다.
class ParentEx { // 컴파일러가 "extends Object" 자동 추가
}
class ChildEx extends ParentEx {
}