on
Java
Java
∘ 재사용성과 유지보수가 좋다. (캡슐화, 상속, 다형성, 추상화)
∘ OS에 독립적이다. (JVM)
∘ 자동 메모리 관리 (GC)
∘ 보안성이 뛰어나다.
∘ 멀티스레드 & 동적 로딩 지원
[ Object-Oriented Programming : OOP ]
[ 객체지향 프로그래밍 ]
∘ 데이터를 추상화시켜 상태(변수)와 행위(함수)를 가진 객체를 만들고 객체간 상호작용을 통해 로직을 구성
∘ 여러 개의 독립된 단위(객체)들의 모임으로 파악하여 객체들이 메시지를 주고받고, 데이터를 처리(협력)
∘ 프로그램을 유연하고 변경이 용이하게 만들기 때문에 대규모 소프 트웨어 개발에 많이 사용
∘ 장점
ⅰ. 코드의 재사용성이 높다.
⇨ 만들어진 클래스를 가져와 사용할 수 있고 상속을 통해 확장이 가능하다.
ⅱ. 유지보수가 쉽다.
⇨ 수정해야 할 부분이 클래스 내부에 변수나 메서드로 존재하기에 해당 부분만 수정하면 된다.
ⅲ. 대형 프로젝트에 적합하다.
⇨ 클래스 단위로 모듈화하여 개발이 가능하다.
∘ 단점
ⅰ. 처리속도가 느리다.
ⅱ. 객체가 많으면 용량이 커진다.
ⅲ. 설계시 많은 노력과 시간이 필요하다.
추상화
∘ 인터페이스로 클래스들의 공통 특성을 묶어 표현하는 것
∘ 불필요한 정보는 숨기고 필요한 정보만을 표현할 수 있다.
캡슐화(정보 은닉)
∘ 속성(멤버변수)과 기능(메서드)을 캡슐(클래스)에 넣어 모으고 분류
∘ 장점 : 재활용 & 정보은닉
상속
∘ 자식 클래스가 부모 클래스의 특성과 기능을 물려받아 사용 및 수정
∘ 코드 수정 & 클래스의 재사용 용이
다형성
∘ 오버라이딩, 오버로딩 가능
∘ 역할 & 구현으로 구분 ⇨ 단순해지고, 유연해지며 변경도 편리
∘ 유연하고 변경 용이 & 확장 가능한 설계 가능
[ 객체지향 설계 원칙 SOLID ]
1. SRP 단일 책임 원칙 [ Single Responsibility Principle ]
• 한 클래스는 하나의 책임만 가져야 한다.
• 책임은 상황에 따라 다를 수 있다.
• 중요한 기준은 변경 : 변경이 있을 때 파급 효과가 적으면 SRP를 잘 따른것
ex) UI 변경, 객체의 생성과 사용을 분리
2. OCP 개방-폐쇄 원칙 [ Open/Closed Principle ]
• 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다
• 다형성을 활용 : 인터페이스를 구현한 새로운 클래스에 새로운 기능을 구현
• 객체를 생성하고, 연관관계를 맺어주는 별도의 조립, 설정자가 필요
3. LSP 리스코프 치환 원칙 [ Liskov Substitution Principle ]
• 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
• 다형성에서 하위 클래스는 인터페이스 규약을 다 지켜야 한다는 것
• 다형성을 지원하기 위한 원칙, 인터페이스를 구현한 구현체는 믿고 사용하려면, 이 원칙이 필요
ex) 자동차 인터페이스의 엑셀은 앞으로 가라는 기능
뒤로 가게 구현하면 LSP 위반, 느리더라도 앞으로 가야함
4. ISP 인터페이스 분리 원칙 [ Interface Segregation Principle ]
• 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다
• Car 인터페이스 -> 운전, 정비 인터페이스로 분리
• User 클라이언트 -> 운전자, 정비사 클라이언트로 분리
• 분리하면 임의의 인터페이스 자체가 변해도 특정 클라이언트에 영향을 주지 않음
• 인터페이스가 명확해지고, 대체 가능성이 높아진다.
5. DIP 의존관계 역전 원칙 [ Dependency Inversion Principle ]
• 추상화에 의존해야지, 구체화에 의존하면 안된다.
⇨ 구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻
• 의존성 주입(DI)은 이 원칙을 따르는 방법 중 하나
• 클라이언트가 인터페이스에 의존해야 유연하게 구현체 변경 가능
[ JVM : Java Virtual Machine ]
∘ Java Byte Code를 OS에 맞게 해석하는 역할
∘ 이후 실행과정 속 필요에 따라 스레드 동기화, GC와 같은 메모리 관리작업 수행
∘ 어떤 기기상에서 실행되고 있는 프로세스에 대한 자원을 대표하고 통제하는 서버
∘ 기능
① 자바 프로그램이 어느 기기나 OS 상에서도 실행되도록 함
② 프로그램 메모리를 관리&최적화
∘ 구성
① Class Loader
∘ Runtime 시점에 클래스를 로딩
∘ 클래스의 인스턴스 생성시 메모리에 인스턴스 로드
② Runtime Data Areas ( JVM Memory )
∘ JVM이 프로그램을 수행하기 위해 OS로부터 할당받은 메모리 공간
ⅰ. PC Register ⇨ Thread별로 현재 수행중인 JVM의 주소를 지니다.
ⅱ. JVM Stack ⇨ Thread별로 변수 / 메서드 저장
ⅲ. Native Method Stack⇨ 실제 실행할 수 있는 기계어로 작성된, 프로그램을 실행시키는 영역
ⅳ. Method ⇨ JVM이 시작할 때 생성되어 정적변수 / 메서드 코드 등을 보관
ⅴ. Heap ⇨ 런타임시 동적할당되는 데이터 저장
③ Excution Engine
∘ Class Loader에 의해 JVM 내의 Runtime Data Areas에 배치된 Byte Code를 실행하는 영역
[ GC : Garbage Collection ]
∘ 특정 기능 수행이 완료되어 더이상 필요없는 객체를 효과적으로 처리(제거)하는 작업
∘ 자바에서는 메모리를 GC를 통하여 관리하기 때문에, 개발자가 메모리를 처리하기 위한 로직을 만들 필요가 없다.
∘ 자바 메모리 영역에서 Heap 영역을 관리
∘ OOM Error : GC를 해도 더 이상 사용가능한 메모리 영역이 없는데 메모리를 할당하고자 할 때 발생하는 오류
∘ 영역
① Young : 생성된지 얼마 안된 객체들이 저장되는 장소, Minor GC
② Old : 오랫동안 사용중인 객체들이 저장되는 장소, Full GC
③ MetaSpace(Perm) : 클래스 & 메타 데이터가 저장되는 영역
∘ Garbage Collection : Minor GC, Full GC
∘ Garbage Collector
① Serial Collector : Minor GC와 Full GC가 하나의 스레드에서 이루어지는 알고리즘
② Parallel : Serial Collector를 병렬화한 알고리즘. 멀티CPU에서 성능이 좋다.
③ Concurrent Mark Sweep(CMS) : Stop the World 처리시간을 최소화하는데 초점을 맞춘 방식
④ Garbage-First (G1) : 대용량 메모리가 있는 멀티 프로세서 시스템용
※ STW (Stop The World)
∘ GC를 실행하기위해 JVM이 애플리케이션 실행을 멈추는 것
∘ GC 튜닝이란 STW 시간을 줄이는 것이다.
[ Java 컴파일 과정 ]
① 개발자가 자바 소스코드(.java) 작성
② 자바 컴파일러가 소스파일(.java)을 컴파일 ⇨ 바이트코드(.class) 파일 생성
바이트 코드 : 각 명령어가 1바이트 크기의 명령코드와 추가 피연산자로 이루어짐
③ 컴파일된 바이트코드를 JVM 클래스로더에게 전달
④ 클래스로더는 동적로딩을 통해 클래스들을 로딩&링크하여 JVM 메모리 (런타임 데이터 영역) 에 올린다.
⑤ 실행 엔진이 JVM 메모리에 올라온 바이트코드들을 명령어 단위로 하나씩 가져와 실행
5-1. 인터프리터 : 바이트코드 명령어를 하나씩 읽어서 해석하고 실행 ( 하나하나는 빠르지만 전체적으로 느림 )
5-2. JIT Compiler : 바이트코드 전체를 컴파일하여 바이너리코드로 변경하고 직접 실행시키는 방식 ( 빠르다. )
[ Java 메모리 구조 ]
① Class ( Method )
∘ 클래스, 클래스 변수(static Variable), 메서드
② Stack
∘ 메소드 호출 정보(스택프레임)
∘ 메소드 호출시 관계되는 멤버변수 & 지역변수
∘ 스레드마다 할당
∘ 메소드 호출이 완료되면 소멸
∘ 높은주소 → 낮은주소 순으로 할당
③ Heap
∘ 멤버 변수, new 키워드를 통해 생성된 인스턴스
∘ 낮은주소 → 높은주소 순으로 할당
[ 변수 ]
Class Variable { static int classValue; // 클래스 변수 int instanceValue; // 인스턴스 변수 void method() { int localValue; // 지역 변수 } }
클래스 변수
∘ static 키워드가 붙은 변수
∘ 해당 클래스의 모든 인스턴스가 공통된 값을 공유하게 된다.
따라서 한 클래스의 모든 인스턴스가 공통적인 값을 가져야할 때, 클래스 변수로 선언한다.
∘ 클래스가 로딩될때 생성되어 종료될때까지 유지, public을 붙이면 전역변수가 된다.
∘ 인스턴스 생성 없이 접근할 수 있으므로 클래스명.변수명 을 통해 접근할 수 있다.
∘ Method Area
인스턴스 변수
∘ 인스턴스가 생성될 때 생성
따라서 인스턴스 변수를 사용하기 전에 먼저 객체를 생성해야 한다.
∘ 인스턴스 변수는 독립적인 저장공간을 가지므로 인스턴스 별로 다른 값을 가질 수 있다.
∘ Heap Area
지역 변수
∘ 메소드 내에 선언되며 메소드 내에서만 사용할 수 있는 변수이다.
∘ 메소드가 실행될 때, 메모리를 할당받으며 메소드가 끝나면 소멸되어 사용할 수 없게 된다.
∘ Stack Area
[ Java Type ]
기본형 타입
∘ boolean, char, byte, short, int, long, float, double (8개)
∘ 비객체 타입, null 불가능
∘ NULL을 넣고 싶다면 Wrapper class 활용
∘ Stack Area에 저장
참조형 타입
∘ class, interface, array, enum
∘ JAVA 최상인 java.lang.Object 클래스를 상속하는 모든 클래스
∘ new로 인해 생성되어 Heap Area에 저장, GC에 의해 관리
∘ 비교시 equals( ) 사용
[ Casting ]
∘ 변수가 원하는 정보를 다 갖고있는것
∘ 목적 : 다형성 + 상속
ex) int a = 0.1 ⇨ 0.1은 int로 될 정보 또한 지니고 있다. ( upCasting )
but int b = (int)true ⇨ boolean을 int로 캐스트 불가능 ( downCasting )
묵시적 형변환
∘ 캐스팅이 자동으로 발생 (UpCasting)
∘ Parent p = new Child();
⇨ Parent를 상속받은 Child는 Parent의 속성을 포함하고 있으므로 명시할 필요가 없다.
명시적 형변환
∘ 캐스팅할 내용을 적어줘야 하는 경우 (DownCasting)
∘ Parent p = new Child();
Child c = (Child) p;
[ Call By Value & Call By Reference ]
Call By Value : 값에 의한 호출
∘ 함수가 호출될 때 메모리 공간 안에서 함수를 위한 임시공간 생성
∘ 변수값을 복사해서 전달받음 ( Local Value 속서을 지닌다 )
⇨ 함수 안 인자값이 변경되어도 외부 변수값은 변경되지 않음
Call By Reference : 참조에 의한 호출
∘ 함수 호출시 인자로 전달되는 변수의 레퍼런스를 전달
∘ 함수 안에서 인자 값이 변경되면 객체 값도 변경됨
∘ 자바는 항상 Call By Value로 값을 넘긴다.
∘ 메모리에 저장된 주소를 보내는 것도 물리적 관점으로 값으로 볼 수 있기 때문
∘ 객체의 참조값을 직접 바꾼것이 아니라 객체의 참조값을 통해 멤버변수에 접근하여 실제 값을 바꾼것
∘ 객체를 매개변수로 전달했을때 객체 안의 매개변수 값을 변경하면 주소 안의 실제 값을 바꿀 수 있다.
( 나머지는 불가능 )
[ Java 의 String ]
∘ 불변 객체 (Immutable) 이므로 동기화를 신경쓰지 않아도 된다.
∘ 문자열 연산시 새로운 객체를 만드는 오버헤드 발생
∘ 문자열 연산이 적고 조회가 많은 상황에 쓰기 좋다.
∘ GC로 제거되어야 한다.
[ StringBuilder & StringBuffer ]
∘ Mutable 객체
∘ 문자열 연산 시 처음 만든 객체를 이용해 연산하고 크기를 변경시켜 문자열을 변경한다.
∘ 문자열 연산이 자주 발생하는 상황에 쓰기 좋다.
∘ 문자열 연산시 크기를 변경시킨다.
StringBuilder
∘ Thread Unsafe
∘ 동기화를 고려하지 않는 싱글스레드 환경에 적합
StirngBuffer
∘ Thread Safe
∘ 동기화가 필요한 멀티스레드 환경에 적합
[ == equals ]
== : 비교하고자 하는 대상의 주소값 비교
equals() : 비교하고자 하는 대상의 값 비교
[ Collection ]
∘ List, Map, Set 인터페이스를 기준으로 여러 구현체 존재 ( Stack, Queue etc. )
∘ 동적배열의 개념
∘ 다수의 Data를 다르는데 표준화된 클래스를 제공해주기 때문에 편하게 사용할 수 있음
∘ 객체를 보관하기 위한 공간을 미리 정하지 않아도 되므로 객체 수를 동적으로 정할 수 있다.
List
∘ ArrayList, LinkedList, Stack, Queue
∘ 중복 O, 저장공간 가변적
Map
∘ HashMap, LinkedHashMap (key순서보장)
∘ key 중복 X
∘ key-value 쌍으로 이루어진 자료구조
∘ 데이터에 접근하기 위해 index가 아닌 key로 접근
Set
∘ HashSet (무작위 값), LinkedHashSet (순서보장), TreeSet(자동정렬)
∘ 집합, 중복 X
[ Access Modifier ]
∘ 변수 or 메서드 접근 범위를 설정하는 Java 예약어
∘ public : 어떤 클래스에서도 접근 가능
∘ protected : 해당 패키지&클래스를 상속받은 외부 패키지의 클래스에서 접근 가능
∘ package(defalut) : 클래스가 정의된 해당 패키지에서만 접근 가능
∘ private : 해당 클래스 내에서만 접근 가능
[ final ]
∘ final 클래스 : 다른 클래스에서 상속 불가능
∘ final 변수 : 변하지 않는 상수값이 되어 새롭게 할당 불가능
∘ final 메서드 : 다른 메소드에서 오버라이딩 불가능
[ static ]
∘ 프로그램이 시작할 때 Stack Area에 메모리가 할당되어 프로그램이 종료될때 해체되는 변수
∘ static 클래스 : 객체를 생성하지 않고도 변수&함수 사용 가능
∘ static 변수 : 객체들이 다같이 공유하는 데이터
∘ static 메서드 : 객체들의 데이터와 관계없는 완벽하게 공통적인 로직을 정의할 때 사용
인스턴스변수나 객체의 함수를 사용할 수 없다
[ Overriding vs. Overloading ]
∘ Overriding : 상위 클래스/인터페이스에 존재하는 메소드를 하위클래스에서 재정의하는 것
∘ Overloading : 같은 이름과 return형의 함수를 다른 매게변수로 만들어 사용
[ 추상 클래스 ]
∘ 미완성 클래스(설계도)
∘ 혼자로써의 역할은 못하지만, 새로운 클래스의 부모 클래스로서의 의미를 갖는다.
∘ 일반 함수, 멤버 포함 가능 [ 차이점 ]
∘ 추상 메소드를 포함한다면 반드시 추상 클래스로 선언
∘ 인스턴스 생성 불가능 [ 공통점 ]
목적 : 자식클래스로 하여금 구현을 강제한다, 메소드의 동작은 자식클래스에게 위임한다.
[ 인터페이스 ]
∘ 기본 설계도
∘ 인터페이스를 구현하는 모든 클래스에 대해 특정 메소드가 반드시 존재하도록 강제
∘ 일종의 추상클래스지만 추상화 정도가 높아 일반메소드, 일반멤버변수를 가질 수 없다.
∘ 오직 추상메소드와 상수만을 가질 수 있다.
∘ 모든 멤버변수 : public static final 이어야 하며 생략가능
∘ 모든 메소드 : public abstract 이어야 하며 생략 가능
∘ 클래스에서 인터페이스 다중 상속 가능, 다중 구현 가능
∘ 장점 : 대규모 프로젝트 개발시 일관된 표준화 가능
∘ 클래스 작성 & 인터페이스 구현 동시에 진행 가능 ⇨ 개발시간↓
∘ 클래스간 관계를 인터페이스로 연결하면 클래스마다 독립적 프로그래밍 가능
목적 : 구현 객체가 같은 동작을 하는것을 보장하는것
[ 추상 클래스 vs 인터페이스 ]
추상클래스 인터페이스 ∘ 클래스 o
∘ 추상메소드 , 일반메소드 , 일반멤버 가능
∘ 다중 상속 불가능
∘ 목적
- 상속을 받아 기능을 확장시키는 목적
- 공유의 목적
- 자식클래스에게 구현 강제화 ∘ 클래스 x
∘ 추상메소드와 상수 , default/static 메소드
∘ 다중 구현 가능
∘ 목적 : 구현 객체와 같은 동작을 보장하기 위해 사용
[ Wrapper Class ]
∘ 기본자료형 8가지에 대한 클래스 표현
∘ null을 사용해야 할때 사용하는 경우가 있음
∘ == 사용 대신 .intValue( ) 메소드를 통해 값을 가져와 비교해야 한다.
∘ 사용 이유
1. null을 사용해야 할때
2. Genereics( < > ) 에 넣어야 할때
3. String타입으로 변환하고자 할때
∘ Boxing (to Wrapper) , Unboxing (from Wrapper)
[ Generic ]
∘ 데이터 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입을 가질 수 있도록 하는것
∘ Collection 클래스에서 사용하는 것으로 컴파일 과정에서 타입체크를 해주는 기능
∘ Collection 내부에 들어온 값이 내가 원하는 값인지 별도로 로직처리를 구현할 필요가 없다.
∘ API 설계시 보다 명확한 의사전달 가능
class Generic { private K key; private V value; void set(K key, V value) { this.key = key; this.value = value; } void print() { System.out.println(key + " : " + value); } } public class Main { public static void main(String[] args) { Generic generic = new Generic<>(); generic.set("TEN", 10); generic.print(); // TEN : 10 Generic generic2 = new Generic<>(); generic2.set(10, "TEN"); generic2.print(); // 10 : TEN } }
[ Annotation (@) ]
∘ 컴파일러에게 코드 문법 에러를 체크하도록 정보 제공
∘ 실행 시 특정 기능을 실행하도록 정보 제공
∘ built-in ano (@Override) , Meta ano , Custom ano
[ Reflection ]
∘ 자바에서 이미 로딩이 완료된 클래스 or 다른 클래스를 동적로딩하여
구체적인 타입을 몰라도 생성자, 멤버필드, 멤버메소드를 사용할 수 있는 기법
∘ 객체를 통해 클래스의 패키지정보, 접근지정자, 부모클래스, 어노테이션을 얻을 수 있음
∘ 컴파일 타임이 아니라 런타임에 동적으로 특정 클래스의 정보를 객체화하여 추출할 수 있는 기법
∘ 사용 목적 : Runtime중 다른 클래스를 동적로딩하여 접근할 필요가 있을때
∘ 주의 : private 멤버도 Field.setAccessible( ) 를 true로 지정하면 접근&조작이 가능해진다.
∘ JVM 최적화 수행 불가능 ⇨ 성능↓
[ Java Thread ]
∘ JDK에서 지원하는 java.lang.Thread 제공
∘ 생성방법
① Thread 클래스 이용
∘ Thread 클래스로부터 제공되는 run() 메소드를 오버라이딩해서 사용
public class ThreadX extends Thread { public void run ( ) { // 수행할 문장 기술 } } ... ThreadX TX = new ThreadX( ); TX.start( );
② Runnalbe 인터페이스를 구현해서 생성
∘ 현재 클래스가 이미 다른 클래스로부터 상속받고 있다면 Runnable인터페이스를 이용하여 스레드 생성
∘ Runnable Interface : JDK 라이브러리 인터페이스, run( ) 메소드만 정의되어 있다.
∘ run( ) 메소드가 종료되면 스레드는 종료
∘ 한번 종료한 스레드는 다시 시작할 수 없다.
∘ 한 스레드에서 다른 스레드를 강종 가능
public class RunnableX implements Runnable { public void run ( ) { // 인터럽트 예외처리 + 수행할 문장 기술 } } ... RunnableX RX = new RunnableX( ); Thread th = new Thread(RX); th.start( );
∘ 스레드 상태 6가지
⇨ NEW(생성) / RUNNABLE(실행or준비완료) / WAITING(wait, 동기화) /
TIME_WAITING(sleep) / BLOCK(I/O작업) / TERMINATED(종료)
∘ 스레드 상태는 JVM에 의해 기록&관리
∘ wait( ) : 스레드가 lock을 가지고 있으면, lock 권한을 반납하고 대기하게 만든다.
∘ notify( ) : 대기상태인 스레드에게 다시 lock 권한을 부여하고 수행하게 한다.
[ Error vs Exception ]
Throwable 클래스
∘ 예외처리를 할 수 있는 최상위 클래스 ( Exception, Error가 상속받음 )
Error
∘ 컴파일 시 문법적인 오류
∘ 런타임 시 NullPoint 참조와 같은 오류 등으로 심각한 문제를 야기시켜 프로세스가 종료
⇨ OOM, StackOverflow 등 복구할 수 없는 심각한 오류
∘ OOM : JVM에서 설정된 메모리의 한계를 벗어난 상황
∘ Heap 사이즈 부족 / 너무 많은 class 로드 / 가용가능한 swap X / 큰 메모리의 native 메소드가 호출
∘ 해결 : dump 파일 분석, jvm 옵션 수정
Exception
∘ 동작 도중 예기치 않았던 이상 상태가 발생하여 수행중인 프로그램이 영향을 받는것
∘ 수습할 수 있는 비교적 덜 심각한 오류
∘ 예외가 주로 발생하는 원인
⇨ 사용자의 잘못된 입력, 잘못된 연산, 잘못된 로직, HW/Network 오작동, 시스템 과부하 etc.
∘ Checked Exception(예외처리 필수, 컴파일 불가) : RuntimeE, IOE, SQLE
∘ Unchecked Exception(런타임에 발생하는 예외) : RuntimeE 하위의 모든 예외 [ NullPointerE, IndexOutOfE etc... ]
[ Exception Handling ]
① try-catch를 이용하여 예외에 대한 최종적인 책임을 지고 처리
∘ try에는 위험한 로직이 들어가고 catch에는 예외발생시 수행할 로직이 들어간다.
∘ catch는 else if 처럼 여러개 사용 가능
∘ finally는 마지막에 실행하고 싶은 로직 ( 대표적으로 .close( ) )
② throws Exception을 이용하여 예외의 책임을 호출하는 쪽이 지도록 하는 방식
from http://gudwnsgur.tistory.com/12 by ccl(A) rewrite - 2021-11-15 02:27:34