[JAVA] 자바 기본 자바라.

하이초·2023년 11월 28일

JAVA

목록 보기
1/7
post-thumbnail

기술 면접 대비겸 CS 지식 향상을 위해 정리하는 포스트.

1️⃣ 자바의 장점 및 단점

👍 장점

1. 운영체제에 독립적

자바는 JVM 위에서 동작하여 특정 운영체제에 종속되지 않는다. JVM에 대해서는 별도의 포스트로 정리할 예정.

2. 객체지향 언어

3. 편리한 메모리 관리

GC가 대표적, 이도 따로 정리할 예정.

자바를 처음 공부하는 스터디에서 들었던 말이 생각난다. 자바는 개발자를 믿지 않아. 처음 42서울에서 C로 개발 공부를 시작하고, 자바를 공부할수록 그 말의 의미를 점점 더 깨달아가는 것 같다. 편리하지만 그만큼 추상화된 것들로 인해 어떻게 해야하지? 싶을 때도 있는 것 같다.

4. 오픈소스

5. 동적 로딩 지원

6. 멀티쓰레드 구현이 쉽다

👎 단점

1. 속도가 상대적으로 느림

2. 메모리 소비

JVM, GC가 편의성을 가져다 준 만큼 그로 인한 속도 저하가 발생하기도 한다.

2️⃣ 객체 지향 언어

앞서 자바의 장점으로 객체 지향 언어를 꼽았는데, 그렇다면 과연 객체 지향 언어는 무엇인가? 내가 생각한 객체 지향이란 결국 하나의 고유한 특성을 가진 객체를 여러개 만들고 이 각 객체들이 서로 상호작용을 하도록 만든 것이라고 생각한다.

C의 경우 절차 지향 언어로 코드가 위에서부터 아래로 흐르게 된다. 따라서 코드의 순서가 중요하고, 프로그램이 커질 수록 유지보수가 어려워진다. 이에 반해 JAVA와 같은 객체 지향 언어는 누가 무엇을 할 것인가?를 중점으로 코딩을 하게 되고, 이에 따라 유지보수가 쉬워진다.

각 객체마다 고유의 멤버 변수, 멤버 함수들을 가질 수 있고 이를 통해 해당 객체가 할 역할을 한정해 줄 수 있게 된다. 그러다보니 어떤 객체의 행동이 변해야 할 때 해당 객체 내부만 수정하면 되고, 외부에는 영향을 미치지 않는다. 그래서 유지보수가 쉬워지는 것이다. c는 하나가 잘못 됐을 때 아 나 이거 어디까지 고쳐야 하지..? 하는 때가 더러있었는데, JAVA의 경우 그 대상을 찾기도, 한정짓기도 쉬워진다. 그러나 이를 위해서는 설계를 잘 해야한다!! 또한, 기계어에 조금 더 가까운 c가 처리 속도나, 실행 속도면에서 빠를 수밖에는 없다.

💫 객체 지향 프로그래밍의 주요 특징 4가지

1. 캡슐화

정보의 은닉이다. 각 객체의 멤버 변수와 메소드 등 실제 구현 내용을 외부로부터 감추는 것이다. 객체의 외부에서는 공개된 메소드를 통해서만 접근할 수 있다. 멤버 변수는 private으로 지정하고 외부에서는 getter, setter 등으로 접근하는 것이 예이다. 클래스화 하는 것과 동일.

2. 상속성

상위 객체의 속성을 하위 클래스에 물려줄 수 있다. 이를 통해 코드의 중복을 줄일 수 있다.

3. 다형성

상위 클래스의 메소드를 재정의하는 오버라이딩, 같은 메소드이나 다른 매개 변수를 통해 다르게 동작하도록 하는 오버로딩과 같은 구현이 가능하다.

4. 추상화

실제 존재하는 대상에서 특징들을 뽑아내 프로그램으로 만드는 것이다.

📌 객체지향 설계 SOLID 5원칙

[S]ingle responsibility principle - 단일 책임 원칙

한 클래스는 하나의 책임만 가지며, 클래스는 그 책임을 완전히 캡슐화 해야 함

[O]pen/closed principle - 개방/폐쇄 원칙

클래스, 함수 등은 확장에 대해 열려 있어야 하고, 변경에 대해서는 닫혀있어야 함
기존 코드를 수정하지 않고 기능을 수정하거나 추가할 수 있어야 하는 것
내가 변화하는 게 다른 객체에게 영향을 주는가? -> 결합도가 높다고 할 수 있음
변화되는 부분과 닫히는 부분이 분리가 되어야 한다

[L]iskov subtitution principle - 리스코프 치환 원칙

프로그램의 정확성을 깨트리지 않으면서 하위 타입의 객체로 바꿀 수 있어야 함
자식 객체를 부모 객체로 변경해도 정삭 작동해야 하는 것
자바 컬렉션 프레임워크가 좋은 예

[I]nterface segregation principle - 인터페이스 분리 원칙

큰 덩어리의 인터페이스를 구체적이고 작은 단위로 분리함으로써 클라이언트가 꼭 필요한 메서드만 이용할 수 있게 함
하나의 general한 인터페이스보다 여러개의 special한 인터페이스가 낫다는 것

[D]ependency inversion principle - 의존 관계 역전 원칙

변화하기 쉬운 것 또는 자주 변화하는 것 보다는 변화하기 어려운 것, 거의 변화가 없는 것에 의존하도록 함
각 클래스간의 결합도를 낮추고, 구현 클래스에 의존하기보다 인터페이스에 의존하라는 것
구체 클래스 = 인스턴스화 할 수 있는 클래스(=new 할 수 있는 클래스)
<-> 인터페이스 & 추상클래스

3️⃣ 자바의 메모리 영역

Static (Method) 영역

  • JVM이 실행될 때 생성됨
  • 클래스 변수, static으로 선언된 것들이 저장된다
  • Static 영역에 있는 것은 어디서든 접근이 가능함
  • JVM 종료(프로그램 종료 시) 메모리에서 해제 됨
    - 프로그램 종료 전까지 메모리에 존재하게 되기 때문에 메모리 부족 현상이 발생하지 않도록 분별있는 사용이 중요하다
  • Runtime Constant Pool

Heap 영역

  • 객체 생성 시 저장되는 영역 cf)new
  • 참조형 데이터 객체의 실제 데이터가 저장되는 공간
    - Stack 영역에는 이 참조형 데이터의 주소가 저장된다
  • 호출 종료 시 즉시 메모리에서 해제되지 않으며 GC에 의해 수거된다
  • Stack과 달리 thread 별로 별도 관리되지 않으며 공통으로 하나의 영역만 존재함

Stack 영역

  • 원시 자료형, 지역 변수, 매개 변수가 저장 된다
  • 메서드 내부의 기본 자료형에 해당하는 변수 저장
  • Heap 영역에 생성된 데이터의 참조값 저장
  • Stack 구조로 LIFO
  • 각 thread 별로 자신만의 stack 영역을 가진다
  • 잠시 사용하고 말 임시 값들

Runtime Data Area

  • 메서드 영역
  • 힙 영역
  • 스택 영역
  • PC 레지스터(현재 스레드가 수행중인 JVM 명령의 주소값)
  • 네이티브 메서드 스택(JAVA의 바이트 코드가 아닌 다른 언어로 작성된 메서드를 담아두는 공감)

힙, 메서드 영역은 전부 공유, Pc register&Stack&Native Method stack 영역은 각 쓰레드마다 생성

4️⃣ 자바 컴파일 과정

향후 JVM 포스트에서 말하는 것이 맞나 싶지만, 일단은!

  1. 개발자가 .java 소스 코드 작성
  2. 자바 컴파일러(javac)가 .java를 읽고 .class 바이트코드로 컴파일
  3. 컴파일 된 .class 바이트코드를 JVM의 클래스 로더에게 전달
  4. 클래스 로더는 동적 로딩을 통해 필요한 클래스들을 로딩 및 링크하여 런타임 데이터 영역(Runtime Data Area의 Method Area), 즉 JVM의 메모리에 올림
    💡 클래스 로더 세부 동작
    1. 로드: 클래스 파일 가져와서 JVM의 메모리에 로드
    2. 검증: 자바 언어 명세 및 JVM 명세에 명시된 대로 구성되어있는지 검사
    3. 준비: 클래스가 필요로 하는 메모리를 할당
    4. 분석: 클래스 상수 풀 내 모든 심볼릭 레퍼런스 다이렉트 레퍼런스로 변경
    5. 초기화: 클래스 변수들을 적절한 값으로 초기화
  5. 실행 엔진은 JVM 메모리에 올라온 바이트 코드들을 명령어 단위로 하나씩 가져와서 실행. 이때 실행 엔진은 두 가지 방식으로 변경
    1. 인터프리터: 바이트 코드 명령어를 하나씩 읽어 해석하고 실행, 하나하나의 실행은 빠르나 실행 속도가 느린 단점을 가짐.
    2. JIT 컴파일러: 인터프리터의 단점을 보완하기 위해 도입된 방식으로 바이트 코드 전체를 컴파일하여 바이너리 코드로 변경, 이후에는 해당 메서드를 더이상 인터프리팅 하지 않고 바이너리 코드로 직접 실행. 하나씩 인터프리팅 하여 실행하는 것이 아니라 바이트 코드 전체가 컴파일된 바이너리 코드를 실행하는 것이기 때문에 전체적인 실행속도는 인터프리팅 방식보다 빠름.

C, C++의 코드는 컴파일 시 바로 CPU에서 실행이 가능한 코드인 기계어로 변환되어 속도가 빠르지만, JAVA의 경우 byte code로 컴파일 후 그 byte code를 기계어로 변환하는 시간이 필요하여 수행 속도가 더 오래 걸린다

5️⃣ Call by Value vs Call by Reference

자바는 call by value라고 한다. 처음 call by reference 할 때 이거 c++ 참조자 말하는 거 맞나..? 싶었는데 찾아보니 맞는 것 같다. c++ 공부 당시에 c도 포인터로 나를 힘들게 하더니 이젠 참조자야 싶었던 기억이 난다. 그러니까, 당연히 포인터도 없는 java에서 참조자가 있을리 없기는 하다. 자바가 개발자가 맘대로 원본 값을 수정하게 뒀을리가 없음.. 처음 참조자에 대해 배웠을 때 매개변수로 넘기면서 복사 생성하지 않으니 메모리를 효율적으로 관리하기에 너무 좋겠다는 생각이 들었었다. 포인터 변수와 같이 변수를 위한 메모리 자체도 할당하지 않을 수 있다니! 그런데 다시 생각하면 위험도가 너무 높다. 원본값이 변경 될 수 있다는 것은 어딘가에서 치명적일 수 있게 마련일테니.

profile
개발국대가 되는 그 날까지. 지금은 개발 응애.

0개의 댓글