JAVA
Java
- Java는 객체지향 언어
- JVM을 통해 어떤 운영체제에서도 동일하게 실행 (운영체제에 독립적)
- 가비지 컬렉터에 의해 자동으로 메모리를 관리
- 다양한 오픈소스 라이브러리와 API를 지원
- 멀티 스레딩 지원
JVM (Java Virtaul Machine 자바 가상 머신)
- JVM은 컴파일된 Java 클래스 파일(bytecode)를 다양한 OS 환경에서 실행 가능하게 해준다.
- JVM과 실행과정

- 실행 절차
- .java 파일 생성 → compiler: .java → *.class 파일인 Byte code로 Compile → JVM: Byte Code → 기계어인 Binary Code로 변환 → CPU에서 실행되어 사용자에게 제공
- Class Loader: JVM 내 메모리 영역으로로 Class 파일을 로드하고 링크
- Excution Engine: 메모리에 적재된 클래스들을 기계어로 변경해 실행
- 인터프리터: 바이트 코드를 한줄씩 읽어 기계어로 변환
- JIT 컴파일러: 반복되는 코드를 기계어로 변환해 캐싱 (-> 캐싱한 것을 바로 실행해 속도 향상)
- Garbage Collection 수행 (메모리 관리)
Garbage Collection 가비지 컬렉션
- 가비지 컬렉션(Garbage Collection)은 Java 프로세스에서 더 이상 사용하지 않는 메모리를 자동으로 해제 해주는 JVM의 작업
- Java Runtime시 Heap 영역에 저장되는 객체들은 따로 정리하지 않으면 계속헤서 쌓이게되어 OutOfMemmory Exception(OOME)이 발생할 수 있다. 이를 방지하기 위하여 JVM에서는 주기적으로 사용하지 않는 객체를 수집하여 정리하는 GC를 진행한다.
Runtime Data Area (Java의 메모리 영역)
OOP (Object Oriented Programming : 객체 지향 프로그래밍)
- 자바는 객체 지향 프로그래밍을 지원한다. 데이터를 객체로 취급하여 객체 내부에 선언된 메서드를 활용하는 방식으로 캡슐화, 상속, 다형성, 추상화의 특징을 갖고 코드의 모듈화, 재사용성, 유지 보수성을 높이는데 도움이 된다.
Encapsulation 캡슐화
- 서로 연관있는 속성과 기능들을 하나의 캡슐로 만들어 데이터를 외부로부터 보호하는 것으로 객체는 내부의 세부 구현을 숨기고 필요한 인터페이스만 노출하여 사용자가 공개된 정보에만 접근이 가능하고(Information Hiding) 객체를 쉽게 이해하고 사용할 수 있게 한다.
- Getter/Setter
필드는 외부에서 접근할 수 없도록 막고(private) 메소드는 공개해서 외부에서 메소드를 통해 필드에서 접근하도록 유도한다. 필드의 값을 외부로 리턴해주는 메소드를 Getter라고 하고 외부에서 갑슬 받아 필드를 변경하는 메소드를 Setter라고 한다.
- Access modifiers 접근 제어자
- 변수나 메서드의 사용 권한은 다음과 같은 접근 제어자를 사용하여 설정할수 있다.
- 클래스와 인터페이스를 다른 패키지에서 사용하지 못하도록 막을 때 사용하며 객체 생성을 막기 위해 생성자를 호출하지 못하게 하거나 필드나 메소드를 사용하지 못하도록 막아야 하는 경우에도 사용한다.
- 접근제어자 구분

Inheritance 상속
- 클래스들 간에 상속 관계를 형성할 수 있다. 부모 클래스의 특성과 동작을 자식 클래스가 상속받아 재사용 할 수 있으며, 새로운 기능을 추가하거나 기존 기능을 변경할 수 있다. 코드의 재사용 측면, 계층적인 관계 생성, 유지 보수성 측면에서 중요하다.
Polymorphism 다형성
- 다형성은 사용 방법은 동일하지만 다양한 객체를 이용해서 다양한 실행 결과가 나오도록 하는 것으로 대표적으로 오버로딩과 오버라이딩이 있다.
- Overloading 오버로딩
같은 이름을 가진 메서드를 여러개 두는 것을 의미한다. 메서드 타입, 매개변수 유형, 개수등으로 여러개를 둘 수 있다.
- Overriding 오버라이딩
주로 메서드 오버라이딩을 말하며 상위 클래스로부터 상속받은 메서드를 하위 클래스가 재정의 하는 것을 미한다. 매개 변수를 달리하는 생성자를 여러개 선언하는 것은 생성자 오버라이딩이라고 한다.
- Overloading vs Overriding
오버라이딩은 상속 관계에서 부모 클래스의 메서드를 자식 클래스에서 재정의 하는 것이고, 오버로딩은 같은 클래스 내에서 메서드 이름은 동일하지만 매개변수 목록이 다른 여러 개의 메서드를 정의하는 것이다. 이 두개념을 활용하여 다형성을 구현하고 유연하고 확장가능한 코드를 작성할 수 있다.
Abstraction 추상화
- 구체적인 사물들의 공통적인 특징을 파악해서 이를 하나의 개념(집합)으로 다루는 것으로 복잡한 시스템으로부터 핵심적인 개념 또는 기능을 간추려 구체적인 클래스를 정의할 수 있다.
- Abstract Class 추상 클래스
- 하위 클래스에서 구현될 추상적인 기능이 포함된 클래스로 공통된 필드와 메소드의 이름을 통일할 목적으로 사용
- 추상 클래스는 선언 시 abstract 키워드를 붙여야만 하며 객체화가 불가능하고 상속을 통해서만 자식 클래스를 만들 수 있다.
- Abstract method 추상 메소드
- 추상 클래스 내에 정의되는 선언 부분만 있고 구현 부분이 없는 메소드로 추상 클래스를 상속한 하위 클래스에서 구현을 강제화하여 재정의(Overriding)을 하도록 한다.
- 공통적인 필드와 메소드를 추상 클래스에 모두 선언해두고 다른 점만 실체 클래스에 선언하면 작성 시간을 절약할 수 있다.
- Interface 인터페이스
- 인터페이스는 개발 코드와 객체가 서로 통신하는 접점 역할을 하며 인터페이스는 추상 메소드와 상수만 가진다.
- 개발 코드가 직접 객체의 메소드르 호출하는 대신 중간에 인터페이스를 두는 이유는 개발 코드를 수정하지 않고 사용하는 개체를 변경 할 수 있도록 하기 위해서 이다. 인터페이스는 하나의 객체가 아니라 여러 객체들과 사용이 가능하므로 어떤 객체를 사용하는냐에 따라서 실행 내용과 리턴값이 다를 수 있다.
- Abstract Class vs Interface
추상 클래스와 인터페이스는 선언만 있고 구현 내용이 없다는 점과 자식 클래스가 메서드의 구체적인 동작을 구현하도록 하여 결합도를 낮춘다는 공통점이 있지만 그 목적이 다르다는 차이가 있다. 추상 클래스는 메서드 오버라이딩을 통한 기능의 구현과 확장에 목적을 둔다면 인터페이스는 필수적으로 동작되어야 할 기능의 규격을 잡아주는 역할을 한다. 또한 추상클래스의 경우 다중 상속이 불가능하지만 인터페이스는 다중 구현이 가능하다.
Instance 멤버와 Static 멤버
- Instance 멤버
- 객체를 생성한 후 사용할 수 있는 필드와 메서드를 말하는데 이들을 각각 인스턴스 필드, 인스턴스 메소드라고 한다.
- 객체가 사라지면 멤버도 사라진다.
- Static 멤버
- 클래스에 고정된 멤버로서 객체를 생성하지 않고 사용할 수 있는 필드와 메서드를 말한다.
- 정적 필드와 정적 메서드라고 부르며 선언 시 static 키워드를 추가적으로 붙이면 된다.
- 멤버는 프로그램이 종료될 때 사라진다.
- 자주 변하지 않는 값이나 공통으로 사용되는 값 같은 공용자원에 대한 접근에 있어서 매번 메모리에 로딩하거나 값을 읽어들이는 것보다 전역변수와 같은 개념을 통해 접근하는 것이 비용도 줄이고 효율을 높일 수 있다.
Java의 final 키워드 (final/finally/finalize)
- final
- 변수나 메서드 또는 클래스가 '변경 불가능'하도록 만든다.
- static final (상수)
- final 필드 vs Constant Value
final 필드는 한 번 초기화 되면 수정할 수 없는 필드이지만 상수라고 부르지는 않는다. 불변의 값인 상수는 객체마다 저장할 필요가 없는 공용성을 띠고 있으며 여러가지 값으로 초기화 될 수 없기 때문이다. final 필드는 객체마다 저장되고 생성자의 매개값을 통해서 여러가지 값을 가질 수 있기 때문에 상수가 될 수 없다.
불변의 값을 저장하는 필드를 자바에서는 상수라고 부르며 static final 로 선언한다.
- finally
- try/catch 블록이 종료될 때 항상 실행될 코드 블록을 정의하기 위해 사용한다.
- finally는 선택적으로 try 혹은 catch 블록 뒤에 정의할 때 사용한다.
- finally 블록은 예외가 발생하더라도 항상 실행된다.
- 단, JVM이 try 블록 실행 중에 종료되는 경우는 제외한다.
- finalize()
- Garbage Collector가 더 이상의 참조가 존재하지 않는 객체를 메모리에서 삭제하겠다고 결정하는 순간 호출된다.
- Object 클래스의 finalize() 메서드를 오버라이드해서 맞춤별 GC를 정의할 수 있다.
- protected void finalize() throws Throwable { // 파일 닫기, 자원 반환 등등 }
Error & Exception
-
Error
실행 중 일어날 수 있는 치명적 오류, UncheckedException의 일종
-
Exception
- 경미한 오류, try-catch를 이용해 프로그램의 비정상 종료를 막을 수 있음
- CheckedException: 실행하기 전에 예측 가능한 예외, 반드시 예외 처리
- UncheckedException: 실행하고 난 후에 알 수 있는 예외, 따로 예외처리를 하지 않음(예: RuntimeException)
-
Exception 일반 예외
컴파일러 체크 예외라고도 하며 프로그램 실행 시 예외가 발생할 가능성이 높기 때문에 자바 소스를 컴파일하는 과정에서 해당 예외 처리 코드가 있는지 검사한다. 만약 예외 처리 코드가 없다면 컴파일 오류가 발생한다.
-
Runtime Exception 실행 예외
컴파일러 넌 체크 예외라고도 하며 실행 시 예측할 수 없이 갑자기 발생하기 때문에 컴파일하는 과정에서 예외 처리 코드가 있는지 검사하지 않는다. 오로지 개발자의 경험에 의해서 예외 처리 코드를 작성해야한다.
-
Exception Class 예외 클래스
자바에서는 예외를 클래스로 관리한다. JVM은 프로그램을 실행하는 도중에 예외가 발생하면 해당 예외 클래스로 객체를 생성하고 예외 처리 코드에서 예외 객체를 이용할 수 있도록 해준다. 모든 예외 클래스는 java.lang.Exception 클래스를 상속 받는다.
- NullPointExeption : 자바 프로그램에서 가장 빈번하게 발생하는 실행 예외로 객체가 없는 상태에서 객체를 사용하려고 할 때 발생한다.
- ArrayIndexOutOfBoundsException : 배열에서 인덱스 범위를 초과할 경우 발생한다.
- NumberFormatException : 숫자로 변활 될 수 없는 문자가 포함되어 있을 때 발생한다.
- ClassCastException : 클래스를 다른 타입으로 변환할 수 없을 때 발생한다.
-
예외 처리 코드
- try-catch-finally 블록 : 생성자 내부와 메소드 내부에서 작성되어 일반 예외와 실행 예외가 발생 할 경우 예외 처리를 할 수 있도록 해준다.
- throws 키워드 : 메소드 선언부 끝에 작성되어 메소드에서 처리하지 않은 예외를 호출한 곳으로 떠넘겨 호출한 곳에서 예외 처리를 하도록 한다.
컬렉션 프레임워크
-
데이터를 쉽고 효과적으로 관리할 수 있는 표준화된 방법을 제공하는 클래스의 집합
-
주요 인터페이스로는 List, Set, Map이 존재한다.
-

-
List 컬렉션
- 순서가 있는 데이터의 집합, 데이터 중복 허용
- ArrayList, Vector, Linked List
-
Set 컬렉션
- 순서가 없는 데이터의 집합, 데이터 중복 불허
- HashSet, LinkedHashSet, TreeSet
-
Map 컬렉션
- 키와 값이 한 쌍, 순서가 없는 데이터 집합, 키를 기준으로 중복 불허
- HashMap, HashTable, LinkedHashMap, Properties, TreeMap
Generics 제너릭
- 클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정되는 것을 의미한다. 특정(Specific) 타입을 미리 지정해주는 것이 아닌 필요에 의해 지정할 수 있도록 하는 일반(Generic) 타입으로 데이터 형식 불일치 문제를 컴파일 과정에서 예방할 수 있다.
Thread 스레드
- Thread
프로세스 내에서 실행되는 흐름의 단위로 한 프로세스는 하나 이상의 스레드를 가지고 스레드를 동시에 실행할 수 있다. 이러한 실행 방식을 멀티스레드(multithread)라고 하며 자바는 이러한 멀티 스레드를 지원한다.
- Process vs Thread
- Process는 하나 이상의 Thread로 구성되어 각 Thread가 다양한 기능을 작동시킨다.
- Process는 서로간에 Memory를 공유하지 않지만 Thread는 공유한다.
- MultiThread Scheduling
Thread는 여러 일을 동시에 주기적으로 처리 해 줄 수 있으나 제어가 어렵다는 문제가 있다. 기본적으로 Thread가 Round Robin 방식을 사용하기 때문이다. 즉, 먼저 시작했어도 더 늦게 끝날 수 있다. 이러한 Thread를 제어하기 위해 다양한 방법을 사용하고 있다.
Syncronous vs Asyncronous
- Sychronized 동기
- 한 자원에 동시에 접근하는 것 제한, 순차적으로 진행
- Thread간 Memory Share가 가능하기 때문에 발생할 수 있는 데이터의 간섭,오염을 막을 때 사용
- Java에서 synchronized 키워드 사용
- Blocking 방식
- Asyncronous 비동기
- 현재 실행 중인 명령이 종료되지 않아도 다음 명령 실행 가능
- ex. Ajax, Thread
- Non-Blocking 방식
Serialization 직렬화
- 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 데이터 변환하는 기술(↔ 역직렬화)
- 같은 자바 시스템에서의 데이터 전송, 저장에 최적화 되어있다.
- SerialVersionUID
- JVM: 직렬화와 역직렬화를 하는 시점의 클래스에 대한 버전 번호를 부여
- 직렬화할 때의 버전 번호와 역직렬화를 할 때의 버전 번호가 다르면 역직렬화가 불가능하게 될 수 있기 때문에 이런 문제를 해결하기 위해 SerialVersionUID를 사용
Call by Reference & Call by Value
- Call by Reference (참조에 의한 호출)
- 함수가 호출될 때, 메모리 공간 안에서는 함수를 위한 별도의 임시 공간이 생성, 인자로 전달되는 변수의 레퍼런스를 전달한다.
- 따라서 함수 안에서 인자의 값이 변경되면, 인자로 전달된 변수의 값도 함께 변경된다.
- Call by Value (값에 의한 호출)
- 함수가 호출될 때, 메모리 공간 안에서는 함수를 위한 별도의 임시 공간이 생성, 인자로 전달되는 변수의 값을 복사하여 함수의 인자로 전달한다.
- 복사된 인자는 함수 안에서 지역적으로 사용되는 local value의 특성을 가진다.
- 따라서 함수 안에서 인자의 값이 변경되어도, 외부의 변수의 값은 변경되지 않는다.
다.
- Java는 항상 Call by Value
String, StringBuilder, StringBuffer
- String
- 새로운 값을 할당할 때마다 새로 클래스에 대한 객체가 생성된다
- String + String + String...
- 각각의 String 주솟값이 Stack에 쌓이고, Garbage Collector가 호출되기 전까지 생성된 String 객체들은 Heap에 쌓이기 때문에 메모리 관리에 치명적이다.
- String을 직접 더하는 것보다는 StringBuffer나 StringBuilder를 사용하는 것이 좋다.
- StringBuilder & StringBuffer
- memory에 append하는 방식으로, 클래스에 대한 객체를 직접 생성하지 않는다.
- StringBuilder
- StringBuffer
- 변경가능한 문자열
- 동기 처리
- multiple thread 환경에서 안전한 클래스(thread safe)