[Java의 정석] 7. 객체 지향 프로그래밍 (2)

진예·2023년 12월 27일
0

JAVA

목록 보기
5/10
post-thumbnail

💡 클래스 간의 관계

📒 포함 (Composite)

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

📒 상속 (Inheritance)

기존의 클래스재사용하여 새로운 클래스를 작성하는 것
= 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 {}

📝 오버라이딩 (Overriding)

부모 클래스로부터 상속받은 메서드의 내용을 변경하는 것

  • 부모 클래스의 메서드와 이름이 같아야 한다.
  • 부모 클래스의 메서드와 매개변수가 같아야 한다.
  • 부모 클래스의 메서드와 반환타입이 같아야 한다.

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;
	}
}

: PointgetLocation() 메서드는 두 좌표의 위치를 출력한다. Point3DPoint의 두 좌표에 z좌표를 추가하여 총 세 좌표의 위치를 출력해야 한다.

이 때, Point3DPointgetLocation()를 그대로 사용하게 되면 두 좌표의 위치만 출력되므로 이름, 매개변수, 반환타입을 그대로 두고 내용세 좌표를 출력하는 로직으로 변경하여 사용할 수 있다.

✔️ super : 자식 클래스에서 부모 클래스로부터 상속받은 멤버를 참조하는 변수

class Piont3D extends Point {
	int z;
	
	String getLocation() {
		// return "x : " + x + ", y : " + y + ", z : " + z;
		return super.getLocation();
	}
}

: super.getLocation()을 호출하는 경우, 부모 클래스를 참조하는 super를 통해 PointgetLocation()을 호출하여 두 좌표의 위치를 출력하게 된다.


💡 패키지 (Package)

클래스 혹은 인터페이스의 묶음

📒 import문

다른 패키지의 클래스를 사용하기 위해 해당 클래스의 패키지미리 명시하는 것

package 패키지명;
import 패키지명.클래스명(*);

class 클래스명 { ... }

📝 static import문

static 멤버를 호출할 때 클래스 이름 생략 가능

import static java.lang.Math.random;

System.out.println(Math.random());
System.out.println(random());

💡 제어자 (modifier)

클래스, 변수, 또는 메서드부가적인 의미를 부여


📒 접근 제어자 (access modifier)

멤버 또는 클래스외부에서 접근하지 못하도록 제한

⭐ (넓음) public > protected > (default) > private (좁음)


📝 public

모든 패키지에서 접근 가능 = 접근 제한이 전혀 없다.

📝 protected

같은 패키지 내 + 다른 패키지자식 클래스에서 접근 가능 (클래스 사용 불가)

📝 default

같은 패키지 내에서만 접근 가능

📝 private

같은 클래스 내에서만 접근 가능 (클래스 사용 불가)

  • 캡슐화 (encapsulation) : 데이터를 외부에서 함부로 변경하지 못하도록 값을 숨기는 것

📒 기타 제어자

📝 static : 클래스의, 공통적인

static이 붙은 멤버모든 인스턴스값을 공유한다.

  • 멤버변수 : 클래스가 메모리에 로딩될 때 생성되어 인스턴스생성하지 않아도 사용 가능하며, 모든 인스턴스같은 값을 가진다.
  • 메서드 : 인스턴스생성하지 않아도 호출 가능하며, 메서드 내에서 인스턴스 변수사용할 수 없다.

📝 final : 변경될 수 없는

final이 붙은 요소는 상수가 되어, 값을 변경할 수 없다.

  • 클래스 : 확장될 수 없는 클래스 ➡️ 상속 불가능 (자식 클래스를 가질 수 없다.)

  • 메서드 : 변경될 수 없는 메서드 ➡️ 오버라이딩 불가능

  • 변수 : 값을 변경할 수 없는 상수 ➡️ 멤버변수의 경우, 생성자를 통한 초기화 가능


📝 abstract : 추상의, 미완성의

abstract가 붙으면 선언부만 작성하고, 실제 수행 내용은 구현하지 않는다.

  • 클래스 : 클래스 내추상 메서드가 선언되어있음을 의미한다.

  • 메서드 : 선언부만 작성하고, 구현부는 작성되지 않는 메서드이다.


➕ 제어자의 조합

  • 메서드 : static + abstract 사용 불가
  • 클래스 : abstract + final 사용 불가
  • abstract + private 사용 불가
대상사용 가능한 제어자
클래스public, default, final, abstract
메서드모든 접근 제어자, final, abstract, static
멤버변수모든 접근 제어자, final, static
지역변수final

💡 다형성 (Polymorphism)

부모 클래스 타입의 참조변수자식 클래스의 인스턴스 참조 가능

  • 참조변수의 타입이 부모 클래스이기 때문에, 자식 타입의 인스턴스를 참조하더라도 자식 타입에 추가된 멤버에는 접근 불가능 (상속된 멤버에만 접근 가능)
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 연산자

인스턴스 instanceof 클래스 : 인스턴스클래스 타입으로 형변환 가능한가? = 클래스 타입의 참조변수로 인스턴스참조할 수 있는가?

System.out.println(fe instanceof Car); // 자식 -> 부모
System.out.println(car instanceof FireEngine); // 부모 -> 자식


💡 추상 클래스 (abstract class)

인스턴스생성할 수 없는 클래스 = 미완성 설계도

abstract class 클래스명 {}

일반적으로 추상 메서드를 포함한 클래스를 추상 메서드라고 하는데, 추상 메서드를 포함하지 않아도 인스턴스 생성을 막기 위해 abstrac 키워드를 붙일 수 있다.

추상 클래스는 추상 메서드 외에도 생성자, 멤버변수, 메서드 등을 가질 수 있다.


📒 추상 메서드 (abstract method)

선언부만 작성하고, 구현부는 작성되지 않은 메서드

abstract 리턴타입 메서드명();

⭐ 추상 메서드는 자식 클래스를 통해 반드시 구현되어야 한다.

abstract class Parent { // 추상 클래스
	abstract void play(); // 추상 메서드
}

class Child extends Parent { // 추상 클래스를 상속받은 자식 클래스
	void play() { // 추상메서드 구현
    	...
    }
}

➕ 추상화

  • 추상화 : 클래스 간 공통점을 찾아내서 공통 클래스 생성
  • 구체화 : 상속을 통해 클래스를 구현, 확장

💡 인터페이스 (Interface)

추상 메서드상수만을 멤버로 가질 수 있는 추상 클래스 = 기본 설계도

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();

💡 내부 클래스 (Inner class)

클래스 내에 선언되는 클래스

class A { // 외부 클래스

	class B { // 내부 클래스 }
    
}
  • 두 클래스긴밀한 관계일 때, 서로의 멤버에 쉽게 접근할 수 있다. (내부 클래스가 외부 클래스를 제외한 다른 클래스에서는 잘 사용되지 않는 경우)

  • 외부에는 불필요한 클래스감추어 복잡성을 줄일 수 있다.


📒 종류

class Outer {
	class InstanceInner { // 인스턴스 클래스 }
    static class StaticInner { // 스태틱 클래스 }
	
    void MyMethod() {
    	class LacalInner() { // 지역 클래스 }
    }
}

📝 인스턴스 클래스 (instance class)

외부 클래스인스턴스 멤버들과 관련된 작업에 사용될 목적

  • 외부 클래스멤버변수 선언 위치에 선언 = 인스턴스 멤버

📝 스태틱 클래스 (static class)

외부 클래스static 멤버 (메서드)에 사용될 목적

  • 외부 클래스멤버변수 선언 위치에 선언 = static 멤버

📝 지역 클래스 (local class)

선언된 영역 내부에서만 사용 가능

  • 외부 클래스메서드초기화 블럭 안에 선언

📝 익명 클래스 (anonymous class)

클래스선언객체의 생성동시에 하는 이름 없는 클래스 = 일회용

new 부모클래스명() {
	// 멤버 선언
}

new 구현인터페이스명() {
	// 멤버 선언
}

출처 : Java의 정석

profile
백엔드 개발자👩🏻‍💻가 되고 싶다

0개의 댓글