Now Loading ...
-
java Thread
Process와 thread
process
실행되는 애플리케이션 그 자체
multi process
동시에 여러 프로그램을 실행하는 것
각 프로세스들은 자신만의 자원, 데이터, 스레드들로 구성되고 공유하지 않는다.
Thread
프로그램 실행의 최소 단위
모든 process는 하나 이상의 thread로 구성된다
Multi-Thread
실제로는 하나의 CPU가 동시에 처리하는 작업은 1개이다.(context switching)
아주 짧은 시간동안 여러 thread가 번갈아가면서 수행
Concurrent vs parallel
concurrent : 하나의 cpu가 여러 작업을 번갈아 가면서 빨리 전환하여 동시에 하는 것처럼 보이는 것
parallel: 여러 개의 cpu가 각각 자신의 작업을 실제로 동시에 처리하는 것
멀티 스레드의 특징을 가진다고 볼 수가 있다.
멀티스레드 프로그래밍의 장단점
장점
CPU의 사용률을 향상
작업의 분리로 사용자 응답성 개선
자원의 공유를 통해 효율적으로 활용
하나의 heap으로 자원을 공유한다.
단점
context switching에 따른 비용이 발생한다.
스레드 제어의 어려움
동기화 문제
데드락
스레드 생성 및 실행
스레드 생성
함수형 인터페이스 Runnable 활용
Runnable 타입의 객체를 thread 생성자 파리미터로 삽입
Thread 클래스 활용
runnable을 implements 하고 있다.
run에 실행 코드 작성
Thread 실행
Thread start() 메서드 호출
우리가 작성하는 코드에서는 run()을 직접 넣지 않고 start()를 넣어주어서 run()이 호출 될 수 있도록 준비만 하는 것이 좋다.
start() run()의 관계
start() : 스레드의 run()이 호출 될 수 있도록 준비만 하는 것
run() : 준비된 스레드를 실제로 동작시키는 것
main에서 run()을 직접 호출 하는 것은 thread를 동작시키는 것이 아닌 단순 메서드의 실행
멀티 스레드와 메모리
스레드마다 자신의 스택에서 동작
메인 스레드가 다른 스레드보다 먼저 종료 가능]
모든 thread의 종료가 프로그램의 종료
start()가 아닌 run()을 호출한다면?
별도의 스택을 구성하지 않고 메인 스레드의 스택에서 동작
Thread 상태와 생명주기
작업의 중요도에 따라 우선 순위를 지정한다. setPriority, getPriority를 제공하여 우선순위를 가져오는 것이 가능
MIN_PRIORITY
NORM_PRIORITY
MAX_PRIORITY
이렇게 3가지 상수를 제공한다.
Thread 상태(*)
NEW: 스레드 객체가 생성 된 후 아직 start()가 호출되지 않은 상태
RUNNABLE: JVM 선택에 의해 실행가능한 상태
TERMINATE: run() 메서드의 종료로 소멸된 상태
WAITING: sleep(),join(),wait() 등에 의해 정해진 시간 없이 대기중인 상태
TIMED_WAITING : sleep(),join(),wait() 등에 의해 정해진 시간 동안 대기중인 상태
BLOCKED: 사용하려는 객체의 모니터 락이 풀릴 때까지 기다리는 상
자바중심 회사에서 면접을 보는 경우 기출문제이다.
객체의 라이프 사이클이 있는데 메모리에 올라가면서 중간중간 호출되는 것들을 보여준다.
Thread 제어
sleep()
지정된 시간 동안 이 메서드를 호출한 thread는 waiting pool에서 대기
시간이 지나면 waiting pool에서 runnable로 이동
millis동안 동작중인 스레드를 대기풀에서 대기하게 한다.
join()
다른 스레드의 작업이 종료될 때까지 대기풀에서 대기
다른 스레드 종료시 ready 상태에서 runnable 상태로 변경후 경합
yield
실행중에 동일한 우선순위를 가진 다른 thread에게 실행을 양보
호출한 thread는 blocking 되지 않고 runnable에서 경합한다.
interrupt()
waiting pool에서 대기중인 thread를 깨워서 runnable로 이동시킨다.
💡 stop()은 절대 호출하면 안되는 메서드이다. thread는 os에서 더이상 돌아가지 않을때, run() 메서드가 종료되면 소멸된다.
thread는 run()이 끝나면 자동으로 종료된다. looping 중인 쓰레드를 종료시키려면 interrupt한 상황을 파악해서 안정적인 종료를 유도한다. 한번 종료된 스레드는 다시 start() 될 수가 없다. → IllegalThreadStateException 발생한다.
Daemon Thread
일반 thread 작업을 돕는 보조적인 thread
일반 thread 모두 종료되는 순간 강제적으로 자동종료
garbage collector
일반적으로 무한 루프를 사용하여 run 이후 대기 상태에 있다가 조건에 따라 실행
공유데이터와 동기화
synchronized 키워드
작업과 관련된 공유 영역에 lock 점검 표시
임계 영역에 mutex 설정
thread t1이 synchronized 만나면 공유 객체의 lock확인
있으면 lock을 가져와서 작업
thread t2도 synchronized 만나면 lock 획득 시도
lock 얻을수 없으므로 lock pool에서 대기
t1이 작업을 끝내고 lock을 반환 → t2가 lock pool에서 runnable로 이동
synchronized는 한 번에 하나의 스레드만 동작 할 수 있도록 한다.
안전하지만 성능상의 문제 발생
thread의 또다른 고민 - 비효율성
lock이 걸려있는 상태에서 계속 호출을 하는 것은 리소스 낭비가 된다.
동기화는 최소화하는 것이 좋다. 동기화 메서드를 가져다 쓰는 것도 추천하지 않는다.
Synchronized 관련 메서드
wait()
lock을 가진 thread가 더 이상 작업을 수행할 수 없는 상황에서 lock을 풀고 watiting pool로 이동
notify(), notifyAll()
wait()로 waiting pool로 이동한 thread들이 활동할 수 있는 조건이 된 경우 호출
waiting pool에서 대기중인 thread들을 runnable로 이동
쓰레드를 지정하여 깨우는 방법은 존재하지 않는다. wait 된 상태는 queue, stack과 같이 순서가 있는 상태로 저장되는 것이 아니라 waiting set이라고 생각해도 무방
waiting set에 waiting 상태의 쓰레드를 보관한다. 쓰레드는 오는 순서와 내보내는 순서를 저장하지 않는다. this.notify() 자기자신을 깨우는 것은 존재하지 않는다. 깨운 애를 점검을 해야한다.
💡
string builder, string buffer차이
StringBuffer은 실무에서 많이 쓴다고 한다. synchronized
string buffer은 threadSafe하지 않는다.
동기화를 통해 stringbuilder를 구현한다고 한다.
Thread Pool
병렬 작업 증가로 1회성 스레드 개수가 증가하면서 thread 생성, 스케쥴링 비용증가 → 애플리케이션 성능 저하
Thread pool
작업 처리에 사용되는 스레드를 제한된 개수로 정해놓고 작업 큐에 들어오는 작업들을 하나씩 스레드가 처리
작업 처리가 끝난 스레드는 다시 작업 큐에서 새로운 작업을 가져와 처리
작업의 유형
Runnable : 작업 후 반환하는 값이 없는 형태
Callabel 작업 후 반환하는 값이 있는 형태
Future(Pending Completion) 지연 완료 객체
작업 결과를 호출 즉시 반환하지 않고 작업이 완료될 때까지 블로킹 되었다가 최종결과를 얻기 위한 객체
💡
Excutable이 있다고 하면 Thread pool이 사용되었다고 해도 무방하다.
Completable Future
Future get()에 의한 블로킹 한계 극복
Callback 기반의 비동기 처리
//supplyAsync() -> 값을 반환하는 비동기 작업
CompleteableFuture future = CompletableFuture.supplyAsync(()->{return 42;})
// runAsync() -> 값 없는 비동기 작업
CompleteableFuture future = CompletableFuture.runAsync(()->{System.out.println("작업중")})
virtual Thread
비용이 매우 저렴한 1회용의 Thread stack 자체를 heap에 구성
JVM이 관리하는 경량의 Thread 1개의 V.T당 약 수천 수백 byte 소요
Carrier Thread가 Platform Thread 역할을 수행하며 virtual에 대한 스케쥴링을 담당
재사용 비용이 크기때문에 threadpool에서 사용하지 않는다. 쓰레드 로컬에서 사용하면 가비지 콜렉션이 과다하게 발생가능하므로 이 경우 일반 쓰레드를 사용하는 것이 좋다.
VO의 주요 목적은 non io blocking이다.,
CPU 작업만 하거나 ContextSwitching이 적은 상황이면 virtual Thread를 사용하지 않는 편이 좋다.
배압(Back Pressure)기능 없다.
배압: 데이터를 생성하는 생산자가 데이터를 소비하는 소비자의 처리능력에 맞춰 데이터 생산 속도를 조절하는 것
DB 처리등 모든 후속 작업들도 위 속도에 맞춰야 하고 지연시 오히려 timeout이 발생한다.
-
java 컬렉션
List 계열
자료구조란?
컴퓨터 과학에서 효율적인 접근, 수정을 가능케 하는 자료의 조직, 관리, 저장
데이터 값의 모임, 또 데이터 간의 관계, 데이터에 적용할 수 있는 함수나 명령을 의미
가장 기본적인 자료구조 : 배열
homogeneous collection(동일한 데이터 타입만 관리가능)
Polymorphism: Object를 이용하면 모든 객체 참조가능
넣을 때는 편하지만 빼낼 때는 번거로움
Generic을 이용한 타입 한정
컴파일 타임에 저장하려는 타입 제한 → 형변환의 번거로움 제거
Collection Framework
java.util → 다수의 데이터를 쉽게 처리하는 방법 제공
Collection framework 핵심 인터페이스
List
입력 순서가 있는 데이터 집합, 순서가 있으니까 데이터의 중복을 허락
Set
입력 순서를 유지하지 않는 데이터 집합, 중복 허락 x
Map
Key와 value 쌍으로 데이터를 관리하는 집합, 순서는 없고 key의 중복 불가, value는 가능
Collection interface
추가
add
addAll
조회
contains()
equals()
isEmpty()
iterator()
size()
삭제
clear()
remove()
기타
toArray()
데이터 추가과정
add, addAll → grow
0→ 10→15→ 22> 33 이렇게 늘어난다.
if(oldCapacity >0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA){
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity,
oldCapacity >> 1)
}
이러한 과정을 이해해야지 성능이 좋은 코드를 짤 수 있다.
ArrayList의 장단점
배열 기반이므로 배열의 장단점을 가진다
장점
동일한 크기의 데이터가 연속되어 접근속도가 빠름
단점
크기를 변경할수 없어 추가 데이터를 위해 새로운 배열을 만들고 복사해야 한다.
비 순차적 데이터의 추가 및 삭제에 많은 시간이 걸린다.
LinkedList
데이터의 삭제 및 추가에 유리
각 요소가 다음 요소의 링크 정보를 가지고 메모리에 연속적으로 구성될 필요가 있다
삭제 및 추가
각 요소가 가지고 있는 링크만 변경하면 완료
고정 사이즈의 리스트 생성
Arrays.asList()
고정 크기, add/remove 불가
요소의 수정 가능, null 가능
Set 계열
hash 충돌
hash 코드에 관한 압축이 필요
index = (hashcode % 배열의 크기) → 결국 hash는 충돌이 불가피하다.
내부적으로 linkedList를 사용하여 데이터를 관리한다.
Map 계열
hashmap을 사용하는 것을 권장
hashMap
특징
내부적으로 node<K,V>[]로 데이터 관리
배열의 index는 hash
key는 데이터 중복 불가, value는 데이터 중복가능
hashset도 내부적으로는 hashMap에 데이터 저장
key에 value를 넣고 value에는 dummy 값을 사용
map interface
추가
put(key, value)
조회
삭제
수정
put(key, value)
정렬
특정 기준에 따라 요소의 크기를 비교하여 내림차순, 오름차순으로 배치하는 것
정렬 가능한 Collenction
배열, List
set에서 SortedSet 계열
Map에서 SortedMap 계열
List 정렬
**Collections.sort(List list)**
Comparable interface
정렬을 하기 위해서는 위치를 바꿀 기준이 필요하다. 이때 비교를 하기위해 제공 가능한 인터페이스가 Comparable interface이다.
pubic interface Comparable<T>{
pubic int compareTo(T,O)
}
Comparator 활용
1회성 객체 사용시 anonymous inner class 사용
클래스 정의, 객체 생성을 한번에 처리
Collections.sort(names, new Comparator<String>(){
@Override
public int compare(String o1, String o2){
return Integer.compare(o1.length(), o2.length());
}
});
람다 표현식 이용
Collections.sort(names,(o1,o2)->{
return Integer.compare(o1.length(), o2.length());
});
Lambda
람다식이란?
함수적 프로그래밍 형태로 재사용 가능한 코드블록
기존의 anonymous inner class를 이용한 처리방식으로 간결하게 처
타겟 타입과 @Functionalnterface
타겟 타입은 abstract 메서드가 반드시 하나만 존재해야 한다.
타겟 타입은 abstract 메서드가 반드시 하나만 존재해야 한다.
FunctionalInterface
컴파일러가 재정의해야 하는 abstract method가 하나만 있음을 체크한다.
안정적인 programming을 위한 옵션
메서드 참조
람다 실행문 내부에서 다른 함수 하나만을 실행하는 경우 ::연산자를 이용해 기존 메서드 참조
::
파라미터 인스턴스 메서드 참조
객체::인스턴스 메서드
첫번째 파라미터는 메서드의 소유자 나머지 파라미터는 메서드의 파라미터로 순서대로 전달된다.
특정 객체의 instance 메서드 참조
객체의 메서드가 호출되며 파라미터는 메서드에 그대로 전달된다.
names.forEach(item)-> names.add(item)
names.forEach(names:add)
함수형 프로그래밍
표준 API 종류
Runnable 계열
단순 실행처리, return x
Consumer 계열
소비자, void로 반환, return x
Supplier
Function
parameter을 return으로 매핑, 새로운 타입으로 변환시켜 리턴
Bifunction<T,U,R> :T와 U 타입의 파라미터를 받고 R타입으로 리턴
주로 파라미터를 연산한 뒤 원하는 형태로 반환
Operation
동일한 타입으로 연산 결과를 리턴
Optional
T타입에 관한 wrapper
객체가 있을 수 있고 없을 수 있는 null 상태를 나타내는 객체
nullpointException에 적극적인 대처가능
관련 메서드
get()
값을 리턴 , null인 경우 NullpointerExcepion 발생
ifPresent
public void ifPresendt( Consumer<? super T> consumer)
consumer을 통해 값을 소비, 없으면 동작하지 않는다.
orElse
public T orElse(T other)
Optional의 값이 있으면 그값을 소비, 만약 값이 null인경우 Supplier인 other을 통해 공급받은 값 리턴
Stream API
stream이란?
jdk8에서 추가되었다.
배열 및 collection의 요소를 하나씩 참조해서 처리하는 목적
람다와 내부 반복자를 이용해 요소를 다루는 코드를 간결화
역할 및 특징
컬렉션, 배열 등 데이터 소스에 대한 공통된 접근 방식 제공
손쉬운 병렬 처리
Map/Reduce 모델 지원
맵: 데이터를 작은 단위로 나누어 지정된 함수를 적용 처리
리듀스: 결과를 모아서 최종 결과를 생성
중간 처리들과 최종 처리를 조합해서 사용한다.
중간 처리: 매핑, 필터링, 정렬 등 가공 처리 → n개 산출된다.
필터링
distinct(), filter()
자르기
skip(),limit()
조회
peek() → 디버깅을 위해 갔다 오는 것을 의미
매핑
최종 처리: 반복, 카운팅, 평균, 총합 등의 집계 처리 → 1개 산출
매칭
allMatch(), anyMatch(), noneMatch()
수집
collect()
루핑
forEach()
중간 처리는 최종 처리가 진행될 때까지 지연된다.
→ 최종처리를 붙여야지 중간 처리의 출력을 실행한다.
각각의 중간 처리는 새로운 스트림을 리턴하여 chaining 패턴을 적용한다.
한번 최종 처리가 끝난 스트림은 재사용 불가
Collection, 배열, File, Random 및 스트림 클래스의 static or default method로 생성한다.
보충
remove, put에는(int index) Generic, (Object o) boolean 이런 식으로 overloading으로 기능은 같지만 매개변수에 따라 다른 결과가 나오는 메서드가 존재한다.
of 메서드
list, map 과 같은 것을 쉽게 만들 수가 있다.
자료삭제시 주의사항 → 테스트에 나올 수도 있다.
일반 상용화 코드를 짤 때 null safe 한지 점검해주는 코드를 넣어야 한다.
NullPointerException이 발생하면 안된다.
if(this.no == null){
return -1;
}else if(o.no == null){
return 1;
}
return no.compareTo(o.no);
이너클래스(공식적으로는 Nested Class) outer Class
//C.class
//C$Inter1
public class C{
C(){
}
class Inter1{
}
void m1(Inter inter){}
interface Inter1{
}
void m2(int a){
new Thread (new Runnable() {
@Override
public void run(){
}
}).start();
}
public static void main(){
new C();
}
}
시간복잡도 관련 Math.max를 사용할 때의 주의점
-
-
-
-
java 추상화
OOP
OOP 특징
Abstraction(추상화)
현실의 객체를 추상화하여 클래스 구
Polymorphism(다형성)
하나의 객체를 여러 타입으로 참조가능
Inheritance(상속)
부모의 자산을 물려받아 자식에서 재정의 가능
Encapsulation(데이터 은닉과 보호)
데이터를 외부에 노출 시키지 않고 메서드를 사용해 보호
객체
→ 주체가 아닌것, 주체를 활용하는 것을 의미
따라서 객체지향 프로그래밍은 주변의 많은 것들을 객체화 해서 프로그래밍하는 것을 의미한다.
OOP의 장점
블록 형태의 모듈화된 프로그래밍
신뢰성이 높다. → 검증된 객체를 사용하기 때문에
추가/수정/삭제 용이하다
재사용성이 높다.
💡
현실의 객체가 갖는 속성과 기능은 추상화되어 **클래스**에 정의된다.
**클래스**는 구체화되어 프로그램의 객체가 된다.
객체 생성과 메모리
Jvm 메모리 구조
Method area
클래스 정보 처리
타입, field, method 정보
상수 풀
Stack
메서드의 실행공간
thread별 별도관리
메스드 프레임에 로컬 변수가 쌓이는 구조
heap
객체를 저장하기 위한 영역
thread에 의해 공유
객체가 생성되고 Garbage collector에 의해 정리된다.
변수
primitive Type variable
기본 8가지 type의 변수
reference Type variable
나머지 모든 것(객체 참조)
선언위치에 따른 분류
클래스 영역(static keyword)
클래스 영역
함수 내부
함수 선언부
인스턴스 멤버 변수
클래스 영역에 선언
생성될 때 heap에 객체 별로 생성된다
메모리에 올린 후 객체 이름으로 접근
Garbage Collector에 의해 객체가 없어질때 소멸
클래스 멤버 변수
클래스 {}영역에 선언, static keyword를 붙인다.
클래스 로더에의해 클래스가 로딩될 때 구성
개별 객체의 생성과 무관, 모든 객체가 공유한다
공유변수라고 불린다.
클래스 이름으로 접근하는 것이 좋다.
메서드
Variable arguments
addAll(int… params)
…을 이용하여 파라미터를 선언하면 호출 시 넘겨준 값의 개수에 따라 자동으로 배열 생성 및 초기화를 시행한다.
이렇게 넘겨주면 함수 내부에서는 배열로 쓰이게 된다.
void m1(int b, int... a){
System.out.printf()
}
a는 배열로 쓰이게 된다.
이는 %d, %s,와 같은 format으로 출력을 할 때 사용한다.
클래스 멤버와 instance 멤버 간의 참조와 호출
가장 중요한 것 호출하려는 멤버가 메모리에 있는가?
있으면 호출가능, 없으면 호출 불가(먼저 메모리에 로딩 후 사용해야 한다.)
static member : 언제나 메모리에 있다.
instance member : 객체 생성 전에는 메모리에 없다.
객체 즉 레퍼런스를 통해 접근을 하게된다.
메서드 호출 스택
각각의 메서드 호출 시 마다 메서드 동작을 위한 메모리 상자를 하나씩 할당
상자 내부에 메서드를 위한 파라미터 변수 등 로컬 구성
A메서드에서 새로운 메서드 B를 호출시 B실행을 위한 메모리 상자를 쌓는다.
stack 형식으로 메모리에 들어오고 종료시 B가 먼저 종료되어 메모리를 반납한다.
레퍼런스로 넘기는 경우 값은 저장된다. 이 경우 클래스의 멤버를 넘겨주는 것도 레퍼런스로 넘겨주는 것에 포함된다.
메서드 오버로딩
overloading: 동일한 기능을 수행하는 메서드의 추가작성
메서드 이름은 기능별로 의미 있게 정한다.
동일한 기능을 여러 형태로 정의를 할 때 쓰인다.
println()도 메서드 오버로딩을 통해 매개변수를 다르게 받아서 출력을 하게 된다.
메서드 이름은 동일, 파라미터의 개수, 순서 or 타입은 달라야 할 것
js는 메서드 오버로딩이 지원되지 않는다.
생성자
this.
참조 변수로써 객체 자신을 가리킨다. 참조 변수를 통해 객체 멤버에 접근한 것처럼 this를 사용하여 자신의 멤버에 접근이 가능하다.
용도
로컬 변수와 멤버 변수의 이름이 동일한 경우 멤버 변수임을 명시적으로 나타낸다.
메서드와 마찬가지로 생성자도 오버로딩이 가능하다
객체 생성 시 필요한 멤버 변수만 초기화를 진행 → 생성자 별 코드의 중복이 발생한다
한 생성자에서 다른 생성자를 호출할 때 사용
반드시 첫 줄에서만 호출이 가능하다.
초기화 블록
생성자처럼 멤버 변수의 초기화를 목적으로 한다.
{}를 사용하여 내부에 실행 코드를 작성한다.
클래스 초기화 블록은 클래스 멤버 변수의 초기화에 사용된다.
클래스 초기화 블록
클래스 멤버 변수의 초기화에 사용, 클래스 로딩시 1회 호출
인스턴스 초기화 블록
인스턴스 멤버 변수의 초기화에 사용, 생성자 코드 실행보다 먼저 호출된다.
객체 생성시 마다 1회 호출
구성요소의 로딩 순서
Static 요소의 로딩
Static 요소의 로딩 - 기본 초기화
Static method 로딩
Static Initializer 실행
Static Method 중 main 실행
Instance 요소의 로딩
멤버 변수 로딩 - 기본 초기화
Instance Initializer 실행
생성자 호출
강의 보충
Property와 field 차이 기억해두기
property와 field는 다르다. python, .net은 property는 있으나 java는 아니다. 변수로 불러오고 저장하는 것은 field로 저장한다고 하고 property는 java에는 setter, getter메서드를 통해 변수로 직접 저장하지 않는다.
python에서 self는 java의 this와 유사하다 python에서는 클래스를 만들고 사용할 때 자기 자신을 포함하도록 self를 선언하는데 다른 java와 js와 같은 경우에는 역사적으로 포함되어서 넘어간다고 가정해서 그렇다.
이에 관한 차이도 알면 좋다.
💡
다시보기가 있으니까 따라가기 힘든 경우에는 일단 듣고 정리한 상태에서 따라치는 것도 좋다.
static 변수 대신에 클래스 변수를 많이 쓴다.
자바는 멤버 변수라는 것을 많이 쓰지 않는다. 오히려 클래스나 인스턴스 변수로 많이 활용되고 쓰이게 된다.
선언된 하나의 클래스에 대해 인스턴스를 여러 개 만드는 경우 인스턴스 멤버 변수는 여러 개이나 인스턴스 메서드는 하나이다.(이는 모든 객체가 공유한다.)
class Person {
String name; // 객체마다 하나
static int count; // 클래스당 하나
void introduce() { } // 클래스당 하나
}
이러한 클래스가 있고 여러 개의 인스턴스를 만든다고 하면 name은 여러 개이나 count와 introduce()는 하나만 생성이 된다.
java는 call by value만을 지원한다. 주소값을 받아서 사용하기 때문이다.
String s = "ssafy";
s=s.toUpperCase(); //SSAFY
System.out.println(s); //ssafy
다른 변수들은 변경된 값이 저장되지만 string의 경우에는 변경이 되지 않는다. string은 불변이다.
자바는 문자열을 잘못 선언하면 garbage가 어마무시하게 나온다.
이렇게 직접 s += “a”를 하게 되면 뒤에 오는 문자들은 다 garbage로 처리되어서 GC가 많이 돌아가 jvm이 과부하되어 속도가 느려질 수가 있다.
StringBuilder와 stringBuffer을 사용해야 threadSafe하게 코드를 작성하는 것이 가능하다.
💡
java관련 문제에서 string은 많이 나온다고 한다. string의 불변성, string의 변화 등 많이 살펴볼 것
Object 클래스
모든 클래스의 조상클래스
별도의 extends선언이 없는 클래스들은 extends Object가 생략된다.
따라서 모든 클래스에는 Object 클래스에 정의된 메서드가 있다.
상속의 관계는 is-a 관계이다.
상속
포함관계
어떤 클래스를 상속받고 어떤 클래스를 포함해야 하는가?
문법보다는 프로젝트 관점으로 보는 것이 중요
Sealed class
봉인된 클래스로 내가 관리하는 특정 클래스에게만 상속이 가능
상속계층 내에서 엄격한 제어를 통해 프로그램의 구조를 명확하게 유지하고 의도치 않은 상속으로 인한 복잡성과 혼란을 방지한다.
명확한 역할과 직무 분류가 중요한 개념에서 사용한다.
class에 sealed 키워드를 사용하고 상속을 허락하는 클래스는 permits뒤에 나열한다.
sealed가 선언된 클래스는 permit를 반드시 필요로 한다.
구현 클래스는 sealed, final, non-sealed 중 하나가 필요하다.
sealed class SealedStudyGroup permits Algo,Cs,Java{
public void study(){
System.out.println ("공부")
}
}
final을 붙이면 상속불가, sealed 붙이면 sealed 상태에서 상속가능, non-sealed를 하면 자유롭게 상속하는 것이 가능하다.
메서드 재정의
매서드 오버라이딩(overriding)
조상 클래스에 정의된 메서드를 자식 클래스에서 적합하게 수정하는 것
public class Person{
void jump(){
System.out.println("두다리로 점프");
}
}
public class Spider{
void jump(){
System.out.println("키 * 1000만큼 엄청난 점프");
}
}
오버라이딩 조건
메서드 이름 같아야 함
매개 변수의 개수, 타입, 순서가 같아야한다.
리턴 타입이 같아야한다.
접근 제한자는 부모보다 범위가 넓거나 같아야 한다.
조상보다 더 큰 예외를 던질 수가 있다.
어노테이션
사전적 의미: 주석
컴파일러, JVM, 프레임워크 등이 보는 주석
소스코드에 메타데이터를 삽입한 형태
소스 코드에 붙여 놓은 라벨
코드에 대한 정보 추가 → 소스코드의 구조 변경, 환경 설정 정보 추가 등의 작업진행
기본 annotation의 예
@Deprecated
컴파일러에게 해당 메서드가 deprecated 되었다고 알려준다.
@Override
컴파일러한테 해당 메서드는 override한 메서드임을 알려준다.
@Override가 선언된 경우 반드시 super class에 선언된 메서드여야 한다.
@SuppressWarnings
컴파일러에게 사소한 warning의 경우 신경쓰지 말라고 알려준다.
Import
다른 패키지에 선언된 클래스를 사용하기 위한 키워
ctrl+space : 어떤 클래스를 사용할지 선택하는 것이 가능
ctrl+shift +o: 이클립스에서 import 해주는 방법
제한자
클래스, 변수, 메서드 선언부에 함께 사용되어 부가적인 의미 부여
final class:
더이상 확장 할 수 없음. 상속금지 → 오버라이드 방지
String class, Math class와 같이 기존에 만들어진 클래스에 대한 override를 방지하기 위해 추가한다.
final method
이는 더 이상 재정의 할 수 없는 메서드이고 override를 방지하는데 사용한다.
접근 제한자 Access Modifier
접근제한자를 통해 다른 패키지로의 접근을 제한할 수 있다. 아무것도 안쓰는 경우는 default이고 같은 package내에서 접근은 다 가능하다.
Touch background to close