😊이 글은 프로그래머스 - 자바 중 강의를 듣고 작성하였습니다.
Object와 오버라이딩
object class : 모든 클래스의 최상위 클래스
- 아무것도 상속받지 않은 클래스는 object클래스를 상속받는 것을 의미
기본 메소드 : 오버라이딩 해야 사용 가능
- equals(Object obj) : 객체가 가진 값을 비교
- 이클립스 source -> generate -> hashCode() and equals() 에서 어떤 속성을 비교할지 선택하여 자동으로 오버라이딩 가능
- return boolean;
- toString : 객체가 가진 값을 문자열로 반환
- 이클립스 source -> generate -> toString() 에서 자동으로 오버라이딩 가능
- 객체만 호출해도 객체가 가진 값 반환 가능
- return String;
- hashCode : 객체의 해시코드 값 반환
- 이클립스 source -> generate -> hashCode() and equals() 에서 어떤 속성을 비교할지 선택하여 자동으로 오버라이딩 가능
- return int;
java.lang 패키지/오토박싱
- import 없이 사용 가능
- Wrapper, Object, String, StringBuffer, StringBuilder, System, Math 가 있음
wrapper class : 기본형 데이터 타입의 객체화를 가능하게 도와주는 클래스
- new Integer(int);
- int형변수.intValue();
오토박싱 : 기본 타입을 객체 타입의 데이터로 자동 형변환 시켜주는 기능
오토언박싱 : 오토박싱과 반대. 객체 타입의 데이터를 기본형 타입으로 자동 형변
StringBuffer 클래스
메소드 체이닝(Method Chaining) : 자기자신을 리턴하여 계속해서 자신의 메소드를 호출하는 방식
- String 클래스와 다르게 자기 자신이 계속 변함
append() : 문자열 추가. 자기 자신의 값이 바뀜
toString() : 문자열 반환
)
String class의 문제점
- 문자열끼리 + 연산자로 더하면 실제로는 스트링 버터 객체를 만들고 append메소드를 이용해서 문자열을 계속 누적해서 스트링 객체로 다시 변환(toString)하여 리턴 --> 항상 스트링 버퍼가 만들어짐
- 만약 반복문 안에서 +연산자를 사용하면 반복할 때 마다 new 연산자로 객체를 만들게 됨 --> 자바에서 new연산자를 많이 사용하면 느려짐. --> 나쁜 코드!
- 따라서 스트링 객체 대신 스트링 버퍼의 append와 toString을 사용하면 훨씬 효율적임
Math 클래스
- 생성자가 static으로 되어 있어서 객체 생성 불가. 바로 사용 가능
- max, min, cos, sin, tan, abs(절대값), sqrt(제곱근), random 등...
- ex) Math.max(30, 10);
- (int)(Math.random()*100)+1; //랜덤 범위 : 0<= double <1
java.util 패키지
유용한 클래스 모음
컬렉션 프레임워크
Collection
- 중복 허용, 순서 기억x
- add(Object) : boolean, 하나씩 저장
- iterator() : iterator, 자료를 하나씩 꺼냄
- size() : int, 저장된 자료의 수
Iterator
- 컬렉션 인터페이스가 의존함
- hasNext() : boolean, 다음 데이터가 있는지
- next() : Object, 다음 데이터 반환
Set
- 컬렉션 인터페이스를 상속받음
- 중복을 허용하지 않는 자료구조
- add(Object) : boolean, 같은 자료가 있으면 false, 없으면 true 반환
List
- 컬렉션 인터페이스를 상속받음
- 중복을 허용하고, 순서를 기억하는 자료구조
- get(int) : Object, 매개변수로 인덱스 값을 받아 해당 인덱스 데이터를 꺼내줌
Map
- set 인터페이스를 의존
- 키와 값을 가짐, 키는 절대 중복될 수 없
- get(Object key) : Object value
- keySet() : Set, 자신이 가지고 있는 모든 키들에 대한 정보를 읽어오는 Set을 반환
- put(Object key, Object value) : void
👇뒤에 더 자세하게 나옴
Generic <>
setter & getter : 필드 값을 바꾸고 받아오도록 하는 메소드
- 반환할 때 Object 타입으로 반환되므로 꺼낼때마다 형변환 해줘야 됨 --> 제너릭으로 바꾸면 편함
사용법
1. 클래스 선언 시 가상의 타입을 준다.
public class 클래스명<가상의타입E> {
private E obj;
public void setObj(E obj) {
this.obj = obj;
}
public E getObj(){
return obj;
}
}
2. 인스턴스 생성 시 사용할 타입을 선언해준다.
클래스명<Object> obj = new 클래스명<>();
obj.setObj(new Object());
Object new_obj = obj.getObj();
클래스명<String> str = new 클래스명<>();
str.setObj("hello");
String new_str = str.getObj();
3. 이렇게 하면 꺼낼때마다 형변환 없이 사용 가능
Set
HashSet
- set은 인터페이스 --> 구현 클래스인 HashSet을 이용하여 생성
- 제네릭을 사용해야 됨
꺼낼 때는 부모 클래스인 컬렉션이 가지는 이터레이터를 사용해야 된다.
- 인덱스 없음 --> while문 안에 hasNext()사용
- next() 사용하여 데이터를 하나씩 가져옴
List
배열과 비슷한 자료구조
- 차이점 : 배열 -한번 생성하면 크기 변경 불가 <--> 리스트-저장공간이 필요에 따라 변동
- 데이터의 중복 O, 순서 O
ArrayList
- set은 인터페이스 --> 구현 클래스인 ArrayList을 이용하여 생성
- 제네릭 사용
순서(인덱스) 가 있음 --> for문 안에 get(int) 사용하여 값을 꺼냄
Map
key와 value를 사용
HashMap
- Map은 인터페이스 --> 구현 클래스인 HashMap을 이용하여 생성
- 제네릭 사용
key가 있음 --> get(key) 사용하여 하나씩 값을 꺼냄
모두 꺼낼때 keySet() 사용 : key만 꺼내서 Set에 담는 것
- Set은 이터레이터를 사용해서 꺼낼 수 있음
- 키를 알면 값도 알 수 있기때문에 값도 모두 꺼내 올 수 있음
Date
JDK1.0과 함께 최조로 만들어진 클래스 -->지역화 고려하지 않음
- 지역화를 고려한 클래스 : 지역(나라)에 따라 시간, 언어 날씨 등이 다르다는 것을 고려하여 만들어진 클래스
Deprecated : 더 이상 지원하지 않는 기능이므로 사용을 자제하라는 의미
- date클래스에 deprecated 클래스나 메소드가 많음
Date 객체를 생성해서 사용
- toString()이 오버라이딩 되어 있음 --> 객체만 호출하여 출력 가능
- 원하는 포멧 사용 가능 : new SimpleDateFormat("yyyy.MM.dd 'at' hh:mm:ss a zzz");
SimpleDateFormat fm = new SimpleDateFormat("yyyy.MM.dd 'at' hh:mm:ss a zzz");
System.out.println(ft.format(date));
Calendar
Date클래스의 단점을 보완하기 위해 만들어진 클래스 --> 지역화 고려
클래스 옆에 A표시가 있으면 추상클래스!
- new를 사용할 수 없어서 static 메소드인 getInstance()로 인스턴스 생성
- get(상수) : 년도 월 일 등 꺼내옴
- get(Calendar.YEAR); //년도
- get(Calendar.MONTH)+1; //0~11월로 알려줌
- get(Calendar.HOUR); //12시간 기준 시간
- get(Calendar.HOUR_OF_DAY); //24시간 기준 시간
- get(Calendar.MINUTE); //분
- add(상수, int) : 원하는 값 바꿀 수 있음
- add(Calendar.MINUTE, 10); //10분 뒤
java.time 패키지
X
자바 IO
input & output : 입력과 출력에 대한 클래스
장식대상 클래스 : '어디로부터', '어디에' 를 정해서 입력, 출력하는 클래스
장식하는 클래스 : 다양한 방식으로 입력, 출력하는 기능을 제공하는 클래스
데코레이터 패턴 : 하나의 클래스를 장식하는 것처럼 생성자에서 감싸서 새로운 기능을 계속 추가할 수 있도록 클래스를 만드는 방식
Byte 단위 입출력
- byte 단위 입출력 클래스는 클래스의 이름이 inputstream, outputstream으로 끝난다.
file로 부터 입출력할 때
package JavaIO.Exam;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteExam2 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("src/javaIO/Exam/ByteExam.java");
fos = new FileOutputStream("byte.txt");
int readCount = -1;
byte[] buffer = new byte[512];
while((readCount = fis.read(buffer)) != -1) {
fos.write(buffer,0,readCount);
}
}catch(Exception e) {
e.printStackTrace();
}finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- read() : return int // 한 바이트씩 읽어서 리턴값(int)의 4바이트 중 마지막 바이트에 저장한다
- 더 이상 읽을 값이 없으면(파일이 끝나면) -1을 리턴한다.
- while을 사용하여 read()의 리턴값이 != -1 일때까지 반복하여 (OutputStream의)write(data)로 출력
- read(byteArray) : return int
- 우리가 사용하는 운영체제는 파일을 읽을 때 1byte씩 읽으려고 해도 보통 512byte씩 읽어온다
- 따라서 1byte를 요구하면 512byte를 읽어와서 첫번째 1byte만 전달하고 나머지 511byte는 버린다
- 때문에 파일을 읽어올 때는 512의 배수로 byte배열을 만들어 사용하는 것이 성능이 더 좋다.
- write(byteArray, 0, readCount)
- 바이트 배열의 값을 0인덱스부터 readCount까지 출
다양한 타입의 출력
try(
DataOutputStream out = new DataOutputStream(new FileOutputStream("data.txt"));
){
out.writeInt(100);
}catch (Exception e){
e.printStackTrace();
}
- 다양한 타입을 파일에 출력할 수 있음
- write메서드를 다양하게 오버로딩 해둠 --> writeInt(8) : 정수값으로 저장
try-whit-resources : 사용한 자원을 자동으로 종료시켜주는 기능
- try(){}catch 형식으로 사용 : ()안에 IO객체를 선언하고, {}안에 실제 사용될 코드를 넣음
다양한 타입의 입력
try(
DataInputStream In = new DataInputStream(new FileInputStream("data.txt"));
){
int i = in.readInt();
}catch (Exception e){
e.printStackTrace();
}
- 파일에 있는 다양한 타입을 각 타입게 맞게 읽어올 수 있음
- read메서드를 다양하게 오버로딩 해둠 --> readInt() : 정수값망 읽어옴
Char 단위 입출력
- Char 단위 입출력 클래스는 클래스의 이름이 Reader, Writer으로 끝난다.
Console
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
try {
line = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(line);
- System.in : 키보드로 입력받음
- BufferedReader : 한 줄씩 입력받
- 반복문을 사용해서 여러 줄 받을 수 있음
- 이외에 파일이나 리스트 등 다양한 자료구조로 받을수도 있음
File
BufferedReader br = null;
PrintWriter pw = null;
try{
br = new BufferedReader(new FileReader("data.txt"));
pw = new PrintWriter(new FileWriter("test.txt"));
String line = null;
while((line = br.readLine()) != null){
pw.println(line);
}
}catch(Exception e){
e.printStackTrace();
}finally {
pw.close();
br.close();
}
- BufferedReader : 한 줄씩 읽어
- FileReader : 파일에서 읽어 옴
- PrintWriter : 다양한 방법으로 출력함(메소드가 다양)
- FileReader : 파일에 출력함
어노테이션(Annotation) @
- 클래스나 메소드 위에 사용 ex) @Override
- 소스코드에 메타코드(추가정보)를 주는 것
- 사용자 정의 가능 : 커스텀 어노테이션
- 자바가 제공하는 것도 있음
커스텀 어노테이션 생성
@Retention(RetentionPolicy.RUNTIME)
public @interface custom{
}
적용
@custom
public void hello(){
적용되었는지 확인하는 법
쓰레드
- 운영체제 : 컴퓨터의 하드웨어를 사용하게 해주는 프로그램
- 프로세스 : 현재 실행되고 있는 프로그램
- 쓰레드 : 프로세스 안에서 동시에 동작하는 여러개의 흐름(작업)
쓰레드 만들기
1. 상속받기 : extends Thread
- run()을 오버라이딩하여 쓰레드 안에서 하고싶은 일을 구현 (main 메소드와 비슷한 역할)
- 자바는 단일 상속만 지원하기 때문에 다른 부모를 상속받으면 쓰레드 상속 불가
2. Runnable 인터페이스 구현 : implements Runnable
- run()을 구현(오버라이딩) : 상속받기와 동일
- 단일 상속 문제 해결
- start()메소드가 없음 --> 쓰레드 객체를 만들고 생성자 매개변수로 Runnable 객체를 전달하여 사용
동작 : main 메소드에서 start() 호출
- run()을 호출하지 않음! --> start()를 호출하면 쓰레드가 실행될 준비를 하고 준비가 되면 시작해줌
- 쓰레드는 메인 메소드와 별개로 동작하여 메인 쓰레드(메소드)가 끝나더라도 다른 쓰레드는 계속 동작한다.
공유객체
: 하나의 객체를 여러 개의 쓰레드가 사용한다(가지고 있다)
동기화 메소드
만약 여러개의 쓰레드(아이들)가 하나의 객체(장난감)를 동시에 호출(가지고 놀려고)하면 어떻게 될까? 망가지겠지
동기화 메소드 : 한가지 메서드가 사용될 때 다른 메서드는 사용하지 못하도록 막았다가(대기) 사용이 끝나면 다음 메서드가 사용(실행)하도록 해야한다.
- 공유객체를 가지는 메서드들의 선언부 리턴타입 앞에 synchronized 를 붙인다.
- 동기화된 메소드들 끼리는 0.000000001초라도 먼저 실행되면 공유 객체의 사용권을 먼저 얻게 된다.
- monitoring lock : 공유객체의 독점권. 해당 메소드의 실행이 끝나거나 wait()를 만나기 전까지 계속 독점
- 먼저 독점권을 가진 메소드가 끝나면 다음 순서로 대기하던 메소드가 monitoring lock을 가짐
메서드 전체를 동기화했을 때, 만약 메서드들의 실행 내용이 길어지면 마지막 대기하던 쓰레드는 너무 오래 기다리게 됨.
동기화 블록 : 메서드 안에 동시에 사용되는 부분(문제가 되는 부분)을 블록으로 감싸서 블록만 동기화 해줌
- synchronized (this) { //문제가 되는 부분 }
- 블록이 있는 부분에서만 lock을 가지므로 다른 코드를 실행할 때 다음 대기자에게 lock을 넘겨줄 수 있음
- 빠르게 쓰레드 진행 가능
쓰레드의 상태제어
쓰레드는 실행했다가 안했다가 한다 : 실행 안한다고 쓰레드가 끝난게 아님
- new로 쓰레드를 생성한 후 start로 실행
- runnable과 running상태를 왔다갔다 함
- 그 사이 sleep 또는 wait 메소드가 실행되면 쓰레드는 blocked 상태가 됨
- blocked 상태에서
- sleep으로 주어진 시간이 끝나면 runnable 상태가 됨
- wait으로 블럭되었다면 notify 메소드를 실행해야 runnable 상태가 됨. - 모니터링 락을 놓게 되어 대기 중인 다른 메서드가 실행 됨
- 현 쓰레드의 동기화 메소드나 동기화 블럭이 실행되었는데 이미 다른 쓰레드가 모니터링 락을 가진 상태라면 현 쓰레드는 락 풀에서 블럭된 상태가 된다.(블럭되었다)
- 쓰레드의 런 메서드가 종료되면 쓰레드는 종료된다(Dead상태)
- yield메서드가 호출되면 해당 쓰레드는 다른 쓰레드에게 자원을 양보하게 된다.
join() : 현 쓰레드가 멈출때까지 메인 쓰레드가 기다림
wait() : 동기화된 블럭 안에서 사용, 해당 쓰레드는 해당 객체의 모니터링 락 권한을 가지고 있었다면 권한을 놓고 대기하게 됨
해당 쓰레드가 시랭되면 자기 자신의 모니터링 락을 가지게 됨
notify() : 해당 쓰레드를 깨워 실행 가능 상태로 바꿈
데몬 쓰레드(Daemon Thread)
자바에서 데몬과 유사하게 동작하는 쓰레드
- 자바 프로그램을 만들 때 백그라운드에서 특별한 작업을 처리하게 하는 용도로 쓰임
- ex) 주기적으로 자동으로 저장, 에디터를 만들 때 일정 시간마다 맞춤법을 검사하게 한다던지..
- 모든 쓰레드가 종료되면 강제적으로 종료됨
람다식 (익명 메서드)
함수형 인터페이스 : 인터페이스 중에서 메서드를 하나만 가지고 있는 것 예)Runnable 의 run()
자바에서는 메서드만 매개변수로 전달할 수 없어. 때문에 람다식이 나옴
생성할 때 매개변수 전달 부분에 메소드를 정의할 수 있음
new Thread( (매개변수 목록) -> {
}).start();
아무래도 IO 이후로는 대학 강의 들어야겠다...!
이해해서 다시 정리하자🥲