기존의 클래스를 재사용하여 새로운 클래스를 작성하는 자바의 문법 요소를 의미
상위 클래스와 하위 클래스로 나누어 상위 클래스의 멤버(필드, 메서드, 이너 클래스)를 하위 클래스와 공유하는 것을 의미한다.
하위 클래스는 상위 클래스가 가진 모든 멤버를 상속받는다.
하위 클래스의 멤버 개수는 언제나 상위 클래스보다 같거나 많다.
두 클래스 간 상속 관계를 설정할 때는 extends
키워드를 사용한다.
자바에서는 단일 상속(single ingeritance) 만을 허용한다.
인터페이스(interface)라는 문법 요소를 통해 다중 상속과 비슷한 효과를 낼 수 있는 방법이 존재한다.
코드를 재사용하여 보다 적은 양의 코드로 새로운 클래스를 작성할 수 있어 코드의 중복을 제거 할 수 있다.
상속은 다형적 표현이 가능하다.
상속예제
public class Person {
String name;
int age;
void learn() {
System.out.println("공부를 합니다.");
}
void eat() {
System.out.println("밥을 먹습니다.");
}
}
class Programmer extends Person { // Person 클래스로 부터 상속. extends 키워드 사용
String companyName;
void coding() {
System.out.println("코딩을 합니다.");
}
}
class HelloJava {
public static void main(String[] args) {
//Person 객체 생성
Person p = new Person();
p.name = "김코딩";
p.age = 24;
p.learn();
p.eat();
System.out.println(p.name);
// Programer 객체 생성
Programmer pg = new Programmer();
pg.name = "박해커";
pg.age = 26;
pg.learn(); // Persons 클래스에서 상속받아 사용가능
pg.coding(); // Programmer의 개별 기능
System.out.println(pg.name);
}
}
// 출력
공부를 합니다.
밥을 먹습니다.
김코딩
공부를 합니다.
코딩을 합니다.
박해커
포함(composite)은 상속처럼 클래스를 재사용할 수 있는 방법으로, 클래스의 멤버로 다른 클래스 타입의 참조변수를 선언하는 것을 의미한다.
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 address2 = new Address("도쿄", "일본");
Employee e = new Employee(1, "김지수" , address1);
Employee e2 = new Employee(2, "박해커", address2);
e.showInfo();
e2.showInfo();
}
}
class Address {
String city;
String country;
public Address(String city, String country) {
this.city = city;
this.country = country;
}
}
// 출력
1 김지수
서울 한국
2 박해커
도쿄 일본
원래라면 Address 클래스에 포함되어 있는 인스턴스 변수 city와 country 를 각각 Employee 클래스의 변수로 정의해주어야 하지만, Address 클래스로 해당 변수들을 묶어준다음 Employee 클래스 안에 참조변수를 선언하는 방법으로 코드의 중복을 없애고 포함관계로 재사용하고 있다.
클래스 간의 관계를 설정하는데 있어서 상속관계를 맺어 줄 것인지 포함 관계를 맺어 줄 것인지 판별 기준은
클래스 간의 관계가 ~은 ~이다(IS-A)
인지 ~은 ~을 가지고 있다(HAS-A) 관계인지
문장을 만들어 생각해 보자.
예시로 예를 들어보면, Employee 는 Address 이다.
라는 문장은 성립하지 않지만 Employee는 Address를 가지고 있다
는 어색하지 않기 때문에 상속보다는 포함관계가 적합하다.
상위 클래스로부터 상속받은 메서드와 동일한 이름의 메서드를 재정의하는 것을 의미한다.
예시
class Vehicle {
void run() {
System.out.println("Vehicle is running");
}
}
class Bike extends Vehicle {
void run() {
System.out.println("Bike is running"); // 메서드 오버라이딩
}
public static void main(String[] args) {
Bike bike = new Bike();
bike.run();
}
}
// 출력
"Bike is running"
메서드 오버라이딩을 사용할 경우 3가지 조건을 만족시켜줘야 한다.
오버라이딩을 사용할 경우 상위 클래스로 타입을 선언하고 각각 타입으로 객체를 생성해주면
간편하게 배열로 선언하여 관리 할 수 있다는 편리성이 있다.
// 배열로 한번에 관리하기
Vehicle[] vehicles = new Vehicle[] { new Bike(), new Car(), new MotorBike()};
for (Vehicle vehicle : vehicles) {
vehicle.run();
}
// 출력값
Bike is running
Car is running
MotorBike is running
super 키워드는 상위 클래스의 객체 , super( ) 는 상위 클래스의 생성자를 호출 할 때 사용한다.
super 예제
class Super {
public static void main(String[] args) {
Lower l = new Lower();
l.calNum();
}
}
class Upper {
int count = 20; // super.count
}
class Lower extends Upper {
int count = 15; // this.count
void calNum() {
System.out.println("count = " + count);
System.out.println("this.count = " + this.count);
System.out.println("super.count = " + super.count);
}
}
// 출력
count = 15
count = 15
count = 20
super
키워드 이다.super( ) 예제
public class Test {
public static void main(String[] args) {
Student s = new Student();
}
}
class Human {
Human() {
System.out.println("휴먼 클래스 생성자");
}
}
class Student extends Human {
Student() {
super(); // Human 클래스의 생성자 호출
System.out.println("학생 클래스 생성자");
}
}