0. 글을 작성하는 이유
Java의 기본기를 탄탄히하고 객체지향적인 프로그래밍 사고를 하기 위해서 학습한 내용 나만의 비법소스로 사용하기 위해서 정리합니다 :)
1. JAVA 기본
1) 변수
- 자료를 저장하기 위한 메모리 공간(그릇)으로 타입에 따라 크기가 달라집니다.
- 메모리 공간에 값(value)을 할당(assign) 후 사용합니다.
2) 타입
- 데이터의 종류로 기본형(Primitive type)과 참조형(Reference type) 두가지 타입이 존재합니다.
- 기본형: 미리 정해진 크기의 메모리 사이즈로 표현하며, 변수 자체에 값을 저장합니다.
- 8개 기본형
- boolean
- byte
- short
- int(-2^31 ~ 2^31-1 = 약 20억)
- long
- float
- double
- char
- 참조형: 크기가 미리 정해질 수 없는 데이터의 표현이며, 변수에는 실제 값을 참조할 수 있는 주소만 저장합니다.
- 주의사항:
정수형 계산은 오버플로우를 주의해야합니다.
실수형 계산은 부동소수점을 주의해야합니다.
3) 형 변환
- 변수의 타입을 다른 타입으로 변환하는 것입니다.
- 기본형은 기본형끼리, 참조형은 참조형끼리 형 변환이 가능합니다.
- 묵시적 형변환(작은 집 -> 큰 집):
자료의 손실 걱정이 없으므로 JVM이 서비스 해줍니다.
- 명시적 형변환(큰 집 -> 작은 집):
값 손실이 발생할 수 있으므로 프로그래머 책임하에 형변환이 진행됩니다.
byte b1 = 10;
byte b2 = 20;
byte b3 = b1 + b2;
int i1 = 10;
long l1 = 20;
int i2 = i1 + l1;
4) 연산자
- 어떤 기능을 수행하는 기호(+, -, *, /, ...)입니다.
- 연산자는 우선순위가 존재합니다.
- 산술 이항 연산자는 연산 전에 피 연산자의 타입을 일치시킵니다.
- 피연산자의 크기가 4byte(int) 미만이면 int로 변경한 후 연산을 진행합니다.
- 두 개의 피연산자 중 큰 타입으로 형 변환 후 연산을 진행합니다.
- 쇼트 서킷:
논리 연산자 AND, OR 을 나타내기 위해 부호 &&, || 을 사용하는 것을 의미합니다.
&, | 는 연산자의 앞 조건식과 뒤 조건식을 둘 다 실행 시킵니다.
&&, || 는 연산자의 앞 조건식의 결과에 따라 뒤 조건식의 실행 여부를 결정합니다. (쇼트 서킷)
5) 조건문
6) 반복문
- for 문:
초기값, 조건식, 증감식의 위치가 명확할 때 사용합니다.
반복의 횟수가 명확할 때 사용합니다.
index의 증감을 활용할 때 사용합니다.
- while 문:
반복의 횟수가 불명확한 경우 사용합니다.
index보다는 break, continue를 활용합니다.
7) 배열
- 동일한 타입의 데이터 0개 이상을 하나의 연속된 메모리 공간에서 관리하는 것입니다.
- 요소에 접근하는 속도가 매우 빠릅니다.
- 한 번 생성하면 크기 변경이 불가능합니다.
- 배열의 생성과 동시에 저장 대상 자료형에 대한 기본값으로 default 초기화가 진행됩니다.
- 배열은 index 번호를 가지고 각 요소에 접근이 가능합니다. (index 번호는 0부터 시작합니다.)
- 배열의 길이는 배열이름.length 로 배열의 크기 조회가 가능합니다.
- for-each with Array:
가독성이 개선된 반복문으로, 배열 및 Collections 에서 사용합니다.
index 대신 직접 요소(element)에 접근하는 변수를 제공합니다.
- Array is Immutable:
배열은 최소 메모리 할당 이후, 변경할 수 없습니다. (= 메모리에 올라간 배열 자료구조를 바꿀 수 없다는 말입니다.)
개별 요소는 다른 값으로 변경이 가능하지만, 요소를 추가하거나 삭제할 수는 없습니다.
- 배열 복사 API:
System.arrayCopy(Object src, int srcPos, Object dest, int destPos, int length);
Arrays.copyOf(int[] original, int newLength);
8) 메서드
- 현실의 객체가 하는 동작을 프로그래밍화 한 것 입니다.
- 어떤 작업을 수행하는 명령문의 집합입니다.
- 메서드를 작성하는 이유:
반복적으로 사용되는 코드의 중복을 방지합니다.
코드의 양을 줄일 수 있고 유지 보수가 용이합니다.
- 리턴타입:
아무것도 리턴하지 않는 경우는 void입니다.
결과를 받을 때 묵시적 형 변환이 적용됩니다.
리턴 타입은 하나만 적용이 가능합니다.
- 메서드이름은 작업을 쉽게 파악하도록 의미 있는 이름을 사용하길 권장합니다.
- Variable arguments:
메서드 선언 시 몇 개의 인자가 들어올 지 예상할 수 없을 경우 (또는 가변적) 일 때 사용합니다.
... 을 이용해 파라미터를 선언하면 호출 시 넘겨준 값의 개수에 따라 자동으로 배열 생성 및 초기화를 해줍니다.
대표적으로 적용된 메서드는 printf() 메서드 입니다.
public PrintStream printf(String format, Object ... args) {
return format(format, args);
}
- static member는 언제나 메모리에 있습니다. (클래스 로딩 시 자동 등록됩니다.)
- instance member는 객체 생성 전에는 메모리에 없습니다. (객체 생성 시 모든 일반 멤버들은 메모리에 생성되고, 객체를 통해서 접근합니다.)
2. 객체지향 프로그래밍(Object Oriented Programming)
1). 객체 (사전적 의미)
- 주체가 아닌 것, 주체가 활용하는 것 입니다.
2). 객체지향 프로그래밍
- 주변의 많은 것들을 객체화 해서 프로그래밍하는 것 입니다.
3). 객체지향 프로그래밍 장점
- 블록(객체) 형태의 모듈화된 프로그래밍이 가능합니다.
- 신뢰성 높은 프로그래밍이 가능합니다.
- 추가 / 수정 / 삭제가 용이합니다.
- 재 사용성이 높습니다.
4). 현실 세계와 프로그램의 객체의 관계
- 현실의 객체가 갖는 속성과 기능은 추상화(Abstraction) 되어 클래스에 정의됩니다.
- 클래스는 구체화 되어 프로그램의 객체(Instance, Object)가 됩니다.
- 객체는 상태, 속성(변수, 필드)과 기능, 행위(메서드, 함수)를 갖습니다.
5). 클래스
- 객체를 정의해 놓은 것입니다. 즉, 객체의 설계도(틀)입니다.
- 클래스는 직접 사용할 수 없고 직접 사용되는 객체를 만들기 위한 틀을 제공합니다.
6). 객체 (프로그래밍적 의미)
- 클래스를 데이터 타입으로 메모리에 생성된 것 입니다.
3. JVM의 메모리 구조
- class area(= method area)
- 클래스 원형을 로딩합니다.
- 메서드의 바이트코드, static 변수(class 변수)를 저장합니다.
- Field 정보
- Method 정보
- 타입 정보
- 상수 풀
- method stack(= java stack)
- 메서드들의 실행 공간입니다.
- thread 별로 별도 관리됩니다.
- 메서드 호출 순서대로 쌓이는 구조입니다.
- 메서드 프레임에 로컬 변수도 쌓이는 구조 입니다.
- 로컬 변수는 선언된 영역을 벗어나면 삭제됩니다.
- 작은 데이터, 지역변수, 매개변수를 저장합니다.
- heap
- 객체를 저장하기 위한 영역입니다.
- thread에 의해 공유됩니다.
- 생성된 객체는 프로그래머가 삭제할 수 없고 GC(Garbage Collector)만이 제어가 가능합니다.
- 큰 데이터, 객체(인스턴스), 배열을 저장합니다.
4. 결론
Java는 객체지향 프로그래밍의 대표적인 언어입니다.
절차지향 객체지향 둘은 서로의 장단점이 있기 때문에, 누가 더 좋다 나쁘다로 판단하면 안됩니다.
Java를 잘 사용하기 위해서는 JVM 메모리 구조를 알고 사용하는 것이 도움이 됩니다.