또 다시 공부를 시작해야 되는게 암울했지만 매일 지날수록 적응이 되고 새로운 것들을 알아가는 것, 아는 건 다시 복습할 수 있는 시간이 좋은 것 같다.
새로 알게된 거 위주로 써보려고 한다.
7/3
부끄럽게도 디버깅이 뭔지 몰랐다. 학교 다닐 땐 한 번도 실행시켜본 적이 없다.
디버깅은 코드번호 옆에 누르면 빨간 점이 생기는데 Run이 아닌 Debug로 실행하면 그 코드라인 전까지 실행이 된다.
-종류 네가지
step over : 하위구조가 있어도 그냥 넘어감
step into : 하위구조가 있으면 타고 들어감
step out : step into에서 타고 들어왔던 하위구조에서 다시 원래 위치로 돌아옴
Run to Cursor : 특정 코드에 마우스 커서 두고 누르면 해당 줄까지 실행됨.
- 변수 이름 규칙
문자, 숫자, _, $ 사용가능
숫자 시작 X
- 카멜 표기법 : 가장 많이 쓰임 ex) myName
- 자료형 :
2진 (0b) , 8진 (0), 16진 (0x)
float 는 뒤에 반드시 f표시를 해야함. 이걸 몰랐었다..
- String 메소드 : equals, indexOf, replace, substring, toUpperCase/toLowerCase
- StringBuffer : String에도 문자열 붙이기가 가능하나 빈번한 추가, 삭제시 사용.
StringBuffer sb = new StringBuilder();
sb.append(" ");
7/4
- 자료형 :
- 리스트 : 배열과 같이 여러 데이터를 담을 수 있는 자료형. ArrayList l1 = new ArrayList();
add,get,size,remove,clear,sort,contains
list.sort(Comparator.naturalOrder()); //오름차순 정렬
list.sort(Comparator.reverseOrder()); //내림차순 정렬
- 맵 : key, value 형태로 데이터 저장. HashMap map = new HashMap(); //제네릭 적용 안 한 케이스
(인덱스로 접근 X, 값 저장한 순서대로 저장되지 않음.)
put,get,size,remove,containsKey
- 제네릭스 : 자료형을 명시적으로 지정. 제한적일 수 잇으니 안정성이 높고 형 변환 가능성이 적다.
ArrayList <String>l1 = new ArrayList<>();
HashMap <String,String> map = new HashMap<>();
* list.remove(인덱스); //인덱스 대신 Integer.valueOf(2)를 쓰면 2의 인덱스를 반환함
- for each 문
for(int num : nums) int형 배열 nums에서 num이라는 변수로 요소 하나씩 접근
- 연습문제 별 문제가 있었음. 헷갈렸어
*
***
*****
*******
7/5
- 다차원 배열
for each로 출력해보기
1차원 2차원
for(int i : myArray) for(int[] ints:myArray) //2차원 배열에서 행 하나를 접근
sout(i); for(int i : ints) sout(i) //행 하나에서 열 하나씩 접근
-클래스와 객체 1
메소드, 클래스 나왔고
- this. VS this()
this.는 자기 자신의 객체를 의미. 생성자에서 많이 씀
this()는 한 생성자 안에서 다른 생성자를 호출할 때 씀. 매개변수를 넣어주면 그것과 매칭되는 생성자 호출됨.
-클래스와 객체 2
- 오버로딩 : 한 클래스 내에 이름이 동일한 메소드 여러개. 매개변수의 타입,갯수는 무조건 달라야함. 반환형, 접근지정자는 관계 X
- 접근지정자 : public, protected, default, private
- static : 변수나 메소드의 특성을 바꾸는 키워드. static 변수 / 메소드는 객체 생성 전부터 메모리에 위치.
특징 : 메모리에 한 번만 할당. 즉 static 변수/ 메소드는 공유됨.
static 클래스 변수 : 해당 클래스의 각 객체들이 값을 공유
static 클래스 메소드 : 객체 생성 안 해도 클래스 이름으로 호출 가능.
- 상속
- supper, supper()
supper : 부모클래스와 자식클래스 멤버 이름이 같을 때 구분.
super() : 부모클래스의 생성자 호출할 때 사용.
ex)
class Animal {
String desc;
Animal() {
this.desc = "동물 클래스 입니다.";
}
Animal(String desc) {
this.desc = desc;
}
public void printInfo() {
System.out.println(this.desc);
}
}
class Cat extends Animal {
String desc;
Cat() {
//this.desc = "고양이 입니다.";
//super.desc = "고양이 입니다.";
super("고양잉이이이");
}
}
- 오버라이딩 : 상속관계에서만 ! 부모 클래스의 메소드를 자식 클래스에서 재정의.
조건 : 메소드 선언부는 부모클래스의 메소드와 동일해야함.
반환타입 한정으로, 부모클래스의 반환타입으로 변환할 수 있는 타입으로 변경가능.
부모 클래스 메소드보다 더 좁은 범위의 접근제어자 불가.
부모 클래스 메소드보다 더 큰 범위의 예외선언 불가.
- 다형성 : 한 객체가 여러가지 타입을 가질 수 있는 것.
부모타입의 참조변수로 자식클래스 인스턴스 참조
class Person{
}
class Student extends Person{
} 이라는 코드가 있을 때
메인에서 Person p1 = new Student(); 요런식으로 업캐스팅(자식 클래스의 객체가 부모 클래스의 객체로 형변환) 해주는 것 !
실제 생성되는 건 Student타입의 객체. 부모 -> 자식 쪽으로만 참조 가능. 역은 안 됨
이때 p1은 부모타입의 객체 참조변수라 자식 쪽은 접근이 불가 (원래 Student인데 잠시 업캐스팅 되어 type만 Person)
이때는 다운캐스팅을 해줘야 한다. Student s1 = (Student) p1 ; 이렇게
이게 좀 이해하기가 어려웠다. 다형성하면 개념은 알겠는데 굳이 왜 쓰는지 ?
그 예시가
Car car2[] = {new Car(), new Firetruck(), new Ambluance()};
for(Car item : car2)
item.horn();
다형성 덕분에 Car이라는 부모 클래스 객체 하나로 상속받은 자식 클래스를 모두 가리킬 수가 있게됨.
더 이해하기 쉽게 공부해보았다.
다형성이란 하나의 메소드나 클래스가 있을 때 이것들이 다양한 방법으로 동작하는 것
오버로딩은 가장 쉬운 다형성의 예라고 한다.
오버로딩은 ? 이름이 같고 매개변수의 타입이나 갯수가 다른 여러 개의 메소드를 두는 것.
어떻게 보면 하나의 이름을 가진 메소드를 다양한 방식으로 쓰는 것이라 말이 되는 거 같다.
다형성 - Java (opentutorials.org)
이 블로그 참조하여 기본적인 이해를 마쳤고 추가 사례를 더 알아보기 위해 chatGPT에 물어봤다.
1. 상속 관계에서의 다형성: 부모 클래스 타입으로 자식 클래스의 객체를 참조할 수 있습니다. 이를 통해 여러 종류의 자식 객체를 하나의 부모 타입으로 관리하고, 동일한 부모 클래스의 메서드를 호출하여 다양한 동작을 수행할 수 있습니다.
2. 인터페이스를 이용한 다형성: 인터페이스는 일종의 계약으로, 클래스가 해당 인터페이스를 구현한다는 것을 보장합니다. 인터페이스를 타입으로 사용하면 해당 인터페이스를 구현한 다양한 클래스의 객체를 동일한 타입으로 다룰 수 있습니다. 이를 통해 객체들 간에 결합도를 낮추고 유연한 코드를 작성할 수 있습니다.
3. 메서드 오버라이딩을 통한 다형성: 자식 클래스에서 부모 클래스의 메서드를 재정의하는 것을 메서드 오버라이딩이라고 합니다. 이를 활용하면 부모 클래스의 타입으로 호출하더라도 실제로는 자식 클래스의 재정의된 메서드가 호출되어 다형성을 구현할 수 있습니다.
4. 매개변수의 다형성: 메서드의 매개변수로 부모 클래스 타입을 사용하면 해당 부모 클래스 및 그를 상속한 자식 클래스의 객체를 모두 전달할 수 있습니다. 이를 통해 하나의 메서드로 다양한 객체를 처리할 수 있습니다.
다형성을 적절하게 활용하면 코드의 유연성을 높이고, 재사용성을 높여 쉽게 확장 가능한 프로그램을 작성할 수 있습니다.
라고 한다.
사실 이미 다 해본 거고 알고있었는데 개념을 연결짓는게 어려웠던 것 같다.
너무 어렵게 생각하지말자 ! 그냥 하나의 클래스나 메소드를 여러방면으로 쓰이게 하는 것 !
- 추상클래스 & 추상메소드
추상메소드 : 본문이 없고 선언만 되어있는 메소드
추상클래스 : 추상메소드를 하나라도 가진 클래스.
추상클래스는 자체적으로 객체 생성이 불가능.
- 상속클래스에서 구현해서 쓰기
- Main에서 익명 클래스로 구현해서 사용
*익명클래스란 ? 이름이 없고 선언과 동시에 객체생성. 일회용
클래스이름 참조변수이름 = new 클래스이름() { ... } ;
- 인터페이스
추상메소드와 상수만으로 이루어짐.
다중상속처럼 사용가능. (하나의 자식이 여러 부모를 참조하는 것)]
ex) class C implements A, B {}
7/6
- 내부클래스 (클래스 in 클래스) 객체 생성해서 쓰는 방법을 처음 봤다 !
클래스 내부에서 클래스 외부 멤버 자유롭게 접근 가능. 그 반대는 불가
종류 : 인스턴스 클래스, 정적클래스, 지역클래스, 익명클래스
- 인스턴스 클래스 : 밖 클래스 객체를 만들어야 내부 클래스 사용 가능
Outer.Inner i = new Outer().new Inner();
- 정적클래스 : static 키워드가 붙어서 외부 클래스가 만들어지기 전부터 메모리에 상주. 외부 클래스 객체 생성 안 하고도 사용가능.
Outer.InnerStaticClass is1 = new Outer.InnerStaticClass(); //정적클래스라 외부클래스 객체 안 만들어주고도 외부클래스 이름.내부클래스이름으로 접근 가능.
- 지역클래스 : 클래스 안에 메소드 안에 위치한 클래스
- 익명클래스 : 이름을 가지지 않음. 선언과 동시에 객체 생성, 일회용
Person 이라는 추상클래스에 printInfo라는 추상메소드가 있을 때
Person p1 = new Person() {
@Override
public void printInfo() { System.out.println("안녕"); } ; //Person에 있는 추상메소드 구현.
}
- 입출력
1. 콘솔입출력
콘솔 입력 : System.in.read(), InputStreamReader reader = , BufferedReader br = , Scanner scanner =
- System.in.read() : char형태로 값 하나만! 받음 123 입력해도 1만 들어가게됨. 문자형태로 받으니까 -'0'을해서 숫자로 변환해줘야함. 데이터 입력하고 enter 누르면 enter도 저장돼서 소진해줘야함. (0이 아스키코드값 48)
소진 : System.in.read(new byte[System.in.available()]); //이 줄 없으면 1 enter했을 때 남은 enter값이 아래 입력으로 들어감. // 첨 보는 방식이라 낯설다.
- InputStreamReader reader = new InputSreamReader(System.in);
char c[] = new char[3];
reader.read(c); //읽고자하는 배열 갯수를 지정해서 읽기 가능.
sout(c);
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
한창 백준 알고리즘 풀면서 Scnner도 까먹을 정도로 많이 사용했는데 안 쓰다보니까 또 낯설어졌다 .. ㅋ
- Scanner 너무 잘 쓰고 있으니 생ㄱ략
콘솔 출력 : System.out.println/print/pritnf
2. 파일입출력 // 또한 부끄럽게도 .... 파일 입출력을 자바배우고 처음 알았다.
파일 출력 : 파일로 출력
- FileOutputStream
- FileWriter
FileWriter fw = new FileWriter("경로");
String memo = "헤드라인\n";
fw.write(memo);
memo = "1월 28일 소은 생일\n";
fw.writer(memo);
fw.close();
* 파일 이어쓰기 : 객체 선언 생성 동일한데 객체 다른 이름으로 하나 만들고 경로 다음에 매개변수로 ,true를 넣어줌.
- PrintWriter : FileWriter과 다른 점은 println이 있어서 줄바꿈을 문자열에 추가해주지 않아도 된다.
PrintWriter pr = new PrintWriter("경로");
String memo = "헤드라인";
pr.println(memo);
pr.close();
* 파일 이어쓰기 : 객체 생성시 매개변수 안에 FileWriter를 만들어서 넣어줘야함. 상당히 귀찮네
PrintWriter pr2 = new PrintWriter(new FileWriter("경로",true));
파일 입력 : 파일에서 읽어들이는 입력
- FileInputStream
- BufferedReader
BufferedReader br = new BufferedReader(new FileReader("경로"));
while(true){
String line = br.readLine();
if(line == null) break;
else System.out.print(line);
//println안 해준 이유는 이미 파일 저장할 때 println으로 저장해서 줄바꿈이 되어있음.
}
- 예외 : 정상적이지 않은 케이스 ex) 0으로 나누기, 배열인덱스 초과, 없는 파일 열기 etc...
- 예외처리 : 정상적이지 않은 case에 대한 적절한 처리 방법
try{
//오류발생가능코드
}catch(){
//어떻게 해결할 건지 !
}finally{
//오류발생여부 상관없이 무조건 실행되는 코드
}
* throw : 예외발생
... 함수명() { throw new Exception(); }
* throws : 예외를 호출한 쪽으로 전가시킴.
...함수명() throws xxxException { } 함수내부에서 예외 발생했을 경우 함수를 호출한 쪽으로 예외를 전가시킴.
//throw 예제
class NotTenException extends RunTimeException{ }
//사용자가 예외를 직접 만들어줌. 여기서 중요한 건 RunTimeException을 무조건 상속받아야함 !
public class Main{
public void ten(int num){
try{
if(num != 10){ //10이 아닐 때 예외를 발생시킴 이부분을 try로 감싸줌
throw new NotTenException();
}
} catch(NotTenException e){
//catch에 매개변수로 들어가는 예외는 발생한 예외랑 동일하게 써줘야함 !
System.out.println(e);
}
}
public static void main(String args[]){
Test t = new Test();
t.ten(8); //예외가 발생할 거임
}
}
//throws 예제
public class Main{
public void ten(int num) throws NotTenException{
if(num != 10){ //10이 아닐 때 예외를 발생시킴
throw new NotTenException();
}
}
public static void main(String args[]){
Test t = new Test();
try{
t.ten(8); //예외가 발생할 거임. 이부분을 try로 감싸줌
}catch(NotTenException e){
System.out.println(e);
}
}
}
- 컬렉션 프레임워크 : 여러 데이터를 편리하게 다룰 수 있게 만들어 놓은 것 ( 자료구조 및 알고리즘을 구조화)
대표 인터페이스 : List, Set, Map
* List 인터페이스 : 순서가 있는 데이터의 집합, 데이터 중복 허용
대표 구현 클래스 : LinkedList(removeFirst(),removeLast()), ArrayList, Vetcor
* Set 인터페이스 : 순서가 없는 데이터의 집합, 데이터 중복 X
대표 구현 클래스 : HashSet(add(값),remove(값)//인덱스가 아니라 원하는 값 바로 지우기 가능 !), TreeSet(이진탐색에 특화된 자료구조래) first() 처음값, Last() 마지막 값, lower(값) 매개변수보다 바로 전 작은 값 하나, higher(값) 매개변수보다 바로 다음 큰 값 하나.
*Map 인터페이스 : key와 value쌍인 데이터 집합, 순서 유지하지 않음.
대표 구현 클래스 : HashMap, TreeMap(put으로 자료넣기, firstKey(),firstEntry()//처음 데이터 쌍, LastKey(), LastEntry(), lowerEntry(값),higherEntry(값))
*HashSet으로 중복을 피해서 로또 번호 만들기 실습해봄 ! 오름차순으로 정렬할 때 LinkedList list = new LinkedList(set);해서 잠시 List로 바꾸고 Collections.sort(list) 했다.
- 람다식 : 람다식도 혼자공부할 때 어렵게 느껴졌었는데 별 거 아니었구나
람다 표현식 : 메소드 대신 하나의 식으로 표현하는 것
익명함수 :
반환타입 메소드이름(매개변수 , ...) { }
ex) public int sum(int x,int y) { return x+y }; 를 익명함수로 바꾸면
(int x,int y) -> { return x+y; }// 완전 간단해졌다
*람다식 장점 : 코드간결, 가독성 높음, 생산성 높음
*람다식 단점 : 재사용불가능(익명), 디버깅 어려움, 재귀함수로는 맞지않음(이름이 없으니까 !)
- 스트림 : 이날 하고 다음날 강의 다시보며 실습하면서 익혔다. 참 편리한 기능이었구나 !!!
알고리즘 풀 때 스트림 관련 지식을 찾아본 적이 있었는데 그때는 너무 어렵고 복잡해서 포기했었다.
그치만 이제는 포기할 수가 없다. 모르는 건 무조건 알고 넘어가야한다...!
정의 : 배열, 컬렉션 등의 데이터를 하나씩 참조하여 처리 가능한 기능.
for문의 사용을 줄여서 코드를 간결하게 함.
스트림은 크게 3가지로 구성 : Stream 생성, 중개연산, 최종연산
1. Stream 생성
//배열 스트림 생성
String str[] = new String{"a","b","c"};
Stream stream = Arrays.stream(str); // 배열이 스트림으로 바뀜
strea.forEach(System.out::println); //forEach는 최종연산
//컬렉션 스트림
ArrayList list = new ArrayList(Arrays.asList(1,2,3,4,5));
Stream stream = list.stream();
//스트림 builder
Stream stream = Stream.builder().add(1).add(2).add(3).build();
//스트림 generate
Stream streamGenerate = Stream.generate( () -> "abc" ).limit(3);
()안에 람다식과 유사하게 어떤 데이터를 만들지 작성. "abc"데이터를 limit만큼 반복생성
//스트림 iterate
Stream streamIterate = Stream.iterate( 10, n -> n*2 ).limit(3);
10은 초기값이고 그 초기값이 어떻게 변할지를 두 번째 매개변수로 써줌. limit는 저 동작을 몇 번 할 지
출력 값 : 10,20,30
//기본타입 스트림
IntStream intStream = IntStrean.range(1,5); // 1~4까지의 데이터 생성.
rangeClosed이용하면 넣은 끝값까지 데이터 추출가능.
2. 중개연산
//Filtering
IntStream intStream = IntStream.range(1,10).filter( n -> n%2 ==0 );
filter안의 값이 참이 되는 데이터만 남김
//Mapping
IntStream intStream = IntStream.range(1,10).map(n -> n*2);
모든 요소에 연산을 적용
//Sorting
IntStream intStream = IntStream.builder().add(5).add(2).add(3).build();
IntStream intStreamSorting = intStream.sorted(); //정렬됨.
3. 최종연산
//최종연산 forEach,sum,average,min,max,reduce등
//sum, average
int sum = IntStream.range(1,6).sum();
double avd = IntStream.range(1,6).average().getAsDouble();
//마지막 getAsDouble안 하면 이상한 값 나온다
//min,max
int min = IntStream.range(1,10).min().getAsInt();
int max = IntStream.range(1,10).max().getAsInt();
//reduce 좀 어렵다
Stream <Integer> stream = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5)).stream();
System.out.println(stream.reduce((x,y) -> x+y).get());
연쇄적인 연산으로 데이터 뽑아내기 가능
*Practice 문제로 1~10까지 짝수들의 합을 출력. for문 쓰면 몇 줄 많이 생기는데 stream을 이용하면 한 줄에도 가능했다.
System.out.println(IntStream.range(1,11).filter(n -> n%2 == 0).sum());
복습 포스팅만해도 두시간이 넘게 걸린 것 같다.
온라인 강의라 불안함도 조금있고 자바 기초는 아는 내용이다보니 집중도 잘 되지 않았는데 그래도 꿋꿋이 들었다.
위에 쓴 것처럼 알았다해도 완벽하게 알지 못 한 것들, 헷갈리는데 그냥 넘어간 것들, 알았어도 다른 곳에 이용된 사례들을 알게된게 쏠쏠하다. 배운 것들을 알고리즘 문제에도 잘 적용할 수 있게 계속 복기하면서 연습해야 할 것같다.
많은 양을 공부했다고 생각하진 않지만 하루도 빠지지않고 꾸준히 해왔음에 의의를 두고 다음 주는 더 열심히 해보자
다음 주부턴 테스트도 있을테니 더욱 바빠지겠지만 시간관리 잘해서 화이팅 해보자 !!!
'ZB 백엔드 스쿨 > 주차별 정리' 카테고리의 다른 글
Pre 코딩테스트 2회차 회고 (2-1~2-5) (0) | 2023.08.08 |
---|---|
Pre 코딩테스트 1회차 회고 (1-1~1-5) (0) | 2023.07.28 |
제로베이스 백엔드 부트캠프 2주차 정리 - Chapter02. 선형자료구조 (0) | 2023.07.21 |
제로베이스 백엔드 부트캠프 2주차 정리 - Chapter01. 기초수학 (1) | 2023.07.19 |