본문 바로가기
멀티캠퍼스/Spring

20230809 (수)

by 세크레투스 2023. 8. 9.
반응형
SMALL

1. 복습

- static : 다른 언어의 전역변수의 역할을 할 수도 있음. 하지만, 전역변수는 버그의 온상이기 때문에...

상수정의 할 때 자주 쓰임.

static final 상수명

- life time

- access scope

- singleton : 상태가 하나만 있는 경우 (인스턴스가 하나만 있는 경우)

* class XXX : 클래스 이름 자체는 싱글턴일 필요는 없다. (우리가 임의로 정함.)

* 생성자 : xxx () { ... } -> 외부에서 임의로 호출 못하게끔 막음.

* private static xxx instance -> xxx.instance = null;

* static xxxx getInstance

 

static에 대해서 좀 더 공부해야 할 것 같음.

 

- 상속

 class XXX extends Parent { ... }

객체 둘 사이에 관계가 생기는데, 이를 UML이라고 함.

 - 상속을 쓰는 목적

1) 코드 재사용

2) Override

- this() : 나의 다른 생성자 호출 (자신의 참조)

- super() : 부모에 대한 참조, default 생성자에서 가장 먼저 실행해야 함. 내가 명시하지 않으면, 부모의 default 생성자의 호출문을 컴파일러가 자동으로 넣어줌.

- override : 메서드 재정의

1) 그냥 사용하는 것.

2) 완전히 대체하는 것.

3) 같이 사용하는 것. (부모 메소드, 자신의 코드를 모두 사용할 때) -> 이게 일반적으로 가장 많이 쓰이는 형태임.

메소드의 시그니처가 완전히 똑같아야 함.

리턴타입, 이름(매개변수)

실수를 방지하기 위해서 체크 의뢰 : @Override

@을 annotation이라고 함.

 

<타입변환과 다형성>

1. 자동 타입 변환(Promotion)

- 프로그램 실행 도중에 자동 타입 변환이 일어나는 것.

부모에서 정의한 것을 자식은 다 갖고 있음. 부모에서 정의한 것을 다 받아와도 됨. -> Upcasting (암묵적인 허용)

자식에서 정의한 것을 부모에서 받아옴..? -> Downcasting -> 다 되는 것은 아니고, 상황에 따라서 될 수도, 안될 수도 있음.

실제로 힙(Heap) 영역에는 부모, 자식 생성자가 모두 다 있음.

부모의 참조로 자식인스턴스를 가리키고, 그때 override된 메소드를 호출.

 

<SOLID 원칙>

 

앞으로의 모든 전개는 이 법칙(Override)을 통해서 전개가 됨.

 

2. 본수업

<타입변환과 다형성>

1. 필드의 다형성

- 다형성을 구현하는 기술적 방법

 * 부모 타입으로 자동변환

 * 재정의된 메소드(오버라이딩)

우리 프로그램의 구조를 UML로 표현할 수 있어야 함.

⃟ : 바꿀 수 있는 멤버변수라는 의미 (aggregation)

◆ : 바꿀 수 없는 멤버변수라는 의미 (composition)

→ : 왼쪽이 오른쪽을 사용하고 있다는 의미

⬆ : 아래쪽이 위쪽의 자식이라는 의미 (바꿔말하면, 위쪽이 아래쪽의 부모라는 의미)

- 결합도는 낮추고, 응집도는 높여야 한다. (시험에 자주나옴)

== aggregation && SRP 하게 코드를 짜야함.

 

2. 매개변수의 다형성

- 매개변수가 클래스 타입을 경우

* 해당 클래스의 객체 대입이 원칙이나 자식 객체 대입하는 것도 허용

** 자동 타입 변환

** 매개변수의 다형성

<설명>

- Driver는 Vehicle의 매개변수를 사용중이고, Driver2는 Taxi의 매개변수만 사용중이다.

- Driver는 Vehicle의 자식인 Taxi, Bus, Truck 등등으로 Vehicle을 바꿀 수 있지만, Driver2는 Taxi이외에는 Vehicle을 변경할 수 없다.

- 만약에, Driver2가 다른 Vehicle을 운전하고 싶다면, 다른 자식 클래스들을 참조하는 매개변수를  Over Loading 해줘야 함.

public void drive(Bus bus) {

bus.run();

bus.stop();

}

 

public void drive(Truck truck) {

truck.run();

truck.stop();

}

...

- 차라리 이렇게 번거로울 바엔, 부모 클래스인 Vehicle을 매개변수로 참조하는 것이 더 편리하게 사용할 수 있음.

- Driver 클래스는 다른 클래스를 참조하고 싶을 때 매개변수만 변경하면 되고, 나머지 코드는 변경사항이 없음.

- 이를 OCP(Open-Closed Principle)라고 함.

- 이를 전략패턴이라고 함. (Strategy Pattern)

<설명>

- Dependency Injection : 필요로 하는 것을 매개변수로 전달받겠다는 뜻.

- 이 방법도 결합도를 낮추는 방법으로 유명하다. (외부에서 주입되게끔.)

- 결국 A가 B를 이용한다는 뜻은, A가 B를 의존한다는 뜻이다. 그래서 Dependency라고 부르는 것이다.

- UpCasting을 이용한 사례이다.

 

3. 강제 타입 변환(Casting)

- 부모 타입을 자식 타입으로 변환하는 것

자식클래스 변수 = (자식클래스) 부모클래스타입; //자식 타입이 부모 타입으로 변환된 상태, 강제 타입 변환

- 조건

* 자식 타입을 부모 타입으로 자동 변환 후, 다시 자식 타입으로 변환할 때

- 강제 타입 변환이 필요한 경우

* 자식 타입이 부모 타입으로 자동 변환 : 부모 타입에 선언된 필드와 메소드만 사용 가능

* 자식 타입에 선언된 필드와 메소드를 다시 사용해야 할 경우

 

4. 객체 타입 확인(instanceof)

- 부모 타입이면 모두 자식 타입으로 강제 타입 변환할 수 있는 것은 아님.

- ClassCastExceptioin 예외 발생 가능

Parent parent = new Parent();

Child cild = (Child) parent; //강제 타입 변환을 할 수 없다.

- 먼저 자식 타입인지 확인 후 강제 타입 실행해야 함

boolean result = 좌항(객체) instanceof 우항(타입)

 

<추상 클래스>

1. 추상 클래스 개념

- 추상 (abstract)

* 실체들 간에 공통되는 특성을 추출한 것

** 예1 : 새, 곤충, 물고기 -> 동물 (추상)

** 예2 : 삼성, 현대, LG -> 회사 (추상)

- 추상 클래스 (abstract class)

* 실체 클래스들의 공통되는 필드메소드 정의한 클래스

* 추상 클래스는 실체 클래스의 부모 클래스 역할 (단독 객체 X)

- 다형성이 있으려면 상속관계가 있어야 한다. (기본)

 

2. 추상 클래스의 용도

- 실체 클래스의 공통된 필드와 메소드의 이름을 통일할 목적

* 실체 클래스를 설계자가 여러 사람일 경우, 실체 클래스마다 필드와 메소드가 제각기 다른 이름을 가질 수 있음.

 

3. 추상 클래스 선언

- 클래스 선언에 abstract 키워드 사용

* New 연산자로 객체생성하지 못하고, 상속을 통해 자식 클래스만 생성 가능.

 

4. 추상 메소드와 오버라이딩(재정의)

- 메소드 이름 동일하지만, 

- 파일처리 클래스 : abstract 클래스임.. 그래서 예제 건너뛰었었는데 지금 배울 것임.

 

<인터페이스>

추상메서드로만 구성된 추상클래스..?

1. 인터페이스란?

- 개발 코드와 객체가 서로 통신하는 접점

- 개발코드는 인터페이스의 메소드만 알고 있으면 OK

 

2. 인터페이스의 역할

- 개발 코드가 객체에 종속되지 않게 -> 객체 교체할 수 있도록 하는 역할

- 개발 코드가 변경 없이 리턴값 또는 실행 내용이 다양해질 수 있음 (다형성)

 

3. 인터페이스 선언

- 인터페이스 이름 : 자바 식별자 작성 규칙에 따라 작성

 

4. 추상 메소드 선언 (생략)

 

<인터페이스 구현 (Implemetation)>

1. 구현 객체와 구현 클래스

- 인터페이스의 추상 메소드에 대한 실체 메소드를 가진 객체 = 구현 객체

 

2. 구현 클래스 선언

- 자신의 객체가 인터페이스 타입으로 사용할 수 있음

* implements 키워드로 명시

 

3. 익명 구현 객체 ( == 자바스크립트의 add(function) { ... } ) -> 백엔드에서 잘 안쓰임. 넘어가~

 

4. 다중 인터페이스 구현 클래스

 

5. 인터페이스 사용

- 인터페이스에 구현 객체를 대입하는 방법

- 1번보단 2번으로 대입하는 방법을 선호하는데, 그 이유는 결합도 때문이다. : 함수를 통해서 변수를 파라미터로 넣어주므로, 값을 직접 넣지 않고, 파라미터 값에 따라 변수에 들어가는 값이 얼마든지 변경 가능함.

==> 이것을 D.I.(Dependency Injection) 라고 한다.

 

<인터페이스가 필요한 이유>

 

- 인터페이스는 표준의 역할을 함.

- 예를 들어서 한 프로젝트에 개발자 3명이 투입된다고 했을 때,

 

- 싱글턴 패턴은 로그인시 DB에서 유저의 정보를 담아올때 자주 사용된다고 함.

 

<예외와 런타임 예외>

1. 오류의 종류

- 에러 (Error)

* 하드웨어의 잘못된 동작 또는 고장으로 인한 오류

* 에러가 발생되면 프로그램 종료

* 정상 실행 상태로 돌아갈 수 없음

 

- 예외 (Exception)

* 사용자의 잘못된 조작 또는 개발자의 잘못된 코딩으로 인한 오류

* 예외가 발생되면 프로그램 종료

* 예외 처리 추가하면 정상 실행 상태로 돌아갈 수 있음

 

2. 예외의 종류

- 일반(컴파일 체크) 예외(Exception) : 예외 처리 코드 없으면 컴파일 오류 발생 (강제로 반드시 해야 함)

- 실행 예외(RuntimeException)

* 예외 처리 코드를 생략하더라도 컴파일이 되는 예외

* 경험 따라 예외 처리 코드 작성 필요

- 컴파일러가 예외적으로 체크 안해주는 경우 : 배열

<예외 처리 코드 (try - catch -finally)>

-예외 처리 코드

- Class 라는 클래스가 있음.

- class는 변수명으로 못사용해서 위 예제에서 clazz라고 한거임.

예제

- main 메서드 안에

Class clazz = Class.forName("java.lang.String2");

이것만 작성하면  class 예외가 발생하면서 try~catch문을 작성할 수 있게 해준다.

 

Exception 예외는 맨 마지막에 쓰거나, 혼자만 사용해야 함.

왜냐하면 모든 에러가 Exception 안에 포함되므로.

 

첫번째 예제처럼 예외처리시 Exception을 맨 처음에 놓으면 에러가 발생한다. (Unreachable 에러)

 

- 보통은 예외처리를 Exception 으로 퉁치곤 함..ㅋㅋ 하지만 무슨 에러인지는 알아야 하기에...!

System.err.println(e);

이렇게 처리를 해줌.

 

그리고 어느 줄에서 났는지 알고싶을땐

e.printStackTrace();

이렇게 해줌. -> 어느 메소드 호출에 의해서 이 에러가 발생했는지를 알려달라는 뜻임.

 

try~catch~finally 구문에서

- finally가 생략되면 catch가 반드시 있어야 하며,

- catch가 생략되면 finally가 반드시 있어야 함.

 

<예외 떠넘기기, 사용자 정의 예외>

1.  throws

* 메소드 선언부 끝에 작성

리턴타입 메소드명(매개변수, ...) throws 예외클래스1, 예외클래스2, ... { ... }

 

* 메소드에서 처리하지 않은 예외를 호출한 곳으로 떠넘기는 역할

 

<사용자 정의 예외>

1. 사용자 정의 예외 클래스 선언

- 자바 표준 API에서 제공하지 않는 예외

- 애플리케이션 서비스와 관련된 예외

* Ex) 잔고 부족 예외, 계좌 이체 실패 예외, 회원 가입 실패 예외 등...

- 사용자 정의 예외 클래스 선언 방법

public class XXXException extends [ Exception | RuntimeException ] {

    public XXXException() { }

    public XXXException(String message) {super(message);}

}

 

2. 예외 발생 시키기

- 코드에서 예외 발생시키는 법

throw new XXXException();

public void withdraw(int money) throws BalanceInsufficientException {

if (balance < money) {

throw new BalanceInsufficientException("잔고부족: " + (money - balance) + " 모자람");

}

balance -= money;

}

==> 예외처리 클래스에서 throws 인 이유 : 예외처리를 여러 개 할 수 있으므로.

 

[다음시간에 배울 내용]

주요 utility 클래스 {System, String...} -> 제너릭 -> 콜렉션(List) -> 파일처리 -> 스레드 -> 네트워크

 

시험문제 볼때는 수박겉핥기 식으로 봐야함. (범위가 너무 많아서..)

문제 수준도 그 정도 수준(낮은 난이도)에서 나옴..

1시간동안 봄

 

 

상속(extends)으로 코드 재사용을 할때, 일반클래스에서 하는게 더 좋을때와 abstract 클래스에서 하는 게 더 좋을때는 구체적으로 어떤 상황이 있을까요..?

  • 목적에 따라서 일반클래스로 상속하거나, abstract 클래스로 상속하는 거임.
  • 상속에서는 큰 의미가 없음.
  • 부모타입으로 운영하기위해서 상속을 하는것이기 때문에.
  • Abstract 사용하는 이유는 전체를 interface 만들지 않기 위해서 사용하는 것임.
반응형
LIST

'멀티캠퍼스 > Spring' 카테고리의 다른 글

20230811 (금)  (0) 2023.08.12
20230810 (목)  (0) 2023.08.10
20230808 (화)  (0) 2023.08.08
20230807 (월)  (0) 2023.08.07
20230731 (월)  (0) 2023.08.04