한 클래스의 멤버변수로 다른 클래스 타입의 참조변수를 선언하는 것
=has-a: ~은 ~를 가지고 있다.
ex) Circle(원)은 Point(점)를 가지고 있다.
class Point {
int x;
int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
class Circle {
Point center;
int r;
public Circle(Point center, int r) {
this.center = center;
this.r = r;
}
}
기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것
=is-a: ~은 ~이다.
class Parent {} // 부모 클래스
class Chind extends Parent {} // 자식 클래스
⭐ 클래스를 상속받는 경우, 자식 클래스는 부모 클래스의 멤버(변수, 메서드)를 상속받아, 해당 멤버를 따로 정의하지 않아도 사용할 수 있다!
ex1) Parent 클래스를 상속받은 Child1 클래스
public class Test {
public static void main(String[] args) {
Parent p = new Parent();
p.age = 70;
p.play();
System.out.println();
Child1 c1 = new Child1();
c1.age = 40; // 부모 멤버변수 사용 가능
c1.play(); // 부모 멤버 메서드 사용 가능
c1.play2();
}
}
class Parent {
int age;
void play() {
System.out.println("Parent : play()");
}
}
class Child1 extends Parent {
void play2() {
System.out.println("Child1 : play2()");
}
}
⭐ 자식 클래스를 또 다른 자식 클래스가 상속받는다면, 자식 클래스는 부모가 된 자식 클래스의 부모 클래스의 멤버에 접근할 수 있다!
ex2) Parent를 상속받은 Child1를 상속받은 Child2 클래스
public class Test {
public static void main(String[] args) {
...
Child2 c2 = new Child2();
c2.age = 10;
c2.play();
c2.play2();
c2.play3();
}
}
...
class Child2 extends Child1 {
void play3() {
System.out.println("Child2 : play3()");
}
}

⭐ 자바는 단일 상속만을 허용한다!
class Child2 extends Child1, Parent { // 에러 발생
void play3() {
System.out.println("Child2 : play3()");
}
}
: 상속받을 두 클래스에 같은 이름의 멤버가 존재하는 경우, 자바는 이를 구분할 수 없다.
⭐ 모든 클래스는 최상위 클래스인
Object클래스를 상속받고 있다! (생략 가능)
class Parent {}
class Parent extends Object {}
부모 클래스로부터 상속받은 메서드의 내용을 변경하는 것
ex) Point를 상속받은 Point3D
class Point {
int x;
int y;
String getLocation() {
return "x : " + x + ", y : " + y;
}
}
class Piont3D extends Point {
int z;
String getLocation() {
return "x : " + x + ", y : " + y + ", z : " + z;
}
}
: Point의 getLocation() 메서드는 두 좌표의 위치를 출력한다. Point3D는 Point의 두 좌표에 z좌표를 추가하여 총 세 좌표의 위치를 출력해야 한다.
이 때, Point3D가 Point의 getLocation()를 그대로 사용하게 되면 두 좌표의 위치만 출력되므로 이름, 매개변수, 반환타입을 그대로 두고 내용만 세 좌표를 출력하는 로직으로 변경하여 사용할 수 있다.
✔️
super: 자식 클래스에서 부모 클래스로부터 상속받은 멤버를 참조하는 변수
class Piont3D extends Point {
int z;
String getLocation() {
// return "x : " + x + ", y : " + y + ", z : " + z;
return super.getLocation();
}
}
: super.getLocation()을 호출하는 경우, 부모 클래스를 참조하는 super를 통해 Point의 getLocation()을 호출하여 두 좌표의 위치를 출력하게 된다.
클래스 혹은 인터페이스의 묶음
다른 패키지의 클래스를 사용하기 위해 해당 클래스의 패키지를 미리 명시하는 것
package 패키지명;
import 패키지명.클래스명(*);
class 클래스명 { ... }
static 멤버를 호출할 때 클래스 이름 생략 가능
import static java.lang.Math.random;
System.out.println(Math.random());
System.out.println(random());
클래스, 변수, 또는 메서드에 부가적인 의미를 부여
멤버 또는 클래스를 외부에서 접근하지 못하도록 제한
⭐ (넓음) public > protected > (default) > private (좁음)
모든 패키지에서 접근 가능 = 접근 제한이 전혀 없다.
같은 패키지 내 + 다른 패키지의 자식 클래스에서 접근 가능 (클래스 사용 불가)
같은 패키지 내에서만 접근 가능
같은 클래스 내에서만 접근 가능 (클래스 사용 불가)
static이 붙은 멤버는 모든 인스턴스가 값을 공유한다.
final이 붙은 요소는 상수가 되어, 값을 변경할 수 없다.
클래스 : 확장될 수 없는 클래스 ➡️ 상속 불가능 (자식 클래스를 가질 수 없다.)
메서드 : 변경될 수 없는 메서드 ➡️ 오버라이딩 불가능
변수 : 값을 변경할 수 없는 상수 ➡️ 멤버변수의 경우, 생성자를 통한 초기화 가능
abstract가 붙으면 선언부만 작성하고, 실제 수행 내용은 구현하지 않는다.
클래스 : 클래스 내에 추상 메서드가 선언되어있음을 의미한다.
메서드 : 선언부만 작성하고, 구현부는 작성되지 않는 메서드이다.
- 메서드 :
static + abstract사용 불가- 클래스 :
abstract + final사용 불가abstract + private사용 불가
| 대상 | 사용 가능한 제어자 |
|---|---|
| 클래스 | public, default, final, abstract |
| 메서드 | 모든 접근 제어자, final, abstract, static |
| 멤버변수 | 모든 접근 제어자, final, static |
| 지역변수 | final |
부모 클래스 타입의 참조변수로 자식 클래스의 인스턴스 참조 가능
class Tv { // 부모
boolean power;
int channel;
void power() { power != power; }
void channelUp() { ++channel; }
void channelDown() { --channel; }
}
class CaptionTv extends Tv { // 자식
String text;
void caption() {}
}
---
Tv t = new CaptionTv();
t.power();
// t.caption(); // 컴파일 에러 발생
class Parent {
int x = 100;
}
class Child extends Parent {
int x = 200;
}
---
Parent p = new Child(); // 참조변수 : 부모
Child c = new Child(); // 참조변수 : 자식
System.out.println("Parent p.x : " + p.x);
System.out.println("Child c.x : " + c.x);

- 자식 ➡️ 부모 : 형변환 생략 가능 (업캐스팅)
- 부모 ➡️ 자식 : 형변환 생략 불가능 (다운캐스팅)
class Car {}
class FireEngine extends Car {}
class Ambulance extends Car {}
---
Car car = new FireEngine();
FireEngine fe = (FireEngine)new Car();
✔️ ClassCastException : 강제 형변환 시 컴파일 에러는 발생하지 않지만, 자식이 부모를 참조할 수 없으므로 예외가 발생하게 된다.
인스턴스 instanceof 클래스: 인스턴스를 클래스 타입으로 형변환 가능한가? = 클래스 타입의 참조변수로 인스턴스를 참조할 수 있는가?
System.out.println(fe instanceof Car); // 자식 -> 부모
System.out.println(car instanceof FireEngine); // 부모 -> 자식

인스턴스를 생성할 수 없는 클래스 = 미완성 설계도
abstract class 클래스명 {}
일반적으로 추상 메서드를 포함한 클래스를 추상 메서드라고 하는데, 추상 메서드를 포함하지 않아도 인스턴스 생성을 막기 위해 abstrac 키워드를 붙일 수 있다.
추상 클래스는 추상 메서드 외에도 생성자, 멤버변수, 메서드 등을 가질 수 있다.
선언부만 작성하고, 구현부는 작성되지 않은 메서드
abstract 리턴타입 메서드명();
⭐ 추상 메서드는 자식 클래스를 통해 반드시 구현되어야 한다.
abstract class Parent { // 추상 클래스
abstract void play(); // 추상 메서드
}
class Child extends Parent { // 추상 클래스를 상속받은 자식 클래스
void play() { // 추상메서드 구현
...
}
}
- 추상화 : 클래스 간 공통점을 찾아내서 공통 클래스 생성
- 구체화 : 상속을 통해 클래스를 구현, 확장
추상 메서드와 상수만을 멤버로 가질 수 있는 추상 클래스 = 기본 설계도
⭐ class 대신 interface 키워드 사용
interface 인터페이스명 {
[public static final] 타입 상수명 = 값;
[public abstract] 반환타입 메서드명(값1, ...);
}
표준화 가능 : 인터페이스를 통해 프로그램의 기본 틀을 제공하여, 일관되고 정형화된 프로그램 개발 가능
독립적인 프로그래밍 가능 : 선언과 구현을 분리하여, 한 클래스의 변경이 다른 클래스에 영향을 미치지 않는다. ⭐
인터페이스만 상속 가능 + 다중 상속 가능 ➡️
extends
interface Movable {
void move(int x, int y);
}
interface Attackable {
void attack(Unit u);
}
interface Fightable extends Movable, Attackable {
// 상속받은 추상 메서드를 멤버로 가짐
}
클래스를 통해 추상 메서드를 구현해야 함 ➡️
implements
public을 사용했으므로, 구현 시에 public을 명시해야 한다. (생략 시 default이므로 컴파일 에러 발생!)class Fighter implements Fightable {
public void move(int x, int y) {
// 추상 메서드 구현
}
public void attack(Unit u) {
// 추상 메서드 구현
}
}
abstract class Fighter implements Fightable {
public void attack(Unit u) {
// 추상 메서드 구현
}
}
class Fighter extends Unit implements Fightable {
public void move(int x, int y) {
// 추상 메서드 구현
}
public void attack(Unit u) {
// 추상 메서드 구현
}
}
인터페이스 타입의 참조변수로 구현 클래스 인스턴스 참조 및 형변환 가능
Fightable f = new Fighter();
클래스 내에 선언되는 클래스
class A { // 외부 클래스
class B { // 내부 클래스 }
}
두 클래스가 긴밀한 관계일 때, 서로의 멤버에 쉽게 접근할 수 있다. (내부 클래스가 외부 클래스를 제외한 다른 클래스에서는 잘 사용되지 않는 경우)
외부에는 불필요한 클래스를 감추어 복잡성을 줄일 수 있다.
class Outer {
class InstanceInner { // 인스턴스 클래스 }
static class StaticInner { // 스태틱 클래스 }
void MyMethod() {
class LacalInner() { // 지역 클래스 }
}
}
외부 클래스의 인스턴스 멤버들과 관련된 작업에 사용될 목적
외부 클래스의 static 멤버 (메서드)에 사용될 목적
선언된 영역 내부에서만 사용 가능
클래스의 선언과 객체의 생성을 동시에 하는 이름 없는 클래스 = 일회용
new 부모클래스명() {
// 멤버 선언
}
new 구현인터페이스명() {
// 멤버 선언
}
출처 : Java의 정석