목표
- 자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을 익힙니다
학습할 것
- 프리미티브 타입 종류와 값의 범위 그리고 기본 값
- 프리미티브 타입과 레퍼런스 타입
- 리터럴
- 변수 선언 및 초기화하는 방법
- 변수의 스코프와 라이프타임
- 타입 변환, 캐스팅 그리고 타입 프로모션
- 1차 및 2차 배열 선언하기
- 타입 추론, var
프리미티브 타입 종류와 값의 범위 그리고 기본 값
- primitive type은 자바의 기본 타입들이며 8개가 존재함
- 프리미티브 타입은 필드 선언 시 초기화하지 않으면 기본 값으로 초기화됨
종류 |
타입 |
메모리 byte |
범위 |
기본 값 |
논리형 |
boolean |
1byte |
true or false |
false |
정수형 |
byte |
1byte |
-128 to 127 |
0 |
|
char |
2byte |
'\u0000'(0) to '\uffff'(65535) |
'\u0000' |
|
short |
2byte |
-32,768 to 32,767 |
0 |
|
int(기본) |
4byte |
-2^31 to 2^31-1 |
0 |
|
long |
8byte |
-2^63 to 2^63-1 |
0L |
실수형 |
float |
4byte |
(6~7자리 정밀도) |
0.0f |
|
double(기본) |
8byte |
(15자리 정밀도) |
0.0d |
Java8 부터 unsigned int, unsigned long이 추가됨
int unsigned = Integer.parseUnsignedInt("2200000000");
System.out.println(Integer.toUnsignedString(unsigned));
BigInteger bigInteger = BigInteger.valueof(2200000000L);
- Java는 유니코드를 지원함 -> 한자 등의 모든 언어 입력 가능
프리미티브 타입과 레퍼런스 타입
Java Data Type
ㄴ Primitive Type
ㄴ Boolean Type(boolean)
ㄴ Numeric Type
ㄴ Integral Type
ㄴ Integer Type(short, int, long)
ㄴ Floating Point Type(float, double)
ㄴ Character Type(char)
ㄴ Reference Type
ㄴ Annotation
ㄴ Array
ㄴ String
ㄴ Class
ㄴ Enumeration
ㄴ Interface
primitive type |
reference type |
boolean, char, byte, short, int등 이미 정해진 유형 |
사용자가 무제한적으로 유형을 선언 |
값 저장 |
주소 저장 |
call by value |
call by reference |
메모리에 저장되는 값이 실제값 |
저장되는 값은 메모리의 주소 |
동일한 유형의 다른 변수에 값이 복사됨 |
다른 참조 유형에 할당되면 동일한 객체를 가르킴 |
메모리에서 변수의 값을 복사해서 사용하기 때문에 변수의 값을 바꾸더라도 메모리에 있는 값이 바뀌지 않음 |
메모리 주소를 복사해서 사용하므로 가져온 변수의 값을 바꾼다면 메모리 주소를 참조하여 사용했기 때문에 값이 바뀜 |
null 할당 불가 |
null 할당 가능 |
Stack에 저장 |
Heap 메모리 영역에 값을 저장하고 Stack에 Heap의 주소값을 저장함 |
|
new 키워드를 통해 생성된 객체의 주소를 참조함(배열, class, 열거형(enum), interface 등 |
리터럴
int num = 15; // 15가 리터럴임
정수형 리터럴 표현 방식
int num = 11; //10진수 int형
int num = 011; //8진수 int형
int num = 0x11; //16진수 int형
long num = 11L; //long 형
int num = 0B11001101; //2진수 int형
int num = 1_000_000; // 큰 수의 표현은 가독성을 위해 _로 구분 가능
실수형 리터럴 표현 방식
double num = 3.1415 or 3.1415d or 3.1415D; //double형
float num = 3.14f or 3.14F; //float형
//추가 표현
3.4e3 == 3.4 X 10^3
3.4e-3 == 3.4 X 10^-3
0.5 == .5
실수형 리터럴 추가 사항
float number = 0f;
for(int i = 0; i < 10; i++) {
number += 0.1f;
}
System.out.println(number); // 1.0000001
// 부동소수점은 정확하지 않다
// 돈계산하는 애플리케이션을 만들 때 절대 float, double을 사용하면 안되고 BigDecimal, BigInteger를 사용해야함
BigDecimal number = BigDecimal.ZERO;
for(int i = 0; i < 10; i++) {
number = number.add(BigDecimal.valueOf(0.1)); // 멀티쓰레드 상황을 고려해야함
}
System.out.println(number); // 1.0
부울형 상수
boolean trueOrFalse = true or false; // boolean형, 오직 true와 false값만 가짐
문자형 상수
char ch = '한'; // char형
char ch = 'A'; // 작은 따옴표로 구분
char ch = '\u20AC'; // 유니코드 입력 가능
char ch = '\b'; // 백스페이스 문자
char ch = '\t'; // 탭 문자
char ch = '\'; // 백 슬래시 문자
char ch = '\''; // 작은 따옴표 문자
char ch = '\"'; // 큰 따옴표 문자
char ch = '\n'; // 개행 문자
char ch = '\r'; // 캐리지 리턴 문자
String 리터럴
String str = "string"; // String형, 큰 따옴표로 표현
String 초기화 방법
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1 == str2); // false
System.out.println(str1.equals(str2)); // true
- new를 사용
- str1과 str2는 힙 영역에 각각의 다른 객체로 만들어짐
- 서로 다른 메모리 주소를 가지고 있기 때문에 같지 않음(동일성)
- 하지만 서로의 값은 같음(동등성)
String str1 = "abc";
String str2 = "abc";
System.out.println(str1 == str2); // true
- 리터럴로 초기화
- 리터럴 "abc"가 상수풀 영역에 등록됨
- str1과 str2는 상수풀에 있는 같은 "abc"를 참조함 -> str1과 str2는 같은 메모리 주소를 가짐
변수 선언 및 초기화하는 방법
변수 선언
int a; // 타입과 변수 이름을 통해 선언 가능
int a, b, c; // 여러개의 변수를 선언 가능
자바 변수 naming convention
convention |
example |
첫 번째 글자는 문자이거나 특수문자 $ 또는 _ 만 가능하고 숫자로 시작할 수 없음 |
price, $price, _price = 가능, 1price, @price, $#price = 불가능 |
대소문자가 구분됨 |
myName != myname |
첫 문자는 영어 소문자로 시작하고 다른 단어가 붙을경우 첫 문자를 대문자로 함 |
myName, yourName |
문자 수(길이)의 제한이 없음 |
|
예약어를 사용할 수 없음 |
|
변수 초기화
class Variables {
int instanceVar; // 0으로 초기화되는 인스턴스 변수
static int classVar; // 0으로 초기화되는 클래스 변수
int initInstanceVar = 10; // 명시적으로 초기화
static int initClassVar = 10; // 명시적으로 초기화
void method(int num) { // 매개변수는 초기화 할 수 없고, 전달받는 값을 사용만 할 수 있음
int a; // 선언은 가능
// int b = a; 자동으로 초기화 되지 않으므로 동작하지 않음
a = 10; // 선언을 미리 해줬다면 이렇게 초기화 가능
int b = a; // 선언과 동시에 초기화
}
}
변수의 스코프와 라이프타임
Variable Type |
Scope |
Lifetime |
Instance Variable |
(static 블록과 static 메서드를 제외한) 클래스 전체 |
객체가 생성되고 객체가 메모리에 살아있는 동안 |
Class Variable |
클래스 전체 |
클래스가 초기화되고 프로그램이 끝날 때 까지 |
Local Variable |
변수가 선언된 블록내부 |
변수 선언 이후 부터 블록을 벗어날 때까지 |
public class Test {
int var1; // 인스턴스 변수, 필드, 전역 변수
static int var2; // 클래스 변수, 정적 변수
void doTest(int var3){ // 매개변수, 파라미터
int var4 = 100; // 지역 변수, 로컬 변수
}
}
public class App {
private static int number = 100;
private int helloNumber() {
return App.number; //참조가능
}
}
public class App {
private static int number = helloNumber(); //참조불가능 : helloNumber() 메서드는 App의 인스턴스가 생성되었을 때 사용가능하다. 하지만 number 변수는 클래스가 메모리에 로드되는 시점에 선언되어야 하므로 컴파일 에러가 발생함
private int helloNumber() {
return 100;
}
}
- 변수들이 로딩되는 시점이 다르다는 것을 인지하여야 함
타입 변환, 캐스팅 그리고 타입 프로모션
- 타입 변환
- 데이터 타입을 다른 데이터 타입으로 변환하는 것
- 강제(명시적) 타입 변환(캐스팅), 자동(묵시적) 타입 변환(프로모션)
- 캐스팅(casting)
- 강제 타입 변환
- 강제적으로 큰 데이터 타입을 작은 데이터 타입으로 저장하는 것(Narrow Conversion)
- 값이 변경 될 수 있음
- 축소
- 프로모션
- 자동 타입 변환
- 원래 타입에서 더 큰 타입으로 변경(Widening Conversion)
- 확장
int var1 = 1234567;
byte var2 = (byte) var1; // 캐스팅
double var3 = 3.14;
int var4 = (int) var3; // var4 = 3; 값이 변경됨, 캐스팅
int var5 = 10;
long var6 = var5; // 프로모션
1차 및 2차 배열 선언하기
1차원 배열
int[] intArr; // 주로사용
int []intArr; // 권장하지 않음
int intArr[]; // 권장하지 않음
int[] intArr = new int[100];
intArr[0] = 1;
System.out.println(intArr1[0]); // 1
System.out.println(intArr1[1]); // 0, 초기화 하지 않은 값은 기본 값으로 초기화됨
- 해당 크기만큼 배열의 요소가 초기화되어 생성됨
- 배열의 각 요소는 인덱스로 접근 가능
- 다른 초기화 방법
int[] intArr = {
100, 200, 300,
400, 500, 600,
700, 800, 900
};
int[] intArr = new int[] {100, 200, 300};
- 배열의 길이는 중괄호 사이에 선언된 요소의 수
- new로 생성되었으며 Java의 배열은 객체임 -> 힙 영역에 배열이 생성됨
2차원 배열
int[][] intArr; // 선언
intArr = new int[3][3]; // 메모리 할당, 초기화
- 다차원 배열 = 요소 자체가 배열인 배열
- 각 요소 배열간 길이는 다를 수 있음
int[][] intArr = new int[3][]; // 첫번째 차원은 지정해야하며 지정하지않을시 컴파일 에러 발생
intArr[0] = new int[1];
intArr[1] = new int[2];
intArr[2] = new int[3];
[0]
[0, 0]
[0, 0, 0]
int[][] arr = {
{1, 2, 3},
{4, 3, 6},
{7, 8, 9}
};
String[][] names = {
{ "Lim", "Kim", "Lee" }, // 다른 길이로도 가능
{ "Yohwan", "Younghee" }
};
String[][] names2 = new String[10][];// 요소의 길이를 초기화시 지정하지 않으면 null로 초기화
String[][] names3 = new String[10][10];// 지정 시 같은 크기로 배열 초기화
System.out.println(names[0][0] + names[1][0]); // LimYohwan
System.out.println(naems[0][2] + names[1][1]); // LeeYounghee
- 배열의 크기는 length 속성으로 알 수 있으며 한 번 초기화하고 나면 크기를 변경할 수 없음
타입 추론, var
타입 추론이란 정적 타이핑을 지원하는 언어에서 타입이 정해지지 않은 변수에 대하여 컴파일러가 변수의 타입을 스스로 찾아낼 수 있도록 하는 기능
= 타입을 명시하지 않아도 되어 코드량을 줄이고 가독성을 높일 수 있음
- Java10 부터 var가 생겼고 Java11부터 람다 타입 지원도 생김
- 컴파일러는 초기화 값을 통해 타입을 유추하므로 반드시 데이터를 초기화해야 함
public void test(){
var message = "Java10"; // 선언과 동시에 반드시 초기화
System.out.println(message instanceof String); // true
}
var의 활용
- forEach문
for(String name : nameList){
System.out.println(name);
}
for(var name : nameList){
System.out.println(name);
}
- 이미 List에 선언된 타입으로 var가 타입 추론을 하여 따로 String을 선언해 주지 않아도 되며 코드가 간결해지고 Object 타입으로 미리 단정 지을 필요도 없어짐
- 람다(Java11)
- 람다 인자에도 var를 사용할 수 있음
- 일반 람다의 경우 파라미터 어노테이션을 선언하지 못하여 선언하고 싶을시 따로 메서드를 생성하던가, 익명클래스로 생성했어야 함
- Java11부터 람다에서 타입 추론의 유연성을 추가함
Consumer personConsumer = (@Nonnull var person) -> {} // @Nonnull에 의해 person값의 nullcheck부터하게됨
- 익명 클래스
var intVal = 20;
var strVal = "string";
var list = new ArrayList();
- 심플한 var 사용은 가독성이 좋지 않아 지양해야 함
var supply = new Supplier(){
@Override
public String get(){
//logic
}
}
var supply = () -> {}; //람다식은 컴파일 오류
- 익명 클래스는 정의가 거대하고 유지하기 쉬우며 선언한 다음에 변수가 바뀌는 일이 없으므로 사용하기 좋음