📌 1. Java란?
📎 Java란?
🔥 출처: 위키백과 사전
자바(Java)
는 자바로 기술된 프로그램 개발 및 실행을 할 수 있는 소프트웨어 모임의 총칭이다. 자바 프로그램은 운영체제나 하드웨어에 의존하지 않는 바이트 코드(중간 언어)인 추상적인 코드로 구현된다. 따라서, 자바 프로그램을 실행하기 위해서는 자바 가상 머신(JVM)
과 개발에 필요한 표준 라이브러리 세트
와 컴파일러의 환경
만 맞추면 자바 프로그램은 모든 환경에서 동일하게 동작한다. 이러한 실행환경과 개발환경을 제공하는 것이 자바 플랫폼이다.
📌 2. Java의 장단점
📎 Java 장점
👉 ⭐️객체지향 프로그래밍 언어(OOP:Object Oriented Programming)⭐️
- 유지보수가 쉽고 직관적인 코드 분석이 가능하다.
- 설계도인 클래스를 작성하여, 객체와 객체를 연결하여 목적에 맞는 프로그램을 완성한다.
👉 분산 네트워크 기술 지원
- 자바에는 TCP/IP라이브러리가 기본적으로 포함되어 있고, HTTP 프로토콜을 지원한다.
👉 멀티쓰레드(Multi Thread) 지원
- 동일한 쓰레드를 동시에 수행할 수 있다.
- 사용자 인터페이스 쓰레드와 장시간 계산이 필요한 쓰레드가 동시에 필요할 때 효과적이다.
👉 ⭐️이식성이 높음⭐️
자바가상머신(JVM)
에서 작동하기 때문에 운영체제(ex: Window, Linux)의 종류에 상관없이 작동한다.
👉 ⭐️자동 메모리 관리(Garbage Collector)⭐️
- 객체 생성시 자동으로 메모리 영역을 찾아서 할당하고, 사용이 완료된 객체는 쓰레기 수집기(Garbage Collector)를 실행시켜 자동으로 메모리에서 체크하고 반환해준다.
- 자바는 개발자가 직접 메모리에 접근할 수 없으며, 메모리는 자바가 직접 관리한다.
👉 동적 로딩 지원
- 프로그램 실행시 모든 클래스가 로딩되지 않고, 필요한 시점에 클래스를 로딩하여 사용할 수 있다.
- 그러므로 애플리케이션의 변경사항도 비교적 적은 작업만으로 처리할 수 있다.
👉 오픈소스 라이브러리가 풍부하다.
- 자바는 오픈소스(Open Source)언어이고 자바 프로그램에서 사용하는 라이브러리 또한 오픈소스 양이 방대하다.
- 고급 기능을 구현하는 코드를 작성하는 대신 검증된 오픈소스 라이브러리를 사용하면 애플리케이션을 다시 컴파일 할 필요가 없다. 따라서 유지보수를 쉽고 빠르게 할 수 있다.
📎 Java 단점
👉 속도가 느림
- 자바는 실행을 위해 자바 가상 머신을 거쳐야 하므로, 다른 언어에 비해 실행 속도가 느려서 처리 속도가 중요한 애플리케이션에는 적합하지 않다.
- 하지만 바이트코드(byte code)를 하드웨어의 기계어로 변환해주는 JIT컴파일러와 Hotspot(향상된 최적화 기술)과 같은 기술 적용으로 JVM 기능이 향상되어 속도문제가 개선되었다.
👉 불편함 예외처리
- 자바는 예외 처리가 잘 되어 있지만, 개발자가 일일이 지정해 줘야 한다는 불편함도 있다. 그렇게 하지 않으면, 컴파일조차 거부된다.
👉 하드웨어 정밀 조정 불가
- 하드웨어에 연결할 수 없기 때문에 직접 하드웨어를 정밀하게 조정해야 하는 프로그램 개발에는 적합하지 않다.
📌 3. Java is 객체지향 언어
📎 객체지향 언어란?
객체지향언어란, 프로그램을 데이터와 처리방법으로 나누지 않고, 객체를 만들고 조작하며 객체끼리 관계를 맺음으로써 다수의 객체가 서로 상호작용할 수 있게 하는 것이다. 다시 말해, 객체를 조립해서 전체의 프로그램을 만드는 조립식 프로그래밍이다.
📎 객체(Object)란?
물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신과 다른 것을 식별가능한 것을 말한다. 예를 들어, 물리적으로 존재하는 학생, 회원 등과 추상적으로 생각할 수 있는 생산, 주문, 배송 등이 모두 객체가 될 수 있다.
📎 클래스(Class)란?
객체라는 추상적인 개념을 코드화 한 것을 클래스
라고 한다. 간단하게 생각하면, 클래스는 붕어빵틀 그리고 객체는 붕어빵 정도로 생각하면 좋다. 이처럼 객체를 만들기 위한 설계도
개념인 클래스는 객체의 속성
과 기능
을 표현하는 변수
가 메소드
를 포함한다.
👉 상태: 멤버변수
클래스 안에서 선언되는 변수를 멤버 변수라고 하며 객체가 가지는 속성을 표현하는데 사용된다.
👉 동작: 메소드
메소드는 객체 안에서 사용하는 함수로 객체가 제공하는 기능을 구현하는데 사용된다.
👉 멤버변수와 메소드 예시
멤버변수와 메소드를 각각 클래스의 상태와 동작의 역할이라고 생각하면 이해하기 쉽다. 예를 들어, 고양이라는 클래스가 있다고 가정해보자. 고양이를 이루는 여러가지 요소를 크게 나누면 상태(속성)와 동작으로 나눌 수 있다. 고양이의 상태로는 생김새나 이름 몸무게 등이 있다. 반대로 고양이의 동작은 할퀴기나 핡기 그리고 밥먹기 등이 있다. 이런 상태와 동작을 각각 메소드와 클래스로 표현하면 아래와 같이 표현된다.
Class cat {
String name = 'kitty';
int weight = 10 ;
void claw() { }
}
Class cat1 = new Cat();
📎 객체지향언어의 특징 4가지
👉 캡슐화(Encapsulation)
- 그림 설명: 원은 멤버 변수이고, 원을 둘러싸고 있는 것은 멤버 메서드이다. 객체의 필드(속성)와 메소드를 하나로 묶고 실제 구현 내용을 외부로 부터 감추는 형태를 그림으로 표현한 것이다.
- 캡슐화에 의해, 외부 객체는 객체 내부의 구조를 얻지 못한다. 객체가 일부로 노출해서 제공하는 필드오 메소드만을 이용할 수 있어야 한다.
- 객체지향 프로그래밍에서는 객체의 데이터를 외부에서 마음대로 읽고 변경할 경우 객체의 무결성이 깨질 수 있기 때문에 일반적으로 외부의 접근을 막는 경우가 많다.
- JAVA의 접근 제한자 public, private, default, proected 로 캡슐화의 구조를 이해할 수 있다.
👉 상속(Inheritance)
- 상위 클래스의 모든걸 하위 클래스가 이어 받는 것으로 기존 코드를 재활용할 수 있다.
- 상속의 대상은 부모의 필드와 메소드이다.
- 상속의 효과로 4가지 정도를 이야기할 수 있다.
- 부모 클래스를 재사용해서 자식 클래스의 효율적인 개발을 도모할 수 있다.
- 반복된 코드의 중복을 줄여준다.
- 유지보수의 편리성을 제공한다.
- 객체의 다형성을 구현할 수 있게 한다.
👉 다형성(Polymorephism)
- 같은 타입이지만 실행 결과가 다양한 객체를 대입할 수 있는 성질을 말한다. 다시 말해, 하나의 이름으로 많은 상황에 대처하다보니 코드가 간결해지는 효과가 있다.
- 오버로드(Overload)와 오버라이드(Override)가 다형성의 대표적인 예시이다.
👉 추상화(Abstraction)
- 추상화는 객체의 공통적인 속성과 기능을 추출하여 정의하는 것을 말한다.
- 사과, 딸기, 배라는 각각의 객체가 있고 이 객체를 하나를 묶기 위해 과일이라는 추상적인 객체로 정의한다고 하면, 이 행위를 추상화라고 할 수 있다.
📎 객체지향의 5원칙
👉 단일책임원칙(SRP Single Responsibility Principle)
- 하나의 클래스는 하나의 책임만 가져야 한다는 원칙이다. 즉, 어떤 변화(요구사항의 변화) 등에 의해 클래스를 변경해야 하는 이유는 오직 하나여야 한다.
- 나머지 4원칙의 기초가 되는 원칙이기 때문에 SRP 원칙만 잘 지키면 다른 책임의 변경으로 인한 연쇄작용을 방지 가능하다.
👉 개방 폐쇄 원칙(OCP Open-Closed Principle)
- SW의 구성요소인 모듈, 컴포넌트, 클래스, 메소드는 확장에는 열려있고, 변경에는 닫혀 있어야 한다.
- 확장에 열려있다는 뜻은, 새로운 변경사항이 발생했을 때 유연하게 코드를 추가 또는 수정할 수 있어야 한다는 뜻이다.
- 변경에 닫혀있다는 뜻은, 객체를 직접 수정하지 않고도 변경사항을 적용할 수 있도록 설계해야한다는 뜻이다.
- 시스템의 아키텍쳐를 떠받치는 원동력이되는 원칙이다.
👉 리스코프 치환 원칙(LIP The Liskov Subsitution Principle)
- 부모 클래스를 상속한 자식 클래스는 부모 클래스의 역할을 정확히 해내야 한다.
- 자식 클래스의 상세 내부를 부모 클래스는 알 필요가 없지만, 상속의 과정 중 메소드의 재정의가 필요할 때 자식 클래스가 부모 클래스의 기존 메소드 의미를 해치지 않아야 한다.
👉 인터페이스 분리 원칙(ISP Interface Segregation Principle)
- 한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다. 즉, 꼭 필요한 인터페이스만 상속해야 한다.
- 클라이언트 자신이 사용하는 메소드에만 의존해야 하며, 사용하지 않는 인터페이스의 메소드를 의존하면 안된다.
- 인터펭스는 그 인터페이스를 사용하는 클라이언트를 기준으로 분리해야 한다.
👉 의존성 역전의 원칙(DIP Dependency Inversion Principle)
- 여기서 DI는 의존성 주입으로, 변화하기 쉬운 것 혹은 자주 변화하는 것 보다 변화하기 어려운 것 혹은 변화가 거의 없는 것에 의존해야 하는 원칙이다.
- 고차원 모듈은 잘 변화하기 않는다.
📎 객체지향언어 장점
재사용성
신뢰성 향상
유지보수의 우수성
📎 객체지향언어 단점
개발속도가 느림
실행속도가 느림
📌 4. JAVA의 구성
👉 JDK(JAVA Development Kit)
- 자바 개발 키트 라는 뜻으로 개발자가 JAVA 프로그램을 개발하기 위한 환경을 제공한다. JDK에는 JRE가 포함되어 있으며, JAVA소스를 JVM이 읽을 수 있는 바이트코드로 변환하는 컴파일러와 같이 개발에 필요한 도구를 포함하고 있다.
👉 JRE(JAVA Runtime Environment)
- 자바 실행 환경이라는 뜻으로 JAVA 프로그램이 실행되기 위한 최소의 조건을 포함하고 있다. 바로 플랫폼에 알맞는
JVM
과 표준 클래스 라이브러리(API)
이다.
📌 5. JAVA 실행과정
- 프로그램 Runtime시 JVM은 OS로부터 프로그램이 필요로 하는 메로리를 할당받음
- 자바 컴파일러(javac)가 java 소스코드를 통해 jvm이 이해할 수 있는 바이트코드(.class)로 변환
- 클래스로더(Class Loader)를 통해 Class파일들을 JVM으로 로딩
- 로딩된 Class파일들은 실행엔진(Execution Engine)을 통해 해석됨
- 해석된 바이트코드는 메모리(Runtime Data Areas)에 배치되어 실질적인 수행이 이루어짐 + 이런 실행과정 동안 JVM은 필요에 따라 GC같은 관리 작업 수행
📌 6. JVM이란?
📎 JVM이란?
JVM이란 JAVA Virtual Machine의 약자이다. JAVA는 하드웨어가 아닌 JVM이라는 가상머신을 통해 작동한다. 이 JVM은 시스템 메모리를 관리하면서 자바 기반 애플리케이션을 위해 이식 가능한 실행 환경(자체 CPU, 메모리, 네트워크 인터페이스 및 스토리지 등...)을 제공한다.
📎 JVM 특징
👉 중개자 역할
- JVM은 자바 애플리케이션을 클래스 로더를 통해 읽어들여 자바 API와 함께 실행한다. 이 실행된 JVM은 JAVA와 OS 사이에서 중개자 역할을 수행하여 JAVA가 OS나 CPU에 구애받지 않고 재사용을 가능하게 해준다.
👉 메모리 관리자
- JVM은 메모리를 관리하고 Garbage Collection실행을 통해 메모리를 최적화한다.
📎 JVM 구조
📂 1) 클래스 로더(Class Loader)
Runtime시 JVM내로 클래스(.class)를 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈이다.
로딩
: .clss를 읽어옴
링크
: 코드 내부의 레퍼런스를 연결함
초기화
: 클래스에 있는 static값들을 초기화함
📂 2) 메모리(Runtime Data Area)
프로그램을 수행하기 위해 OS에서 할당받은 메모리 공간으로, 힙,메소드
는 전체 공유자원으로 분류되고 스택,PC,네이티브메소드 스택
은 쓰레드 단위의 자원으로 분류된다.
PC(PC Register)
- 쓰레드(Thread)가 시작될 때 생성되며 생성될 때마다 생성되는 공간으로 쓰레드마다 하나씩 존재함
- 쓰레드가 어떤 부분을 어떤 명령으로 실행해야할 지에 대한 기록하는 부분
스택(Stack)
- 프로그램 실행과정에서 임시로 할당되었다가 메소드를 빠져나가면 바로 소멸되는 특성의 데이터를 주로 저장하는 영역
- 메소드 호출때마다 각각의 스택 프레임(그 메서드만을 위한 공간)이 생성되고 메소드 수행이 끝나면 프레임 별로 삭제 수행
- 에러 났을 때 에러 메시지보면 런타임 스택에 메시지가 쌓여있는 것을 볼 수 있음
네이티브 메소드 스택(Native Method Stack)
- 자바 프로그램이 컴파일되어 생성되는 바이트코드가 아닌 기계어로 작성된 프로그램을 실행시키는 별도의 스택 영역
- JAVA Native Interface를 통해 바이트 코드로 전환하여 저장한다.
메소드(Method) = Class Area = Static Area
- 프로그램 시작 전에 클래스 수준의 정보(클래스 이름, 부모 클래스 이름, 메소드, static 변수, 일반 변수 등...)를 저장하여 프로그램 종료때까지 해당 데이터를 가지고 감
- 자바는 Main 메소드의 호출에서부터 계속된 메소드의 호출로 흐름을 이어가기 때문에, 메소드의 바이트 코드는 프로그램의 흐름을 구성하는 바이트 코드로 볼 수 있음
- Runtime Contatnt Pool이라는 별도의 관리 영역이 함께 존재하는데, 여기에 상수 자료형을 저장하여 참조와 중복을 막는 역할을 수행
힙(Heap)
- 객체를 저장하는 가상 메모리 공간
- 프로그램 시작 후 데이터가 들어오고 나가는 구역 (어느순간 들어오고, 어느순간 나가는 데이터들)
📂 3) 실행엔진(Execution Engine)
클래스를 실행시키는 역할을 한다. 클래스 로더가 JVM내의 메모리(Runtime Data Area)에 바이트 코드를 배치시키고, 이것은 실행엔진에 의해 실행된다.
인터프리터(Interpreter)
- 자바 바이트 코드를 명령어 단위(한줄씩)로 읽어서 네이티브 코드로 변환
- 단, 한줄씩 수행해서 느리다는 단점이 있음
JIT(Just In Time)
- 인터프리터의 단점을 보완하기 위해 도입
- 인터프리터 방식으로 실행하다가 적절한 시점에 바이트 코드 전체를 컴파일하여 네이티브 코드로 변환
- 네이티브 코드는 캐시에 보관하기 때문에 한 번 컴파일된 코드는 빠르게 수행
GC(Grabage Collector)
- 더 이상 참조되지 않는 객체를 모아서 메모리 정리
📖 참고