📂 목차
📚 본문
Java = 강형 언어이며, 변수에 항상 데이터의 형태가 뭔지 알려줘야 변수 선언이 가능한
타입에 엄격한 언어라는 말이다.
Java 변수
변수는 데이터를 쓸 수 있는 영역을 마련해주는 공간, 쓸 변수마다 그 공간이 달라진다.
변수를 선언할 때 대입연산자(=)
과 literal
을 통해 변수에 값을 할당해줄 수 있다.
literal: 데이터 그 자체, 실제 값
// 10 은 리터럴 특히 정수형 리터럴이라고 함
int a = 10;
정수 리터럴
- 10진수: int x = 10
- 8진수: int y = 010
- 16진수: int z = 0xA
- 2진수: int b = 0b1010
10진수 리터럴은 _를 사용하여 숫자를 쉽게 보게 할 수 있다.
기타 리터럴
- long 리터럴: int a = 10000000000000L
- 실수 리터럴
- 3.193
- 10f
- 3.29F
- 3d - d 혹은 D 생략 가능
- 1.2e3 - 지수 표기법
- 논리 리터럴: true, false
- null 리터럴: null
- 문자 리터럴:
- ‘A’
- ‘\n’ - 이스케이프 문자(\t, ", ', \, \r 등등)
- ‘\u0041’
- “String”
char 은 한 문자를 의미, 여기는 숫자(유니코드 내의 숫자) 와 홑따옴표로 한 개의 문자가 들어가도록 리터럴을 넣어줄 수 있음
Java 변수 유형
자바 변수는 선언하는, 내용의 특징에 따라 혹은 선언하는 위치에 따라 수식어가 붙는다.
데이터 타입에 따른 분류
- 기본형(Primitive): 실제 값 자체를 저장하며 byte, short, int, long, float, double, char, boolean 8가지가 있다.
- Stack 이라는 메모리 영역에 저장
- 참조형(Reference): 그 이외에
- Heap 이라는 영역에 저장
범위에 따른 분류
클래스 범위와 함수 범위와 변수 할당의 차이
public class Exam {
int intValue;
public static void main(String[] args) {
// 초기화하지 않으면 사용이 불가함
// 직접 리터럴을 대입해줘야 함
int intValue_;
}
}
intValue
: 클래스 변수, 필드 변수, 멤버 변수라고 하며 기본적으로 값이 초기화(0으로)된다.intValue_
: 지역 변수라고 하며 메서드 내에서 자동으로 초기화가 되지 않고, 초기화를 해줘야 한다.
이를 더 자세히 보자.
Local Variable
메서드/생성자/블록 안에서 선언하는 변수이다.
Field
클래스 범위(스코프) 내에서 선언한 변수이다. 보통 클래스 범위의 맨 위에 선언한다.
- Instance Variable: 객체가 생성될 때 함께 생성되며, 값이 자동 초기화되는 특징이 있다.
- Static Variable:
static
키워드로 선언하며, 클래스 로딩시 딱 한 번만 메모리에 올라가고, 모든 객체가 공유를 한다.
Parameter
메서드 호출 시 전달되는 값이며, 일종의 지역변수이지만 특별히 구분해서 부르게 된다.
파라미터에서 선언된 변수명을 로컬 변수로 다시 선언할 수 없다.
final 키워드
재할당, 재정의 금지라는 뜻 이 이후에는 변수를 바꿀 수 없음
final double PI = 3.141592d
final의 primitive 는 대문자로 쓰는게 관례(Convention)이다. final의 String 도 마찬가지
Java 변수 할당 방식
위 변수들은 전부 JVM이 메모리에 할당하여 사용할 수 있게 된다.
Java 프로그램이 실행되면 JVM은 크게 Heap
, Stack
, Method Area(=Metaspace)
세 부분을 사용하며, 각 영역마다 다음 특징이 있다.
메모리 영역
- Heap:
new
키워드로 생성된instance
들이 저장- ⭐️ 모든 스레드가 공유하는 메모리 영역
- ⭐️ GC 의 대상이 된다.
- Stack: 메서드 호출 시마다
Stack Frame
이 생성된다.- 지역 변수가 저장되며, 메서드가 끝나면 해당
Stack Frame
삭제
- 지역 변수가 저장되며, 메서드가 끝나면 해당
- Method Area(Metaspace)
- 클래스 정보, static 변수, 상수 풀(Constant Pool) 저장
- JVM 시작 시 로딩되는 영역이다(static 으로 선언된 변수가 포함됨)
Constant Pool
- 클래스 상수 풀(Class Constant Pool): 클래스 메타데이터, 상수 값, 필드, 메서드, 참조 등을 저장
- 문자열 상수 풀(String Constant Pool): 문자열 리터럴을 효율적으로 관리하기 위해 사용하는 특수 저장공간이며, 문자열 리터럴이 생성될 때마다 JVM 은 해당 문자열이 문자열 상수 풀에 존재하는지 확인하고, 존재하지 않으면 추가하여 메모리를 최적화 함
Java 형 변환
연산자들은 생략하고, 얻어갈 수 있는 형 변환에 대한 것들을 적는다.
Implicit Type Casting
자동 형변환은 작은 타입에서 큰 타입으로 변환이 필요할 때 컴파일러가 자동으로 해주는 것을 의미한다.
- 작은 타입 → 큰 타입 가능
- 정수형 → 실수형 가능
하지만 이때 long → float 의 경우에는 변환 시에 값 손실을 감안하고 형변환을 진행한다(소수점으로 표현하고 지수자리로 표현됨에 따라 2진법을 사용하는 컴퓨터는 손실이 됨).
Explicit Type Casting
큰 타입 → 작은 타입 으로 변환할 때 사용하며, 손실을 감안하고 변환한다.
long l1 = 12345678910L;
int i1 = (int) l1;
System.out.println(i1);
// 출력: -539222978
Arithmetic Promotion
숫자들을 다룰 때, byte, short, char 등으로 표현했다고 치자. 그러고 두 수를 더하고 싶을 때 일반적으로 덧셈 연산을 통해 수행을 한다. 하지만 여기서 short + short 는 short 로 나와버리면 short 로는 표현할 수 없는 값이 생기고, 이는 음수로 바뀔 것이다.
이를 방지하고 값의 신뢰성을 높이기 위해 덧셈이나 곱셈 등과 같이 크기가 늘어나는 연산에 대해 산술 승격이 자동으로 이루어지게 된다.
- byte, short, char는 연산 시 자동으로 int로 승격 → int
- 연산 중 더 큰 타입과 만나면 큰 타입으로 승격
Java 공식 문서 파헤치기
자주 사용되는 클래스들은 전부 java.lang
에 포함되어 있으며,
import
를 쓰지 않아도 java.lang
의 모듈에 있는 기능들은
전부 컴파일러가 알아서 추가해준다.
자동 추가 클래스 목록
- String
- Math
- Number
- Object
- System
- …
여기서 주의할 점은
java.lang
에 있는 클래스들만이지,java.lang.reflect
와 같은 패키지는 자동 import 가 되지 않는다.
더 많은 내용은 공식 문서를 참고하자.
Number
Number 추상 클래스는 byte, double, float, int, long 타입의 수퍼 클래스이다.
주로 숫자 데이터를 다룰 수 있게하고, 정의한다.
메서드
- (primitive)Value(): Number 를 통해 위 primitive 타입 들로 변환할 수 있다.
String
String 은 immutable 타입이고, reference 형태인 특이한 데이터타입이다.
즉, 한 번 생성되면 변하지 않고 변하지 않으면 안전하게 공유를 할 수 있다는 뜻이 된다(이전의 String Constant Pool
참고).
Field
static Comparator<String> CASE_INSENSITIVE_ORDER
: 문자열을 정렬할 때에 대소문자를 구분하지 않고 정렬을 하고 싶을때 사용한다.
보통
Collections.sort
,List.sort
등에 넘겨서 많이 쓰이며, 정렬을 하는 행위에서 두 값을 비교할 때 어떤 정책을 따라, 어떤 규칙을 따라 비교할지에Comparator
를 넣어준다.
함수들은 너무 많기에 코드 문제를 풀면서 익히는 것이 좋을 듯하다.
System
멤버 변수
err
: 표준 에러 출력 스트림in
: 표준 입력 스트림out
: 표준 출력 스트림
여기서 스트림이란 데이터를 문자나 바이트 형태로 전달하는 통로를 의미하며,
- 출력스트림: 데이터를 바이트 단위로 외부로 내보낼 수 있는 스트림
- 입력스트림: 데이터를 바이트 단위로 읽어오는 최상위 추상 클래스
Runtime
JVM 환경을 나타내는 클래스이며 운영체제와 JVM 사이의 직접적인 시스템 작업을 수행할 수 있게 해주는 클래스이다.
가장 핵심 클래스이며, Singleton
패턴으로 다른 클래스들에게 제공된다. 기본적으로 Runtime.getRuntime()
으로 접근하면 된다.
주요 메서드
exec(String command)
: 지정된 환경과 작업 디렉토리에서 별도의 프로세스로 지정된 문자열 명령을 실행(ex. notepad, ls 등등)
Deprecated 되어서 이젠 쓰이지 않고ProcessBuilder
를 통해 Process 를 만들어 사용하게 된다.gc()
: 가비지 컬렉션 요청totalMemory()
/freeMemory()
:JVM
이 가용한 메모리 상태 확인exit(int status)
: JVM status code 의 상태로 종료addShutdownHook(Thread hook)
: JVM 종료 시 실행할 코드 등록(이런걸 훅이라고 한다)
훅: 특정 이벤트나 시점에서 사용자가 원하는 코드를 끼워 넣을 수 있는 지점
Process
위 Runtime
으로 exec
을 할 수 있지만, 이는 들어갈 수 있는 인자의 제어를 효과적으로 못하여 Process
라는 실행 가능한 클래스를 통해 실행하게 된다.
ProcessBuilder pb = new ProcessBuilder("echo", "Hello");
Process process = pb.start(); // 프로세스 실행
위 코드 처럼 ProcessBuilder
는 네이티브 프로세스(운영체제의 개념)를 Builder
패턴으로 어떤 프로세스를 만들지 정의를 해주고 프로세스를 만들 수 있다(재사용성 증가).
이를 Runtime
에게 주어서 exec()
으로 실행하게 된다.
주요 메서드
InputStream getInputStream()
: 프로세스가 표준 출력에 쓴 데이터 읽기InputStream getErrorStream()
: 프로세스가 표준 에러에 쓴 데이터 읽기OutputStream getOutputStream()
: 프로세스가 표준 입력에 쓰기void destroy()
: 하위 프로세스 종료getRuntime()
: 현재 Java Application 과 연결된 런타임 객체 반환- …
Object
모든 클래스가 상속받는 최상위 클래스이다.
보통 오버라이드하여 객체 동작을 커스터마이징한다.
메서드
toString()
: 객체를 문자로 표현하는 법 정의equals(Object obj)
: 객체 비교 방법 정의hashCode()
: 객체 해시코드 반환getClass()
: 객체의Runtime
클래스 정보 반환clone()
: 객체 복제 방법 정의(깊은/얕은 복사 가능)finalize()
: GC가 객체를 수거하기 전에 호출wait()
,notify()
,notifyAll()
: 스레드 동기화에 사용
Object
에 스레드 관련 메서드가 있는 이유는,
자바에서 모든 객체를 Monitor
로 사용할 수 있기 때문이다.
synchronized
키워드를 사용하면 객체 단위로 Monitor Lock이 걸리며,
synchronized
는 이 추상적 클래스 모니터의 구현체인 동기화 Monitor
를 기준으로 이루어진다.
모니터란 한 번에 하나의 Thread만이
모니터 내의 임계 구역(critical section)에 들어올 수 있도록 보장하는 장치이다.
따라서 공유 자원에 대한 접근은 반드시 Monitor Lock을 획득한 스레드만 가능하다.
즉, 객체가 모니터 락을 얻어서 동기화된 코드 블록(또는 메서드)을 실행할 수 있게 되는 것이
synchronized (모니터 락을 획득할 대상)
구문이다.
보통 this
자체가 모니터 락 대상이 되는 경우가 많지만,
별도의 Object
멤버 변수를 선언해서 락으로 쓰기도 한다.
또는 메서드에 synchronized
를 직접 선언할 수도 있다.
class Counter {
private static int count = 0;
public static synchronized void increment() {
count++;
// 이 시점에 Counter.class 모니터 락을 보유 중이므로
// wait() / notify() 호출 가능
}
}
이는 운영체제에서 더 다루겠다. 또한 더 많은 기능들과 기본적인 자바 문법들은 전부 타 블로그에 정보가 매우 많기에 생략한다.
Wrapper Variables
자바의 기본형 타입을 객체로 다룰 수 있게 해주는 클래스이며 reference 타입으로 감싸는 역할을 한다.
Integer, Short, Byte, Boolean, Float, Double …
다음 이점을 위해 사용한다:
- 객체만 다룰 수 있는 API 사용
Collection
은 기본형을 직접 담을 수 없기 때문에 다양한 유틸 기능을 가지는Collection
을 사용하기 위해 형변환을 수행한다.
- 편리한 형 변환 유틸 기능을
public static
함수로 제공- Integer.parseInt(), Double.toString 등 편리한 기능 제공
- nullable
- 아무 값도 존재하지 않는 그런 값을 표현할 수 있다.
Auto Boxing
Java 5 이후에 오토 박싱이라는 것으로 primitive
변수를 Integer
선언한 변수에 담을 때 자동으로 컴파일러가 형변환을 시행하여 들어가게 되는게 Auto Boxing
이다.
int n = 10;
// Boxing
Integer obj1 = Integer.valueOf(n);
// Unboxing
int m = obj1.intValue();
// 오토 박싱 & 언박싱
Integer obj2 = n; // int → Integer (자동 박싱)
int k = obj2; // Integer → int (자동 언박싱)