기존의 클래스를 재활용하여 새로운 클래스를 작성하는 자바의 문법 요소를 의미
하위 클래스는 상위 클래스가 가진 모든 멤버를 상속받게 된다.
따라서 하위 클래스의 멤버 개수는 언제나 상위 클래스의 그것과 비교했을 때 같거나 많다.
단일 상속(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 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 박해커
도쿄 일본
Address
클래스로 인스턴스 변수 city와 country를 묶어 Employee
클래스 안에 참조변수를 선언하는 방법으로 코드의 중복을 없애고 포함관계로 재사용하고 있다.
상속or포함 어떤 걸 써야할지 결정하는 방법
- 상속 = 클래스 간의 관계가 ‘~은 ~이다(IS-A)’ 관계
- 포함 = ~은 ~을 가지고 있다(HAS-A) 관계
상위 클래스로부터 상속받은 메서드와 동일한 이름의 메서드를 재정의하는 것을 의미
class Vehicle {
void run() {
System.out.println("Vehicle is running");
}
}
public class Bike extends Vehicle { // Vehicle 클래스 상속
void run() {
System.out.println("Bike is running"); // 메서드 오버라이딩
}
public static void main(String[] args) {
Bike bike = new Bike();
bike.run();
}
}
// 출력값
"Bike is running"
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();
Vehicle bike2 = new Bike(); // 상위 클래스 타입으로 선언 + 각각 타입으로 객체 생성
Vehicle car2 = new Car();
Vehicle motorBike2 = new MotorBike();
bike2.run();
car2.run();
motorBike2.run();
}
}
class Vehicle {
void run() {
System.out.println("Vehicle is running");
}
}
class Bike extends Vehicle {
void run() {
System.out.println("Bike is running");
}
}
class Car extends Vehicle {
void run() {
System.out.println("Car is running");
}
}
class MotorBike extends Vehicle {
void run() {
System.out.println("MotorBike is running");
}
}
// 출력값
Bike is running
Car is running
MotorBike is running
Bike is running
Car is running
MotorBike is running
상위 클래스 타입으로 선언하건 각각의 타입으로 선언하건 동일한 출력이 나오는 것을 확인할 수 있다.
참조 변수 bike2, car2, motorBike2는 모두 Vehicle 타입이지만 메서드 오버라이딩을 통해 각각의 run() 메서드가 출력되고 이를 이용해 간편하게 배열로 선언하여 관리할 수 있는 편리성이 있다.
// 배열로 한번에 관리하기
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()는 상위 클래스의 생성자를 호출하는 것을 의미
리마인드
this는 자신의 객체, this() 메서드는 자신의 생성자 호출을 의미
this
,this()
,super
,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 = 15
count = 15
count = 20
만약 super 키워드를 붙이지 않는다면, 자바 컴파일러는 해당 객체는 자신이 속한 인스턴스 객체의 멤버를 먼저 참조함.
this와 super는 기본적으로 같은 것이라 말할 수 있지만 상위 클래스의 멤버와 자신의 멤버를 구별하는 데 사용된다는 점이 다르다.
상위 클래스의 생성자를 호출하는데 사용
this()
는 같은 클래스의 다른 생성자를 호출하는데 사용
public class Test {
public static void main(String[] args) {
Student s = new Student();
}
}
class Human {
Human() { //Human class 생성자
System.out.println("휴먼 클래스 생성자");
}
}
class Student extends Human { // Human 클래스로부터 상속
Student() {
super(); // Human 클래스의 생성자 호출
System.out.println("학생 클래스 생성자");
}
}
// 출력값
휴먼 클래스 생성자
학생 클래스 생성자
super()
가 없는 경우에는 컴파일러가 생성자의 첫 줄에 자동으로 super()
를 삽입한다. 이때 상위클래스에 기본생성자가 없으면 에러가 발생)상속계층도에서 최상위에 위치한 상위클래스
자바의 모든 클래스는 Object 클래스로부터 확장된다.
(아무런 상속을 받지 않은 클래스는 컴파일러가 자동으로 Object에 상속 시킴)
Object 클래스의 멤버들을 자동으로 상속받아 사용할 수 있음.
특정 객체 안에 관련된 속성과 기능을 하나의 캡슐(capsule)로 만들어 데이터를 외부로부터 보호하는 것
캡슐화를 해야하는 이유
특정한 목적을 공유하는 클래스와 인터페이스의 묶음
다른 패키지 내의 클래스를 사용하기 위해 사용
(패키지 구문과 클래스문 사이에 작성)
cf) import문은 컴파일 시에 처리가되므로 프로그램의 성능에는 영향을 주지 않음
import 패키지명.클래스명; 또는 import 패키지명.*;
ex)
import practicepack.test.ExampleImp
클래스, 필드, 메서드, 생성자 등에 부가적인 의미를 부여하는 키워드를 의미한다.
제어자는 크게 접근 제어자와 기타 제어자로 구분한다.
접근 제어자 | public, protected, (default), private |
---|---|
기타 제어자 | static, final, abstract, native, transient, synchronized 등 |
하나의 대상에 대해서 여러 제어자 사용 가능하지만 접근 제어자는 단 한번만 사용할 수 있다.
접근 제어자를 사용하면 클래스 외부로의 불필요한 데이터 노출을 방지(data hiding)할 수 있고, 외부로부터 데이터가 임의로 변경되지 않도록 막을 수 있다.
접근 제어자 | 접근 제한 범위 |
---|---|
private | 동일 클래스에서만 접근 가능 |
default | 동일 패키지 내에서만 접근 가능 |
protected | 동일 패키지 + 다른 패키지의 하위 클래스에서 접근 가능 |
public | 접근 제한 없음 |
(cf. default = 아무런 접근 제어자를 붙이지 않는 경우 기본적인 설정)
private(동일 클래스) < default(동일 패키지) < protected(동일 패키지 + 하위클래스) < public(접근 제한 없음)
접근 제어자로 은닉 된 객체의 변수의 데이터 값을 추가하거나 수정하는 방법
setter 메서드
getter 메서드
상위 클래스-하위 클래스의 상속 관계,장점
포함관계와 상속관계의 차이
상속 관계에서 사용할 수 있는 메서드 오버라이딩의 정의, 성립 조건, 장점을 이해하고 이를 활용할 수 있다.
super 와 super() 의 차이
super 키워드는 상위 클래스의 객체, super()는 상위 클래스의 생성자를 호출
캡슐화의 핵심 개념과 목적
특정 객체 안에 관련된 속성과 기능을 하나의 캡슐(capsule)로 만들어 데이터를 외부로부터 보호하는 것
패키지의 개념
클래스와 인터페이스의 묶음
import문 사용법
import 패키지명.클래스명
를 이용해 사용
(import를 안써도 패키지명을 붙여서 클래스 멤버를 사용할 수 있지만 매우 번거로움)
접근제어자 네 가지 각각의 접근 가능 범위
private(동일 클래스) < default(동일 패키지) < protected(동일 패키지 + 하위클래스) < public(접근 제한 없음)
Q: 상속과 이너클래스의 사용성 측면에서 차이점이 궁금합니다!
메서드 오버라이딩을 제외하고는 멤버를 가져다 쓸 수 있는 구조가 유사해 보여 기능상 차이점이 눈에 띄지 않는데 대표적인 차이점들이 있을까요??
A: 이너클래스, 익명클래스는 1회성으로 잠깐 사용하고 말 객체를 쓰는 거고,
상속은 공통기능을 재활용 하기 위함이쥬