JAVA의 정석
1. 문제
- ByteArrayInputStream input = new ByteArrayInputStream(inSrc)를 생성해서 사용할 때, 왜 input.read()는 exception을 잡을 필요가 없는데 input.read(temp)는 exception을 처리해야 할까?(temp는 byte[]임)
2. 시도
- 코드를 보자. input.read() 메소드의 코드는 ByteArrayInputStream 클래스에 있고, input.read(temp)는 InputStream 클래스에 있다
- 그런데, ByteArrayInputStream의 read()는 InputStream의 read()를 overriding한 것인데, InputStream의 read에는 abstract int read() throws IOException이 있고 ByteArrayInputStream에는 throws가 없다
- 추상 메소드를 구현할 때, 이 메서드 또한 throws Exception을 하지 않아도 되는건가?
- 직접 확인해보자. 추상클래스, 인터페이스 모두 그렇다. 추상 메서드에 throws Exception이 되어있다고 하더라도 구현체는 throws Exception을 안해도된다
3. 해법
- 위 문제로 돌아가서,
- input.read()는 왜 exception을 처리하지 않아도 될까?
① read() 메서드의 InputStream은 throws를 하지만 구현체는 throws 하지 않는다.
- input.read(temp)는 왜 exception을 처리해야 할까?
① read(temp) 메서드는 ByteArrayInputStream에는 overriding이 안되어있으므로 InputStream 것을 사용한다. 그리고 여기에는 throws IOException이 되어있다
4. 알게된 점
- 처음에 추상 메서드에 throws가 선언되어있으면, 구현체에도 throws가 선언되야한다고 생각했다
- 하지만, 반대로 생각했다. 구현체에서 throws를 하려면 추상 메서드에 throws가 있어야한다가 정답이었다
- 그렇다면 그냥 InputStream input = new ByteArrayInputStream(inSrc)를 하면 read()를 하더라도 exception을 처리해야한다. 왜냐하면 InputStream의 read메서드는 exception을 던지기 때문
부트캠프 온보딩 강의
★ 우리가 만들어보는 클래스의 종류
1. 모델이란 무엇인가
(1) 현실에는 다양한 객체가 있고, 그 객체는 역할이 있다 -> 프로그래밍 세계에서는 크게 3개의 역할로 구분한다
(2) 그 객체를 설계하는 것이 모델링
(3) 모델이란 = 클래스를 역할에 따라 부르는 이름이다
(4) 모델의 종류 : [시작 클래스], [DTO, VO], [DAO], [Utility]
① DTO, VO : 데이터를 담는 모델(저장하거나 이동에 편리), Data Transfer Object, Value Object의 줄임말
② DAO : 데이터를 처리하는 모델, DB에 Access해서 처리하는 모델, Data Access Object
③ Utility : 도움을 주는 모델
2. DTO, VO가 왜 필요한가?
(1) 데이터를 하나로 묶어야될 경우 필요함(바구니가 필요, 데이터를 하나로 수집하는 역할임)
(2) 만약 메서드에 인자가 100개라면? 100개를 다 보내줘야함 -> 넘기는 쪽, 받는 쪽 모두 불편
(3) 이 때 DTO, VO를 사용하면 편리
3. DAO가 왜 필요한가?
(1) DB에 데이터(DTO, VO)를 CRUD하기 위해서 만들어지는 클래스
(2) 비즈니스 로직을 처리하는 클래스
4. Utility가 왜 필요한가?
(1) 반복적으로 사용해야될 동작(기능)을 별도의 클래스로 만들어 놓고 필요할 때 사용하기 위해
★ 객체를 접근하는 권한 이해하기
1. 접근권한이란
(1) 객체는 혼자 사용되지 않음 -> 객체는 다른 객체에 의해 사용되기 위해서 만들어짐
(2) 접근을 허용하거나 허용하지 말아야 될 부분을 정해야함 -> 이것이 접근권한
(3) 객체 상호간에 접근을 제어하기 위해서 접근제한자를 사용한다
(4) 젭근제어가 필요한 이유? 객체의 상태정보는 중요해서 접근을 못하게 막야아하므로
(5) 보통 상태 정보는 접근을 막고, 행위 정보는 상호작용을 위해 허용함
(6) 접근을 제한하는 방법 : 클래스와 클래스 내부에 만들어지는 멤버(변수, 메서드)에 모두 사용 가능
① public : 모든 패키지에서 접근 가능
② private : 오로지 자기 자신에서 접근 가능
③ protected : 상속 관계에서 하위 클래스에서 상위 클래스로 접근 가능
④ default : 같은 패키지에서만 접근 가능
1. 문제
- private이 자기 자신에서만 접근이 가능이니깐 상속 관계에서 하위 클래스도 접근을 못하는 것이 맞을까?
2. 시도
- 직접 만들어보자
3. 해결
- 하위클래스도 접근할 수 없었다
4. 알게된 점
- private은 오로지 자기 자신에서만 사용 가능하다
- 그렇다면 상속관계에서 자식 클래스가 부모의 멤버 변수에 접근하려면 어떻게 해야할까?
- protected로 하거나 private을 사용하려면 자식 클래스에서 부모의 getter나 setter를 사용해야함
2. 패키지란 무엇인가
(1) 서로 기능이 비슷한 클래스들끼리 모아서 관리를 쉽게 하기 위해서 사용(폴더 개념임)
(2) 패키지 외부에서 클래스의 접근을 할 수 없도록 사용(보안을 위해, 그렇지만 잘 사용되지 않음)
(3) 자바에서 제공해주는 API도 패키지의 형태로 제공함
3. 클래스를 접근하는 이름 이해하기
(1) 클래스 이름은 크게 두 가지로 나눌 수 있음
① 패키지를 포함하지 않은 클래스 이름 : Scanner
② 패키지를 포함한 클래스 이름 : java.util.Scanner -> java 패키지 안의 util 패키지 안의 Scanner 클래스가 있다는 뜻
(2) 매번 클래스 full name을 적을 수 없으므로 import를 통해 해결한다
(3) import java.util.Scanner을 하면 full name을 쓰지 않고서도 클래스를 사용할 수 있음
(4) import java.lang.*은 작성해주지 않아도 디폴트로 작동한다
1. 문제
- IntelliJ에서 쉽게 도와주는 static import는 어떻게 작성하는 걸까?
2. 시도
- 직접 사용해보자
3. 해결
- import static java.lang.Math.abs 를 할 경우 int a = abs(3.5)처럼 사용할 수 있었음
- import static java.lang.Math.PI 또한 System.out.println(PI)를 할 수 있었음
4. 알게된 점
- static을 import할 때는 'import static'을 적어서 사용한다
★ 잘 설계된 VO 클래스
1. 정보 은닉이란?
(1) 다른 객체에게 자신의 정보를 숨기고, 동작, 기능, 연산만을 통해 접근을 하게끔 하용하는 것
(2) 클래스 외부에서 특정 정보의 접근을 막는 것을 뜻함
1. 문제
- Person class에 private int age 필드를 두고, public void method() 함수에서 Person p = new Person()을 생성한 후 p.age는 사용이 가능할까?
2. 시도
- 직접 해보자
3. 해결
- 가능하다
4. 알게된 점
- private멤버는 해당 클래스에서는 자유롭게 사용할 수 있다
2. setter, getter 메서드 만들기
(1) 은닉된 정보에 접근하기 위해 getter와 setter를 만든다
3. 생성자를 이용한 초기화
(1) 생성자를 이용해서 객체를 초기화할 수 있다
(2) 생성자를 오버로딩해서 다양하게 초기화가 가능하다
1. 문제
- 생성자에서 this.setName(name)을 할 수 있을까?
2. 시도
- 직접 해보자
3. 해결
- 가능하다
4. 알게된 점
- this는 자기 자신을 가리키는 것이므로 멤버변수, 메서드 모두 사용할 수 있다
- 그렇지만 굳이 저렇게 사용하는 것보다 생성자에서는 this.name = name을 사용할 것 같다
1. 문제
- 멤버변수 초기화가 안됐다면, 사용할 수 있을까? 사용할 수 있다면 어떤 값이 들어가있을까?
2. 시도
- 다양한 타입을 모두 시도해보자
3. 해결
- int 멤버변수에는 0이, 객체에는 null이, boolean에는 false, char에는 'NUL'이 초기화가 되어있었음
4. 알게된 점
- 멤버변수는 초기화를 하지 않아도 기본값이 할당이 된다
- 그렇지만 지역변수는 초기화를 꼭 해주어야한다. 그렇지 않으면 컴파일 에러가 남
4. toString() 메서드로 객체값 출력하기
(1) 객체가 갖고 있는 값은 매번 getter로 갖고와서 알아볼 경우 불편함(100개면?)
(2) toString() 메서드를 만들어서 객체 멤버 변수 값을 String으로 받아보자
1. 문제
- 기억상으로 System.out.println(person)을 하면 자동적으로 person.toString()의 결과가 나오는 것으로 알고있는데 어떻게 그럴 수 있을까?
2. 시도
- 직접 해보고 코드를 보자
3. 해결
- 객체의 toString()이 출력된다
- System.out.println(object) 메서드를 보면 object.toString()을 출력하게끔 설계되어있다
4. 알게된 점
- toString() 메서드는 Object 클래스로부터 상속되었으므로, System.out.println(object)를 구현할 수 있다는 것을 깜빡했다... 생각해보면 당연한 것을!!! 조금 더 차분히 생각해보자
5. 잘 설계된 VO 클래스
(1) 설계 방법
① 모든 상태정보를 정보 은닉하기(private)
② 디폴트 생성자 만들기(사용하지 않더라도)
③ 생성자 오버로딩으로 객체 초기화
④ getter, setter
⑤ toString() 메서드 만들기(객체가 갖고 있는 전체값 출력 목표)
코테준비
1. 프로그래머스 - 뒤에 있는 큰 수 찾기
: N이 100만이므로 바로 떠오르는 방법인 이중 for문으로 해결할 수 없다. 이럴 경우 특별한 '자료구조'나 '알고리즘'을 사용해서 풀어야하는데, 정렬 알고리즘에만 꽂혀서 어떻게 풀지 고민하다가 다른 사람의 풀이를 보고 Stack 자료구조를 사용해야함을 알게되었다. '자료구조'를 이용해서 푸는 방법이 있다는 것을 명심하자
2. 프로그래머스 - 최솟값 만들기
: 두 배열을 정렬한 후 하나는 앞에서 하나는 뒤에서부터 탐색하며 서로를 곱해서 합을 구한다
Java책 필수적으로 완독하자. 오늘도 고생했다!