한 클래스의 멤버변수로 다른 클래스 타입의 참조변수를 선언하는 것
=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의 정석