JAVA 정리
클래스 객체 인스턴스의 차이
- 클래스(Class) : 객체를 만들어 내기 위한 설계도 혹은 틀 , 연관되어 있는 변수와 메서드의 집합
- 객체(Object) : 소프트웨어 세계에 구현할 대상, 클래스에 선언된 모양 그대로 생성된 실체, ‘클래스의 인스턴스’ 라고도 부른다. 객체는 모든 인스턴스를 대표하는 포괄적인 의미를 갖는다. Oop의 관점에서 클래스의 타입으로 선언되었을 때 ‘객체’ 라고 부른다.
- 인스턴스(Instance) : 설계도를 바탕으로 소프트웨어 세계에 구현된 구체적인 실체이다. 즉, 객체를 소프트웨어에 실체화하면 그것을 ‘인스턴스’ 라고 부른다. 실체화된 인스턴스는 메모리에 할당된다. 인스턴스는 객체에 포함된다고 볼 수 있다. Oop의 관점에서 객체가 메모리에 할당되어 실제 사용될 때 ‘인스턴스’ 라고 부른다. 객체에 메모리가 할당되어 실제로 활용되는 실체
클래스, 객체, 인스턴스
클래스는 객체를 만들어 내기 위한 설계도이고
객체는 소프트웨어 세계에 구현할 대상, 클래스를 바탕으로 설계된 구체적인 실체,
인스턴스는 객체에 메모리가 할당되어 실제로 활용되는 실체를 말합니다.
오바라이딩과 오버로딩
- 오버라이딩: 상위 클래스가 가지고 있는 메소드를 하위 클래스에서 재정의하여 사용하는 기술
- 오버로딩: 매개변수의 타입과 개수를 변경하면서 같은 이름의 메소드를 여러 개 사용하는 기술
오버라이딩과 오버로딩
오버라이딩은 상위 클래스가 가지고 있는 메소드를 하위 클래스에서 재정의하여 사용하는 기술이고
오버로딩은 매개변수의 타입과 개수가 다른 같은 이름의 메소드들을 정의하여 사용하는 기술입니다
객체지향 언어
- 객체 : 현실세계의 실체 및 개념을 반영하는 상태와 행위를 정의한 데이터의 집합
- 객체지향 프로그래밍 : 각자의 역할을 지닌 객체들끼리 서로 메시지를 주고받으며 동작할 수 있도록 프로그래밍 하는 것
객체지향 장점
- 라이브러리만 임포트하면 필요한 기능만 뽑아서 사용할 수 있으므로 생산성이 높아지고 버그 발생률을 줄여 코드의 재사용성이 높다.
- 객체 단위로 코드를 작성하므로 협업에 최적화되어있고 유지보수에 용이하다.
- 객체를 중심으로 프로그래밍하기 때문에, 사람의 관점에서 프로그램을 이해하고 파악하기 쉽다.
객체지향의 단점
- 객체 간의 정보 교환이 모두 메시지 교환을 통해 일어나므로 실행 시스템에 많은 overhead가 발생한다.(하드웨어의 발전으로 어느정도 해소)
- 객체가 상태를 갖기 때문에 예상치 못한 부작용이 발생할 수 있다. 변수가 존재하고 이 변수를 통해 객체가 예측할 수 없는 상태를 갖게 되어 애플리케이션 내부에서 버그를 발생시킬 수 있다.(함수형 프로그래밍 등장의 패러다임이다)
객체지향의
- 상속
- 어떤 클래스가 다른 클래스를 연장하여 다시 쓰는 것
- 기존 클래스는 부모 클래스가 되고, 새로 파생된 클래스는 서브클래스라고 부른다
- 캡슐화
- 내부의 코드를 캡슐처럼 보호하기 위하여 사용된다.
- 즉, 캡슐화를 위하여 모든 인스턴스 변수를 private으로 명시하고, setter와 getter 메소드를 만들어 접근하게 한다.
- 캡슐 안의 데이터에 직접적으로 접근하는 것은 불가능하며, 오로지 메소드로만 접근할 수 있다.
- 다형성
- 하나의 객체를 여러가지 타입으로 해석할 수 있는 기술이다.
- 다형성 구현을 위하여 메소드의 이름을 같게 하되, 리턴 형이나 혹은 파라미터의 개수나 타입을 다르게하여 재정의할 수 있다.
- 추상
- 객체를 생성할 수 없는 클래스로, 오로지 부모클래스로써의 역할만 하는 클래스이다.
- 추상 클래스는 추상메소드를 반드시 가져야 하지만, 비추상메소드도 가질 수 있다.
- 추상 클래스가 가지는 추상메소드의 접근 제어자는 private는 올 수 없는데, 이는 자식 클래스가 받아서 그 메소드를 오버라이드 할 수 있어야 하기 때문이다.
- 인터페이스
- 인터페이스란 메소드 선언만 하고 구현은 되어있지 않은 템플릿이다.
- 인터페이스는 다음의 조건을 만족해야 한다.
- 모든 메소드는 내부적으로 public abstract 이어야 하는데, 다른 클래스에서 구현하여 정의할 수 있어야 하기 때문이다.
- 모든 변수는 public static final constant 여야 한다.
- 인터페이스를 구현하는 클래스는 인터페이스에 선언된 모든 메소드를 포함하고 있어야 한다.
객체지향 언어의 특징과 장점
객체지향 언어의 특징으로는 상속, 캡슐화, 다형성, 추상화가 있습니다.
상속은 자식 클래스가 부모클래스를 연장해서 다시 사용할 수 있는 것이고,
캡슐화는 내부의 코드를 보호하기 위해 데이터에 직접적으로 접근하는 것을 막고 메소드로만 접근할 수 있도록 하는 것입니다.
다형성은 오버로딩을 사용하여 하나의 객체를 여러가지 타입으로 해석할 수 있는것이고
추상화는 객체를 개념화하는 것입니다.
이러한 특징들로 인해서 코드의 재사용성이 높고 유지보수가 용이하다는 장점이 있습니다.
추상클래스와 인터페이스의 차이점
추상클래스 | 인터페이스 |
---|---|
Default 생성자를 가진다. | 생성자를 가지지 않는다 |
추상 메소드, 비 추상 메소드를 포함할 수 있다. | 추상 메소드만 선언할 수 있다. |
추상 클래스를 상속한 클래스는 꼭 모든 메소드를 구현할 필요는 없으며 추상 메소드만 클래스 안에서 구현되면 된다. | 인터페이스를 구현하는 클래스는 인터페이스에서 선언된 모든 메소드를 다 구현해야 한다. |
객체 생성이 불가하므로 extends로 구현한다. | 객체 생성이 불가하므로 implements로 구현한다. |
추상클래스와 인터페이스의 차이점
추상클래스는 추상메소드를 하나이상 포함하고 있는 클래스로 Default 생성자를 가지고,
추상 클래스를 상속한 클래스가 모든 메소드를 구현할 필요는 없고 추상 메소드들만 구현하면 됩니다.
인터페이스는 추상메소드로만 이루어진 클래스로 생성자를 가지지 않고,
인터페이스를 구현하는 클래스는 선언된 모든 메소드를 다 구현해야 합니다.
둘 다 객체 생성이 불가합니다.
객체지향 5대 원칙
“SOLID” 원칙
- S: 단일 책임 원칙(SRP, Single Responsibility Principle) : 객체는 단 하나의 책임만 가져야 한다.
- O: 개방-폐쇄 원칙(OCP, Open Closed Principle) : 기존 코드를 변경하지 않으면서 기능을 추가할 수 있도록 설계가 되어야 한다.
- L: 리스코프 치환 원칙(LSP, Liskov Substitution Principle) : 일반화 관계에 대한 이야기며, 자식 클래스는 최소한 자신의 부모 클래스에서 가능한 행위는 수행할 수 있어야 한다.
- I: 인터페이스 분리 원칙(ISP, Interface Segregation Principle) : 인터페이스를 클라이언트에 특화되도록 분리시키라는 설계 원칙이다.
- D: 의존 역전 원칙(DIP, Dependency Inversion Principle) : 의존 관계를 맺을 때 변화하기 쉬운 것 또는 자주 변화하는 것보다는 변화하기 어려운 것, 거의 변화가 없는 것에 의존하라는 것이다.
객체지향 프로그래밍과 절차지향 프로그래밍의 차이
- 절차지향 프로그래밍 : 실행하고자 하는 절차를 정하고, 이 절차대로 프로그래밍하는 방법이고 목적을 달성하기 위한 일의 흐름에 중점을 둔다
- 객체지향 프로그래밍 : 실세상의 물체를 객체로 표현하고, 이들 사이의 관계, 상호 작용을 프로그램으로 나타낸다. 객체를 추출하고 객체들의 관계를 결정하고 이들의 상호 작용에 필요한 함수(메서드)와 변수(필드)를 설계 및 구현한다. 객체 지향의 핵심은 연관되어 있는 변수와 메서드를 하나의 그룹으로 묶어서 그룹핑하는 것이다. 사람의 사고와 가장 비슷하게 프로그래밍을 하기 위해서 생성된 기법이다. 하나의 클래스를 바탕으로 서로 다른 상태를 가진 인스턴스를 만들면 서로 다른 행동을 하게 된다. 즉, 하나의 클래스가 여러 개의 인스턴스가 될 수 있다는 점이 객체 지향이 제공하는 가장 기본적인 재활용성이라고 할 수 있다.
객체지향 프로그래밍과 절차지향 프로그래밍의 차이
절차지향 프로그래밍은 실행하고자 하는 흐름, 절차를 중점으로 구현하고
객체지향 프로그래밍은 객체의 표현, 객체 사이의 관계, 상호 작용을 중점으로 구현합니다.
JAVA의 특징
- 객체 지향 프로그래밍 언어
- 바이트코드로 변환되어 실행되기 때문에 고성능
- 멀티 스레딩을 지원
- JVM 위에서 실행되기 때문에, 플랫폼에 의존하지 않고 실행이 가능
JAVA의 장점
- 운영체제에 독립적이다
- JVM에서 동작하기 때문에, 특정 운영체제에 종속되지 않는다.
- 객체지향 언어이다
- 객체지향적으로 프로그래밍하기 위해 여러 언어적 지원(캡슐화, 상속, 추상화, 다형성 등)을 하고있다.
- 객체지향 패러다임의 특성상 비교적 이해하고 배우기 쉽다.
- 자동으로 메모리 관리를 해준다
- JVM에서 Gargabe Collector라고 불리는 데몬 쓰레드에 의해 CG가 일어난다.
- GC로 인해 별도의 메모리 관리가 필요 없으며 비즈니스 로직에 집중할 수 있다.
- 멀티스레드를 쉽게 구현할 수 있다
- 자바는 스레드 생성 및 제어와 관련된 라이브러리 API를 제공하고 있기 때문에 실행되는 운영체제에 상관없이 멀티 스레드를 쉽게 구현할 수 있다.
- 동적 로딩을 지원한다
- 애플리케이션이 실행될 때 모든 객체가 생성되지 않고, 각 객체가 필요한 시점에 클래스를 동적 로딩해서 생성한다
- 또한 유지보수 시 해당 클래스만 수정하면 되기 때문에 전체 애플리케이션을 다시 컴파일할 필요가 없다. 따라서 유지보수가 쉽고 빠르다.
JAVA의 단점
- 비교적 속도가 느리다
- 자바는 한 번의 컴파일링으로 실행 가능한 기계어가 만들어지지 않고 JVM에 의해 기계어로 번역되고 실행하는 과정을 거치기 때문에 C나 C++의 컴파일 단계에서 만들어지는 완전한 기계어보다는 속도가 느리다. 그러나 하드웨어의 성능 향상과 바이트 코드를 기계어로 변환해주는 JIT 컴파일러 같은 기술 적용으로 JVM의 기능이 향상되어 속도의 격차가 많이 줄어들었다.
- 예외처리가 불편하다
- 프로그래머 검사가 필요한 예외가 등장한다면 무조건 프로그래머가 선언을 해줘야 한다.
JAVA의 장단점
JAVA의 객체지향언어이며 장점으로는 JVM에서 동작하기 때문에 운영체제에 독립적이고,
Garbage Collector로 인해 자동으로 메모리 관리를 해준다는 점이 있습니다.
그리고 멀티 스레딩을 지원하고 동적 로딩을 지원해줍니다.
단점으로는 JVM에 의해 기계어로 번역되고 실행되는 과정을 거치기 때문에
C나 C++에 비해 속도가 느리고 설계단계에서의 시간이 오래걸리며
예외처리가 불편하다는 점이 있습니다.
JAVA의 접근 제어자의 종류
- public: 어떤 클래스의 객체에서든 접근 가능하다
- protected: 클래스가 정의되어 있는 해당 패키지 내 그리고 해당 클래스를 상속받은 외부 패키지의 클래스에서 접근이 가능하다.
- default: 클래스가 정의되어 있는 해당 패키지 내에서만 접근이 가능하도록 접근 범위를 제한한다
- private: 정의된 해당 클래스에서만 접근이 가능하도록 접근 범위를 제한한다.
public은 같은 프로젝트 내에서 접근 제한이 없고,
protected는 같은 패키지 안에서 사용이 가능하지만 외부에서 상속을 받으면 접근할 수 있습니다.
default는 같은 패키지 안에서만 사용이 가능하고 상속으로도 접근 할 수 없으며,
private는 해당 클래스 안에서만 접근이 가능합니다.
Generic
- 제네릭은 데이터형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있도록 하는 방법이다. 제네릭은 클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정되는 것을 의미한다. 한마디로 특정타입을 미리 정해주는 것이 아닌 필요에 의해 지정할 수 있도록 하는 일반 타입이라는 것이다.
- Generic의 장점
- 제네릭을 사용하면 잘못된 타입이 들어올 수 있는 것을 컴파일 단계에서 방지할 수 있다.
- 클래스 외부에서 타입을 지정해주기 때문에 따로 타입을 체크하고 변환해줄 필요가 없다. 즉, 관리하기가 편하다.
- 비슷한 기능을 지원하는 경우 코드의 재사용성이 높아진다.
Generic
제네릭은 데이터 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있도록 하는 방법입니다.
클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정하여 사용합니다.
제네릭을 사용하면 잘못된 타입이 들어올 수 있는 것을 컴파일 단계에서 방지할 수 있고 관리하기가 편하며 코드의 재사용성을 높일 수 있습니다.
Collection
-
Java Collection 에는 List, Map, Set 인터페이스를 기준으로 여러 구현체가 존재한다. Collection을 사용하는 이유는 다수의 데이터를 다루는데 표준화된 클래스들을 제공해주기 때문에 DataStructure를 직접 구현하지 않고 편하게 사용할 수 있기 때문이다. 또한 배열과 다르게 객체를 보관하기 위한 공간을 미리 정하지 않아도 되므로, 상황에 따라 객체의 수를 동적으로 정할 수 있다. 이는 프로그램의 공간적인 효율성 또한 높여준다.
-
List : List 인터페이스를 직접 사용자가 정의하여 사용할 수도 있고, 대표적인 구조체로는 ArrayList가 존재한다. 이는 기존에 있었던 Vector를 개선한 것이다. 이외에도 LinkedList 등의 구현체가 있다. 데이터를 순차적으로 저장, 데이터의 중복을 허용, 데이터로 null을 허용
-
Map : 대표적인 구현체로 HashMap이 존재한다. Key-value의 구조로 이루어져 있으며 Map 에 대한 구체적인 내용은 DataStructure 부분의 hashtable과 일치한다. Key 를 기준으로 중복된 값을 저장하지 않으며 순서를 보장하지 않는다. Key 에 대해서 순서를 보장하기 위해서는 LinkedHashMap을 사용한다. 순서없이 key, value로 데이터를 저장, value는 중복을 허용하지만 key는 중복을 허용하지 않는다.
-
Set : 대표적인 구현체로 HashSet이 존재한다. Value에 대해서 중복된 값을 저장하지 않는다. 사실 Set 자료구조는 Map의 key-value 구조에서 key 대신에 value가 들어가 value를 key로 하는 자료 구조일 뿐이다. 마찬가지로 순서를 보장하지 않으며 순서를 보장해주기 위해서는 LinkedHashSet을 사용한다. 순서없이 key로만 데이터를 저장, key의 중복을 허용하지 않는다, key로 null을 허용하지 않는다
-
Stack과 Queue
인터페이스 | 설명 | 구현 클래스 |
---|---|---|
List | 순서가 있는 데이터의 집합으로, 데이터의 중복을 허용함 | Vector, ArrayList, LinkedList, Stack, Queue |
Set | 순서가 없는 데이터의 집합으로, 데이터의 중복을 허용하지 않음 | HashSet, TreeSet |
Map<K, V> | 키와 값의 한 쌍으로 이루어지는 데이터의 집합으로, 순서가 없음. 이때 키는 중복을 허용하지 않지만, 값은 중복될 수 있음 | HashMap, TreeMap, HashTable, Properties |
Collection Framework
데이터를 저장하는 자료 구조와 데이터를 처리하는 알고리즘을 구조화하여 클래스로 구현해 놓은 것입니다.
이러한 컬렉션 프레임워크는 인터페이스를 사용하여 구현되며 주요 인터페이스로는 List, Map, Set가 있습니다.
List는 순서가 있는 데이터 집합으로, 데이터의 중복을 허용합니다.
Set은 순서가 없는 데이터의 집합으로, 데이터의 중복을 허용하지 않습니다.
Map은 키와 값의 한 쌍으로 이루어지는 데이터의 집합으로, 순서가 없습니다. 이때 키는 중복을 허용하지 않지만, 값은 중복될 수 있습니다.
Java의 vector와 arraylist 차이
- vector: 동기화를 지원, 속도가 느리지만 병렬 상황에서 안전, 크기가 증가하는 경우, 2배가 증가
- arrylist: 동기화를 지원하지 않는다, 속도는 빠르지만 병렬 상황에서 안정하지 않다. 크기가 증가하는 경우 1.5배 증가함
Wrapper class
- 기본 자료형에 대한 클래스 표현을 Wrapper class라고 한다. Integer, Float, Boolean 등이 래퍼 클래스의 예이다. 래퍼 클래스는 각각의 타입에 해당하는 데이터를 인수로 전달받아, 해당 값을 가지는 객체로 만들어 준다.
사용 이유: 컬렉션에서 제네릭을 사용하기 위해서는 래퍼 클래스를 사용해줘야 한다. Null 값을 반환해야만 하는 경우에는 return type을 wrapper class 로 지정하여 null을 반환하도록 할 수 있다. 하지만 이러한 상황을 제외하고 일반적인 상황에서 wrapper class를 사용해야 하는 이유는 객체지향적인 프로그래밍을 위한 프로그래밍이 아니고서야 없다. 일단 해당 값을 비교할 때, Primitive data type 인 경우에는 ==로 바로 비교해줄 수 있다. 하지만 래퍼 클래스인 경우에는 .intValue() 메소드를 통해 해당 래퍼클래스의 값을 가져와 비교해줘야 한다. - 박싱(Boxing), 언박싱(Unboxing)
래퍼 클래스는 산술 연산을 위해 정의된 클래스가 아니므로, 인스턴스에 저장된 값을 변경할 수 없다. 단지, 값을 참조하기 위해 새로운 인스턴스를 생성하고, 생성된 인스턴스의 값만을 참조할 수 있다. 기본 타입의 데이터를 래퍼 클래스의 인스턴스로 변환하는 과정을 박싱, 래퍼 클래스의 인스턴스에 저장된 값을 다시 기본 타입의 데이터로 꺼내는 과정을 언박싱이라고 한다. - 오토 박싱(AutoBoxing), 오토 언박싱(AutoUnBoxing)
JDK 1.5부터는 박싱과 언박싱이 필요한 상황에서 자바 컴파일러가 이를 자동으로 처리해 준다. 이렇게 자동화된 박싱과 언박싱을 오토 박싱과 오토 언박싱이라고 부른다.
Integer num = new Integer(17); // 박싱
int n = num.intValue(); // 언박싱
System.out.println(n); // 출력 값: 17
Character ch = 'X'; // Character ch = new Character('X'); : 오토박싱
char c = ch; // char c = ch.charValue(); : 오토언박싱
System.out.println(c); // 출력 값: X
래퍼 클래스의 비교 연산도 오토언박싱을 통해 가능해지지만, 인스턴스에 저장된 값의 동등 여부 판단은 비교 연산자인 동등 연산자(==)를 사용해서는 안되며, equals() 메소드를 사용해야만 한다. 래퍼 클래스도 객체이므로 동등 연산자를 사용하게 되면, 두 인스턴스의 값을 비교하는 것이 아니라 두 인스턴스의 주소 값을 비교한다.
public class Wrapper03 {
public static void main(String[] args) {
Integer num1 = new Integer(10);
Integer num2 = new Integer(20);
Integer num3 = new Integer(10);
System.out.println(num1 < num2); // true
System.out.println(num1 == num3); // false
System.out.println(num1.equals(num3)); // true
}
}
Wrapper Class
기본 자료형에 대한 클래스 표현을 래퍼 클래스라고 합니다.
데이터를 전달받아 객체로 사용하며 컬렉션에서 제네릭을 사용하기 위해 사용합니다.
JVM (Java Virtual Machine)
-
JVM : 자바 가상 머신의 약자를 따서 부르는 용어. (가상 머신이란 프로그램을 실행하기 위해 물리적 머신과 유사한 머신을 소프트웨어로 구현한 것) JVM의 역할은 자바 애플리케이션을 클래스 로더를 통해 읽어 들여 자바 API와 함께 실행하는 것이다. 그리고 JVM은 JAVA와 OS사이에서 중재자 역할을 수행하여 JAVA가 OS에 구애받지 않고 재사용을 가능하게 해준다. 그리고 가장 중요한 메모리 관리, Garbage collection을 수행한다. 그리고 JVM은 스택기반의 가상머신이다.
-
JVM 구조 중 메모리 구조
- Method Area(메소드 영역): 클래스 변수의 이름, 타입, 접근 제어자 등과 같은 클래스와 관련된 정보를 저장한다. 그 외에도 static 변수, 인터페이스 등이 저장된다.
- Heap Area(힙 영역): new를 통해 생성된 객체와 배열의 인스턴스를 저장하는 곳이다. 가비지 컬렉터는 힙 영역을 청소하며 메모리를 확보한다.
- Stack Area(스택 영역): 메소드가 실행되면 스택 영역에 메소드에 대한 영역이 1개 생긴다. 이 영역에 지역변수, 매개변수, 리턴값 등이 저장된다.
- PC register(PC 레지스터): 현재 쓰레드가 실행되는 부분의 주소와 명령을 저장한다.(CPU의 레지스터와 다르다.)
- Native Method Stack(네이티브 메소드 스택): 자바 외의 언어(C, C++ 등)로 작성된 코드를 위한 메모리 영역이다. JNI를 통해 사용된다
- 프로그램이 실행되면 JVM은 OS로부터 이 프로그램이 필요로 하는 메모리를 할당받는다. JVM은 이 메모리를 용도에 따라 여러 영역으로 나누어 관리한다.
- 자바 컴파일러(javac)가 자바 소스코드(.java)를 읽어들여 자바 바이트코드(.class)로 변환시킨다.
- Class Loader를 통해 class파일들을 JVM으로 로딩한다.
- 로딩된 class파일들을 Execution engine을 통해 해석된다.
- 해석된 바이트코드는 Runtime Data Areas에 배치되어 실질적인 수행이 이루어지게 된다.
이러한 실행과정 속에서 JVM은 필요에 따라 Thread Synchronization과 GC같은 관리 작업을 수행한다.
Java 소스 파일을 javac로 컴파일하여 class파일(Java 바이트 코드)을 생성 -> 클래스로더가 컴파일된 Java 바이트 코드를 런타임 데이터영역으로 로드함 -> 실행 엔진이 자바 바이트코드를 실행
https://asfirstalways.tistory.com/158
JVM, 실행 과정
JVM 은 자바 가상 머신의 약자로써 자바 애플리케이션을 클래스 로더를 통해 읽어 들여 자바 API와 함께 실행하는 역할을 합니다.
JVM을 사용하여 JAVA가 운영체제에 독립적으로 사용할 수 있게 하며 메모리 관리와 GC를 수행합니다.
JAVA의 실행과정은 자바 컴파일러를 통해 자바 소스코드를 .javac 읽어들여 자바 바이트코드.class를 생성합니다.
클래스 로더를 통해 class파일들을 JVM으로 로딩하여 런타임 데이터 영역에 로드합니다.
실행 엔진을 통해 실행이 됩니다.
Garbage Collection
-
가비지 컬렉션은 메모리를 정리하는 과정, 그렇기 때문에 일반적으로 메모리의 사용을 중단한 채로 진행이 되어야 한다, JVM은 GC를 실행하기 위해 애플리케이션의 실행을 멈추는 stop-the-world를 먼저 실행하게 된다. Stop-the-world를 실행하면 GC를 실행하는 쓰레드를 제외한 모든 쓰레드가 작업을 멈춘다, 그리고 GC가 끝나면 다시 작업을 재개, GC의 작업은 Young 영역에 대한 Minor GC와 Old영역에 대한 Major GC로 구분
-
Young 영역: 새롭게 생성한 객채들이 위치한다. 대부분의 객체는 금방 접근 불가능한 상태가 되기 때문에, 많은 객체가 Young 영역에 생성되었다가 사라진다.
-
Old 영역: Young 영역에서 계속 사용되어 살아남은 객체가 복사되는 영역, Young 영역보다 크게 할당되며, 더 적은 GC가 발생
-
가비지 컬렉션 알고리즘 종류(추후)
-
가비지 컬렉션에 의한 시스템 중단 시간을 줄이는 방법(추후)
https://mangkyu.tistory.com/94
Garbage Collector
C언어는 직접 메모리를 해제해줘야 하지만 자바는 JVM의 가비지 컬렉터가 메모리 자동으로 정리해줍니다
GC의 작업은 Young 영역에 대한 Minor GC와 Old영역에 대한 Major GC로 구분됩니다.
Young 영역은 새롭게 생성한 객체들이 위치하고 Old 영역은 Young 영역에서 계속 사용되어 살아남은 객체가 복사되는 영역입니다.
Annotation
- 메타데이터 : 메타데이터란 데이터의 대한 속성정보이다. 데이터의 대한 데이터로서 하위 레벨 데이터를 설명 및 기술하는 데이터라고 보면된다. 도서관을 예시로 들어보자면 표제, 저자, 주제명, 분류기호 등이 포함되어 있는 목록이 메타데이터의 속한다.
- 어노테이션이란 메타데이터라고 볼 수 있다. 프로그램 실행 관점에서보면 프로그램이 처리할 메인 데이터가 아니라 실행과정에서 데이터를 어떻게 처리할것인지 알려주는 서브 데이터라고 볼 수 있는 것이다.
- 어노테이션의 세가지 용도
- 코드 문법 에러체크
- 코드 자동 생성 정보 제공
- 런타임시 특정 기능을 실행하는 정보 제공
- 어노테이션 사용방식 두가지
- Custom Annotation : 직접 생성하여 사용
- Built-in Annotation : Java에서 제공
Annotation
어노테이션은 프로그램 실행과정에서 데이터를 어떻게 처리할 것인지 알려주는 서브 데이터라고 할 수 있습니다.
코드 문법의 에러체크와 코드 자동 생성 정보 제공,
런타임시 특정 기능을 실행하는 정보를 제공하기 위해 사용합니다.
Java의 String, SrtingBuffer, StringBuilder
- Java 에서 문자열을 다루는 대표적인 클래스로 String, StringBuffer, StringBuilder가 있다. 연산이 많지 않을 때는 어떤 클래스를 사용하더라도 이슈가 발생할 가능성은 거의 없다. 그러나 연산횟수가 많아지거나 멀티쓰레드, Race condition 등의 상황이 자주 발생한다면 각 클래스의 특징을 이해하고 상황에 맞는 적절한 클래스를 사용해야 한다.
- String은 불변성을 가지기 때문에 변하지 않는 문자열을 자주 읽어들이는 경우에 사용한다. 문자열 추가, 수정, 삭제 등의 연산이 빈번하게 발생하는 알고리즘에 String을 사용하면 힙 메모리에 많은 임시 가비지가 생성되어 힙메모리 부족으로 어플리케이션 성능에 치명적인 영향을 끼친다.
- StringBuffer, StringBuilder 는 가변성을 가져서 .append() .delete() 등의 API를 이용하여 동일 객체내에서 문자열을 변경하는 것이 가능하다. 따라서 문자열의 추가, 수정, 삭제가 빈번하게 발생할 경우에 사용한다.
- String : 문자열 연산이 적고 멀티쓰레드 환경일 경우
- StringBuffer : 동기화를 지원하여 문자열 연산이 많고 멀티쓰레드 환경일 경우
- StringBuilder : 동기화를 지원하지 않는다. 문자열 연산이 많고 단일쓰레드이거나 동기화를 고려하지 않아도 되는 경우
String, StringBuffer,StringBuilder
String은 불변성을 가져서 변하지 않는 문자열을 자주 읽어들이거나, 문자열 연산이 적고 멀티쓰레드 환경일 경우 사용합니다.
StringBuffer와 StringBuilder는 가변성을 가져서 문자열 연산이 많을 때 사용합니다.
그렇지만 StringBuffer는 동기화를 지원하여서 멀티쓰레드 환경일 경우 사용하고
StringBuilder는 동기화를 지원하지 않아서 단일쓰레이거나 동기화를 고려하지 않아도 되는 경우에 사용합니다.
final
- final 키워드는 변수나 메서드 또는 클래스가 '변경 불가능' 하도록 만드는것이다.
- 원시 변수: 해당 변수의 값은 변경이 불가능
- 참조 변수: 참조 변수가 힙 내의 다른 객체를 가리키도록 변경할 수 없다
- 메소드: 오버라이드 될 수 없다
- 클래스: 상속 될 수 없다
- 생성자 : 생성자는 final이 될 수 없다.
finally
- try/catch 블록이 종료될 때 항상 실행될 코드 블록을 정의하기 위해 사용한다.
- finally는 선택적으로 try 혹은 catch 블록 뒤에 정의할 때 사용, finally 블록은 예외가 발생하더라도 항상 실행
finalize()
- GC가 더 이상의 참조가 존재하지 않는 객체를 메모리에서 삭제하겠다고 결정하는 순간 호출된다.
final 키워드
final 키워드는 변수나 메서드 또는 클래스가 변경 불가능하도록 만드는 것입니다.
final 키워드를 사용하면 변수의 값을 변경할 수 없고 메소드는 오버라이드 될 수 없으며 클래스는 상속될 수 없습니다.
예외(Exception)
- 예외한 실행 중에 발생할 수 있는, 개발자가 구현한 로직에서 발생하는 문제
- 예외의 종류로는 체크예외, 언체크 예외
- 체크예외 : 컴파일 단계에서 확인되는 예외들, 반드시 명시적으로 처리, 로직상 예외 발생 가능성이 있는 상황들을 표현, 주로 JVM 외부와 통신 시에 발생하는 예외들
- 언체크 예외: 실행 단계에서 확인 되는 예외들, 명시적인 처리를 강제하지 않는다, RuntimException 클래스의 하위 클래스들이 모두 여기에 속한다
- 예외 처리 방법 : Try/Catch 블록, throw, catch에서 다른 예외로 던지는 것
예외
예외란 프로그램 실행 중에 발생할 수 있는 개발자가 구현한 로직에서 발생하는 문제입니다.
예외의 종류로는 컴파일 단계에서 확인되는 예외로 개발자가 반드시 명시적으로 처리해야하는 체크 예외가 있고
실행 단계에서 확인 되는 언체크 예외가 있습니다.
예외의 처리 방법으로는 try, catch 블록을 사용하는 것과 throw를 사용하는 것, catch에서 다른예외로 던지는 방법이 있습니다.
synchronized
- 여러 쓰레드가 하나의 자원을 이용하고자 할 때, 한 스레드가 해당 자원을 사용중인 경우, 데이터에 접근할 수 없도록 막는 키워드. 병렬 상황에서 자원의 접근을 안전하게 하지만, 자원을 이용하지 않는 쓰레드는 락에 의한 병목현상이 발생
- 메소드 synchronized: 한 시점에 하나의 쓰레드만이 해당 메소드를 실행할 수 있다
- 변수 synchronized: 한 시점에 하나의 쓰레드만이 해당 변수를 참조할 수 있다.
synchronized
여러 쓰레드가 사용중인 하나의 자원을 이용하고자 할 때 데이터에 접근할 수 없도록 막는 키워드 입니다.
메소드에서 사용하면 한 시점에 하나의 쓰레드만이 해당 메소드를 실핼할 수 있고
변수에서 사용하면 한 시점에 하나의 쓰레드만이 해당 변수를 참조할 수 있습니다.
Java8에서 추가된 것
- 함수형 프로그래밍을 위한 stream API와 Lambda, 함수형 인터페이스 등과 Null-safe한 작업을 위한 Optional API 등이 추가
java8 특징
함수형 프로그래밍을 위한 stream API 와 Lambda, 함수형 인터페이스와 Optional API가 추가 되었습니다.
Stream API
- Java에서 함수형 프로그래밍할 수 있는 API중 하나로 데이터를 추상화하고, 처리하는데 자주 사용되는 함수들을 정의해두었다.
- 특징: 원본의 데이터를 변경하지 않는다, 일회용이다, 내부 반복으로 작업을 처리한다.
- 연산 종류: 생성하기, 가공하기, 결과만들기
- 장점: 코드를 간결하게 작성하여 가독성을 높일 수 있다. 병렬스트림과 같은 기술을 이용하면 처리 속도를 많이 높일 수 있다
- 단점: 잘못 사용하면 기존의 Java 방식보다 오히려 성능이 떨어질 수 있다. 코드들이 추상화되어 있어 실수가 발생할 수 있다.
Stream API
Java에서 함수형 프로그래밍을 할 수 있도록 해주는 API중 하나로
데이터를 추상화하고 처리하는데 자주 사용되는 함수들을 정의해 둔것입니다.
Stream API는 원본의 데이터를 변경하지 않고 일회용으로 사용하며 내부 반복으로 작업을 처리합니다.
장점으로는 코드를 간결하게 작성하여 가독성을 높일 수 있지만
단점으로 코드들이 추상화되어 있어 실수가 발생할 수 있고 잘못 사용하면 오히려 성능이 떨어질 수 있습니다.
람다(Lambda)
- 람다는 불필요한 코드를 줄이고, 가독성을 높이기 위한 익명 함수로써, 함수의 이름과 반환타입 없이 손쉽게 함수를 선언할 수 있다. 람다는 아래와 같이 괄호와 화살표로 표현할 수 있으며, 람다의 반환값은 함수형 인터에피스이므로, 이를 이용해줘야 한다. 함수를 하나의 식으로 표현한 것, 익명 함수의 한 종류
interface MyFunctionalInterface {
String test();
}
public class Lambda {
public static void main(String[] args) throws Throwable {
String str = "This is My String";
// Labmda Expression
MyFunctionalInterface fi = () -> str.replaceAll("\\s+", "");
System.out.println(fi.test()); }
}
- 특징: 람다식 내에서 사용되는 지역변수는 final을 붙지 않아도 상수로 간주된다, 람다식으로 선언된 변수명은 다른 변수명과 중복될 수 없다.
- 장점: 코드를 간결, 가독성 높아짐, 함수를 만드는 과정없이 한번에 처리할 수 있어 생산선 높음, 병렬프로그래밍 용이
- 단점: 재사용 불가, 디버깅 어려움, 남발하면 코드가 지저분, 재귀로는 부적합
람다식
함수를 하나의 식으로 표현한 것으로 익명함수의 한 종류라고 할 수 있습니다.
람다식을 사용하면 코드를 간결하게 작성할 수 있어 가독성이 높아지고 생산성이 높아집니다.
그러나 재사용이 불가하고 디버깅이 어려우며 람다식을 너무 남발하여 사용하면
코드가 지저분해질 수 있다는 단점이 있습니다.
함수형 인터페이스
- 함수를 1급 객체처럼 다룰 수 있게 해주는 어노테이션으로, 인터페이스에 선언하여 단 하나의 추상 메소드만을 갖도록 제한하는 역할을 한다. 함수형 인터페이스를 사용하는 이유는 Java의 람다식이 함수형 인터페이스를 반환하기 때문이다.
Optional
- Optional 클래스를 사용해 NPE(NullPointerException)를 방지할 수 있도록 도와준다. Optional는 null이 올 수 있는 값을 감싸는 Wrapper클래스로, 참조하더라도 NPE가 발생하지 않도록 보와준다.
- orElse(): null이든 아니든 항상 호출된다.
- orElseGet(): null일 때만 호출된다.
Optional
null 또는 실제값을 value로 갖는 wrapper로 감싸서 NPE으로 부터 자유로워지기 위해 나온 래퍼 클래스입니다.
메소드의 결과가 null이 될 수 있으며, 클라이언트가 이 상황을 처리해야 할 때 사용하는 것이 좋습니다.
Optional API의 단말 연산에서는 orElse와 orElseGet함수가 있습니다.
orElse 는 null이든 아든 항상 호출되고 orElseGet은 null일때만 호출된다는 차이점이 있습니다.
Author And Source
이 문제에 관하여(JAVA 정리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@cksql428/JAVA-leoekhie저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)