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로 만들지 않기 위해서 사용하는 것임.
'멀티캠퍼스 > 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 |