[2주차] 자바 데이터 타입, 변수, 그리고 배열
목표
- 자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을 익힙니다.
학습할 것
- 프리미티브 타입 종류와 값의 범위 그리고 기본 값
- 프리미티브 타입과 레퍼런스 타입
- 리터럴
- 변수 선언 및 초기화하는 방법
- 변수의 스코프와 라이프타임
- 타입 변환, 캐스팅 그리고 타입 프로모션
- 1차 및 2차 배열 선언하기
- 타입 추론, var
프리미티브 타입 종류와 값의 범위 그리고 기본 값
정수형
- 부호를 가지고 있으며, 소수 부분이 없는 수
- 타입이 표현할 수 있는 범위를 벗어난 데이터를 저장하면, 오버플로우(overflow)가 발생
- 전혀 다른 값이 저장될 수 있음
- 기본값: 0 (long: 0L)
타입 | 크기 (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: 0.0F(or f)
- double: 0.0(D or d)
타입 | 지수 길이 | 가수 길이 | 유효 자릿수 |
---|---|---|---|
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 (생략 가능) |
문자형
- 작은 정수나 문자 하나를 표현
- 유니코드(unicode)를 사용하여 문자 표현
- 기본값: \u0000
타입 | 크기 (byte) | 데이터 표현 범위 |
---|---|---|
char | unsigned 2 | 0 ~ 216 \u0000 ~ \uffff |
논리형
- 참(true)이나 거짓(false) 중 한 가지 값만을 가짐
- 기본값: false
타입 | 크기 (byte) | 데이터 표현 범위 |
---|---|---|
boolean | 1 | true 또는 false |
프리미티브 타입과 레퍼런스 타입
프리미티브 타입
- 실제 데이터 값(리터럴)을 담는 타입
- 값은 Stack 메모리에 저장
- 기본값이 있음
- 비객체 타입이므로
null
이 없음- 기본형 타입에
null
을 넣고 싶으면 레퍼런스 타입 사용
- 기본형 타입에
- 문자열 -> 기본형으로 변환할 때 parseType 메서드 사용
- 레퍼런스 타입의 valueOf 메서드 보다 조금 더 빠름
레퍼런스 타입
java.lang.Object
를 상속 받으면 참조 타입- 기본 자료형 외에는 모두 참조 타입
- 문자열 -> 기본형으로 변환할 때 valueOf 메서드 사용
- 값이 저장되어 있는 곳의 주소값을 저장
- 주소값은 Heap 메모리에 저장
- 4byte 의 같은 크기를 가짐
- Wrapper Class
- 8개의 기본 타입에 해당하는 데이터를 객체로 포장해 주는 클래스
- void의 래퍼 클래스인 Void도 존재
리터럴
변수에 저장될 수 있는 데이터 자체를 의미
정수 리터럴
- 정수형 숫자
- 정수형 숫자가
L
또는l
로 끝나는 형태l
은 숫자 1과 구분이 어려우므로L
을 사용하는 것이 좋음
byte
,short
,int
,long
타입은int
리터럴로 생성int
범위를 벗어나는 값은long
리터럴로 생성
실수 리터럴
- double: 실수형 숫자 (+
D
또는d
로 끝날 경우) - float: 실수형 숫자가
F
또는f
로 끝나는 형태
double d1 = 123.4;
// 지수 표기법
double d2 = 1.234e2;
float f1 = 123.4f;
숫자 리터럴에서의 밑줄문자(_, underscore) 사용
- 자바7부터 추가된 기능
- 숫자 리터럴을 읽기 쉽게 해줌
- 자릿수가 긴 리터럴을 표현할 때 유용
- 숫자 사이에만 밑줄을 넣을 수 있음
- 연속 입력 가능
다음 위치에는 넣을 수 없음
- 숫자의 시작 또는 끝
- 부동 소수점 리터럴에서 소수점에 붙은 경우
- 뒤에 붙는 F, L, D등의 문자 앞 뒤에 붙은 경우
- 문자열에서 문자가 올 것으로 예상되는 위치
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;
}
문자 및 문자열 리터럴
- 유니코드로 표현
- 직접 해당 문자를 코드에 입력 가능
- 유니코드 이스케이프('\u0000') 사용 가능
char 리터럴: 작은 따옴표(') 사용
String 리터럴: 큰 따옴표(") 사용
이스케이프 문자: \
(백슬래시)
\b
(백 스페이스)\t
(탭)\n
(라인 피드)\f
(폼 피드)\r
(캐리지 리턴)\"
\'
\\
불린 리터럴
- true
- false
그 외 리터럴
- null
- Class
<TypeName>.class
형태로 표현- 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 키워드 없이 선언 된 필드
- 인스턴스 별로 다른 값을 가짐
클래스 변수 (static)
- static 키워드로 선언 된 필드
- 모든 인스턴스가 값을 공유
- 여러 개의 인스턴스가 생성되더라도 static 변수는 하나만 생성
로컬 변수
- 메서드 내부에 선언되고 사용되는 임시 변수
- 인스턴스 변수 선언과 유사 (ex: int count = 0;)
- 로컬 변수는 선언 된 메서드 내부에서만 사용할 수 있음
- 다른 클래스에서 접근 불가
매개 변수
- 메서드의 인자로 전달되는 변수
변수의 스코프와 라이프타임
Instance Variable
스코프: 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 는 접근 불가
Class Variable (static)
스코프: 클래스 전체
라이프타임: 프로그램 실행부터 종료까지
- 클래스 내부, 모든 블록 외부에서 선언되고 static으로 선언
- static 변수는
instantName.variableName
으로 사용하기 보다는ClassName.StaticVariableName
으로 사용
String name = ClassScopeExample.NAME;
Local Variable
스코프: 변수가 선언된 블록 내부
라이프타임: 변수가 선언된 블록을 벗어날 때까지
- 인스턴스 또는 클래스 변수가 아닌 모든 변수
- Method Vriable
- 메소드 내에서만 접근 가능
- 다른 메소드에서 정의한 변수에 접근하려고 하면 컴파일 에러 발생
- 함수 호출 시 스택(Stack) 메모리에 생성
public class MethodScopeExample {
public void methodA() {
Integer area = 2;
}
public void methodB() {
// compiler error, area cannot be resolved to a variable
area = area + 2;
}
}
- Loop Variable
- Loop 내에서만 접근 가능
- Loop 밖에서 접근하려고 하면 컴파일 에러 발생
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이라는 메소드 변수는
// 루프 내부에서만 사용할 수 있으며 외부에서는 사용 불가
- Bracket Scope
- 괄호 안에서만 접근
- 괄호 밖에서 접근하려고 하면 컴파일 에러 발생
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는 괄호 안에서만 유효
- Scopes and Variable Shadowing
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 접두사를 사용하는 것이 좋음
타입 변환, 캐스팅 그리고 타입 프로모션
타입 변환
- 변수나 리터럴의 타입을 다른 타입으로 변환하는 것
- e.g.,
int
타입의 리터럴과float
타입의 리터럴을 연산하기 위해서는int
타입이든,float
타입이든 하나의 타입으로 일치시킨 후 연산해야 함
- e.g.,
타입 캐스팅
- 명시적 형 변환: 큰 데이터 타입에서 작은 데이터 타입으로 형 변환
- 값 손실이 일어날 수 있음
- e.g., 4byte int 300 > casting > 1byte byte 44
- int는 32bit, byte는 8bit의 크기를 갖고 있음
- int 300 의 2진수 표현: 00000000 00000000 00000001 00101100
- int 300의 2진수 표현에서 변환할 타입의 크기의 bit만 남기고 나머지는 잘려나감
- i.e., 2진수 표현한 300을 byte로 캐스팅했을 때: 00101100
- byte로 캐스팅된 2진수의 값을 10진수로 변환하면: 44라는 값이 나옴
- 정수형 > 실수형 변환 시 소수점 이하 값은 버림 처리
- e.g., 4byte int 300 > casting > 1byte byte 44
- 프리미티브 타입에서
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
1차 및 2차 배열 선언하기
1차원 배열(One Dimensional Array)
선언
// 타입[] 배열이름;
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}; // 이미 선언된 배열은 이 방법으로만 초기화할 수 있음.
2차원 배열(Two Dimensional Array)
- 배열의 요소로 1차원 배열을 가지는 배열
- 자바에서는 2차원 배열을 나타내는 타입을 따로 제공하지 않음
- 대신 1차원 배열의 배열 요소로 또 다른 1차원 배열을 사용하여 2차원 배열을 나타낼 수 있음
// 타입[][] 배열이름;
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}
};
가변 배열(Dynamic Array)
- 행마다 다른 길이의 배열을 저장할 수 있는 배열
- 2차원 배열을 생성할 때 열의 길이를 명시하지 않으면 행마다 다른 길이의 배열을 요소로 저장할 수 있음
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
- 자바 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()
의 리턴 타입을 이해하기 어려워져 코드의 가독성이 떨어짐
예상과 다른 결과가 발생할 수 있음
- Java 7에 도입된 다이아몬드 연산자와 함께 사용하는 경우:
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
객체가 아니기 때문
참조
- https://programmers.co.kr/learn/courses/5/lessons/231
- https://codechacha.com/ko/java-variable-scope/
- https://www.baeldung.com/java-variable-scope
- 백기선님-온라인-스터디-2주차-자바-데이터-타입-변수-그리고-배열
- https://www.baeldung.com/java-type-casting
- http://www.tcpschool.com/java/java_array_oneDimensional
http://www.tcpschool.com/java/java_array_twoDimensional - https://velog.io/@bk_log/Java-%ED%83%80%EC%9E%85-%EC%B6%94%EB%A1%A0
- https://www.baeldung.com/java-10-local-variable-type-inference
각주
- 오버헤드(overhead)
- 기존 A메서드 소요시간 10초. A메서드에 안정성을 고려하여 작업한 B메서드 소요시간 15초 -> 오버헤드 5초 라고 함
- B메서드를 개선한 C메서드의 소요시간 12초 -> 오버헤드가 3초 단축되었다고 함
Author And Source
이 문제에 관하여([2주차] 자바 데이터 타입, 변수, 그리고 배열), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@max/2주차-자바-데이터-타입-변수-그리고-배열저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)