목표
학습할 것
타입 | 크기 (byte) | 데이터 표현 범위 |
---|---|---|
byte | 1 | -128 ~ 127 |
short | 2 | -215 ~ (215 - 1) -32,768 ~ 32,767 |
int | 4 | -231 ~ (231 - 1) -32,768 ~ 32,767 |
long | 8 | -263 ~ (263 - 1) -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 |
타입 | 지수 길이 | 가수 길이 | 유효 자릿수 |
---|---|---|---|
float | 8 | 23 | 소수 부분 6자리까지 오차없이 표현 |
double | 11 | 52 | 소수 부분 15자리까지 오차없이 표현 |
타입 | 크기 (byte) | 데이터 표현 범위 | 리터럴 타입 접미사 |
---|---|---|---|
float | 4 | (3.4 X 10-38) ~ (3.4 X 1038) | F 또는 f |
double | 8 | (1.7 X 10-308) ~ (1.7 X 10308) | D 또는 d (생략 가능) |
타입 | 크기 (byte) | 데이터 표현 범위 |
---|---|---|
char | unsigned 2 | 0 ~ 216 \u0000 ~ \uffff |
타입 | 크기 (byte) | 데이터 표현 범위 |
---|---|---|
boolean | 1 | true 또는 false |
null
이 없음null
을 넣고 싶으면 레퍼런스 타입 사용java.lang.Object
를 상속 받으면 참조 타입변수에 저장될 수 있는 데이터 자체를 의미
L
또는 l
로 끝나는 형태l
은 숫자 1과 구분이 어려우므로 L
을 사용하는 것이 좋음byte
, short
, int
, long
타입은 int
리터럴로 생성int
범위를 벗어나는 값은 long
리터럴로 생성D
또는 d
로 끝날 경우)F
또는 f
로 끝나는 형태double d1 = 123.4;
// 지수 표기법
double d2 = 1.234e2;
float f1 = 123.4f;
다음 위치에는 넣을 수 없음
void 밑줄_사용한_숫자_표현() {
long creditCardNumber = 1234_5678_9012_3456L;
long socialSecurityNumber = 999_99_9999L;
float pi = 3.14_15F;
long hexBytes = 0xFF_EC_DE_5E;
long hexWords = 0xCAFE_BABE;
long maxLong = 0x7fff_ffff_ffff_ffffL;
byte nybbles = 0b0010_0101;
long bytes = 0b11010010_01101001_10010100_10010010;
}
char 리터럴: 작은 따옴표(') 사용
String 리터럴: 큰 따옴표(") 사용
이스케이프 문자: \
(백슬래시)
\b
(백 스페이스)\t
(탭)\n
(라인 피드)\f
(폼 피드)\r
(캐리지 리턴)\"
\'
\\
<TypeName>.class
형태로 표현// 변수 선언
// <변수 타입> <변수명>;
int a;
char b;
// 변수 선언 및 초기화
// <변수 타입> <변수명> = 초기화할 값;
int a = 1;
long b = 10L;
boolean c = true;
float f = 3.14f;
double d = 8.8;
String str = "Java";
스코프: static 메서드를 제외한 클래스 전체
라이프타임: 인스턴스가 메모리에 있는 동안
private
변수의 경우 클래스 외부에서 접근 불가public
변수의 경우 생성된 인스턴스를 통해 외부에서 접근 가능public class ClassScopeExample {
private Integer amount = 0;
public Integer qty = 0;
public void exampleMethod() {
amount++;
}
public void anotherExampleMethod() {
Integer anotherAmount = amount + 4;
}
}
// 클래스 외부
ClassScopeExample classScope = new ClassScopeExample();
classScope.qty = 1; // classScope.amount 는 접근 불가
스코프: 클래스 전체
라이프타임: 프로그램 실행부터 종료까지
instantName.variableName
으로 사용하기 보다는ClassName.StaticVariableName
으로 사용String name = ClassScopeExample.NAME;
스코프: 변수가 선언된 블록 내부
라이프타임: 변수가 선언된 블록을 벗어날 때까지
public class MethodScopeExample {
public void methodA() {
Integer area = 2;
}
public void methodB() {
// compiler error, area cannot be resolved to a variable
area = area + 2;
}
}
public class LoopScopeExample {
List<String> listOfNames = Arrays.asList("Joe", "Susan", "Pattrick");
public void iterationOfNames() {
String allNames = "";
for (String name : listOfNames) {
allNames = allNames + " " + name;
}
// compiler error, name cannot be resolved to a variable
String lastNameUsed = name;
}
}
// iterationOfNames 메소드에 name이라는 메소드 변수는
// 루프 내부에서만 사용할 수 있으며 외부에서는 사용 불가
public class BracketScopeExample {
public void mathOperationExample() {
Integer sum = 0;
{
Integer number = 2;
sum = sum + number;
}
// compiler error, number cannot be solved as a variable
number++;
}
}
// 변수 number는 괄호 안에서만 유효
public class NestedScopesExample {
String title = "Java Study";
public void printTitle() {
System.out.println(title); // Java Study
String title = "Max";
System.out.println(title); // Max
}
}
// title 클래스 변수에 액세스하려면 this.title과 같은 this 접두사를 사용하는 것이 좋음
int
타입의 리터럴과 float
타입의 리터럴을 연산하기 위해서는 int
타입이든, float
타입이든 하나의 타입으로 일치시킨 후 연산해야 함boolean
을 제외한 나머지 타입들은 서로 형변환 가능// 타입 캐스팅
double d = 123.45
int score = (int) d
e.g.,
// byte 타입 변수 byteValue에 정수 리터럴 65 저장
byte byteValue = 65;
// char 타입 변수 charValue에 byteValue 값 저장
char charValue = byteValue; // 컴파일 에러 발생
byte: 1byte / char: 2byte
크기만 봐서는 byte > char 자동 형 변환이 가능할 것 같지만 char 타입은 unsigned이며 데이터 표현 범위는 0~65535로 음수 저장 불가.
따라서 char 타입은 음수 저장이 불가능 하기 때문에 음수가 저장될 수 있는 byte 타입에서 char 타입으로 자동 형변환(Promotion) 할 수 없음
// 타입 프로모션
int score = 100
double d = score
선언
// 타입[] 배열이름;
Integer[] integers;
String[] strArray;
// 타입 배열이름[];
Double example[];
Char chars[];
두 가지 방법 모두 사용 가능하지만 첫 번째 방법만 사용 권장
생성
// 배열이름 = new 타입[배열길이];
integers = new Integer[3];
chars = new Char[5];
선언과 동시에 초기화
// 타입[] 배열이름 = {배열요소1, 배열요소2, ...};
Byte[] bytes = {1, 2, 3, ...};
// 타입[] 배열이름 = new 타입[]{배열요소1, 배열요소2, ...};
String[] strings = new String[]{"apple", "banana", "carrot", ...};
위의 두 방식은 같은 결과를 반환
다음의 경우 두 번째 방법만 사용 가능
1. 배열 선언과 초기화를 따로 진행해야 할 경우
2. 메소드의 인수로 배열을 전달하면서 초기화해야 할 경우
int[] grade1 = {70, 90, 80}; // 배열의 선언과 동시에 초기화할 수 있음.
int[] grade2 = new int[]{70, 90, 80}; // 배열의 선언과 동시에 초기화할 수 있음.
int[] grade3;
// grade3 = {70, 90, 80}; // 이미 선언된 배열을 이 방법으로 초기화하면 오류가 발생함.
int[] grade4;
grade4 = new int[]{70, 90, 80}; // 이미 선언된 배열은 이 방법으로만 초기화할 수 있음.
// 타입[][] 배열이름;
String[][] strings;
// 타입 배열이름[][];
Float floats[][];
// 타입[] 배열이름[];
Integer[] integers[];
선언과 동시에 초기화
/*
타입 배열이름[열의길이][행의길이] = {
{배열요소[0][0], 배열요소[0][1], ...},
{배열요소[1][0], 배열요소[1][1], ...},
{배열요소[2][0], 배열요소[2][1], ...},
...
};
*/
int[][] arr = {
{10, 20, 30},
{40, 50, 60}
};
int[][] arr = new int[3][];
arr[0] = new int[2];
arr[1] = new int[4];
arr[2] = new int[1];
선언과 동시에 초기화
int[][] arr = {
{10, 20},
{10, 20, 30, 40},
{10}
};
var
var
를 함수나 변수 이름으로 사용할 수 있음 -> 이전 버전과의 호환성을 보장함// ~ Java 9
String message = "Good bye, Java 9";
// Java 10 ~
@Test
public void whenVarInitWithString_thenGetStringTypeVar() {
var message = "Hello, Java 10";
assertTrue(message instanceof String);
}
// var 를 함수나 변수 이름으로 사용할 수 있음 -> 이전 버전과의 호환성을 보장함
public void varIsNotAKeyword() {
// Integer var = 3;
var test = 3;
}
boilerplate 코드를 작성하지 않아도 됨
Map<Integer, String> map = new HashMap<>();
위 코드를 다음과 같이 다시 작성할 수 있음
var idToNameMap = new HashMap<Integer, String>();
변수의 타입보다 변수 이름에 집중할 수 있음 -> 변수 네이밍이 잘 돼 있으면 소스 코드 파악에 더 좋을 수 있음
var를 사용할 수 없는 경우
// 초기화하지 않을 경우
var n; // error: cannot use 'var' on variable without initializer
// null 로 초기화 하는 경우
var emptyList = null; // error: variable initializer is 'null'
// 지역 변수가 아닌 경우
public var = "hello"; // error: 'var' is not allowed here
// 람다표현식에서는 명시적 타입이 필요하므로 사용할 수 없음
var p = (String s) -> s.length() > 10; // error: lambda expression needs an explicit target-type
// 배열 초기화에도 마찬가지로 명시적 타입이 필요하므로 사용할 수 없음
var arr = { 1, 2, 3 }; // error: array initializer needs an explicit target-type
코드의 가독성이 떨어질 수 있음
var result = obj.prcoess();
위 코드는 var
를 사용하는 데 문제는 없지만 process()
의 리턴 타입을 이해하기 어려워져 코드의 가독성이 떨어짐
예상과 다른 결과가 발생할 수 있음
var empList = new ArrayList<>();
empList
를 List<Employee> empList = new ArrayList<>();
처럼 사용하고 싶다면 명시적으로 타입을 적어줘야함
var empList = new ArrayList<Employee>();
var
를 사용하는 경우:@Test
public void whenVarInitWithAnonymous_thenGetAnonymousType() {
var obj = new Object() {};
assertFalse(obj.getClass().equals(Object.class));
}
이제 다른 Object
를 obj
에 할당하려고 하면 컴파일 오류 발생함
obj = new Object(); // error: Object cannot be converted to <anonymous Object>
추론된 유형의 obj
객체가 아니기 때문
참조
각주
좋은 글 감사합니다. 다음 연재도 기다리고 있어요!