Java | 변수와 자료형

설탕·2023년 9월 12일
0

Java

목록 보기
1/4
post-thumbnail

🥊 이 글은 제대로 파는 자바 - Java 끝.장.내.기 (얄팍한 코딩사전) 강의 내용을 정리한 글입니다.

변수

  • 자바는 정적 자료형 - 변수에 자료형이 다른 데이터를 넣을 수 없음 (컴파일 단계에서 차단됨)
  • 자바의 변수: 앞에 담을 데이터의 자료형을 명시
int age; // 변수 선언
System.out.println(age); // ⚠️ 컴파일 에러 (아직 값이 없으므로 사용할 수 없음)

age = 20; // 초기화
System.out.println(age); // 20 (이제 해당 값을 사용 가능)
  • 쉼표를 사용하여 여러 변수를 한 줄에 선언 및 초기화 가능 (모두 같은 자료형으로 선언됨)
char ch1, ch2, ch3; // 선언만
char ch4 = 'A', ch5 = 'B', ch6 = 'C'; // 선언과 초기화 동시에

자료형

정수 자료형

  • byte: 1byte
  • short: 2byte
  • int: 4byte
  • long: 8byte
  • 대부분의 컴퓨터에서 1바이트(byte) = 8비트(bit)
byte _1b_byte = 127; // 1byte
short _2b_short = 32767;
int _4b_int = 2147483647; // 가장 많이 쓰임
long _8b_long = 9223372036854775807L; // 끝에 L 붙여야 함

형변환

  • 큰 자료형에 작은 자료형의 값을 넣을 수 있음 - 묵시적(암시적) 형변환
  • 작은 자료형에 큰 자료형의 값을 (들어있는 값의 크기와 무관하게) "그냥" 넣을 수 없음 - 명시적 형변환
byte byteNum;
int smallIntNum = 123;

// 명시적(강제) 형변환
byteNum = (byte) smallIntNum; // byteNum: 123

// 강제로 범주 외의 값을 넣을 경우 값 손실
int intNum = 12345;
byteNum = (byte) intNum; // byteNum: 57 (12345 % 128)

실수 자료형

  • float: 4byte
  • double: 8byte
  • double: float보다 단순히 범위가 넓은 것이 아니라, 보다 정밀하게 표현 가능
float flt1 = 3.14f; // float는 뒤에 f 또는 F를 붙여 표현
double dbl1 = 3.14;

// float에는 double을 담을 수 없음
float flt2 = dbl1; // error
// 반대는 가능
double dbl2 = float1;

문자 자료형: char

  • char: 2byte
  • 단따옴표 사용하여 1개의 문자 표현
  • 빈 문자 불가
// 각 문자는 상응하는 정수를 가짐
char ch1 = 'a'; // ch1: 'a' 97
char ch2 = 'a' + 1; // ch2: 'b' 98
char ch3 = '가'; // ch3: '가' 44032
char ch4 = '가' + 1; // ch6: '각' 44033

int ch1Int = (int) ch1; // ch1Int: 97

// 문자 리터럴, 숫자, 유니코드로 표현 가능
char ch5 = 'A'; // ch5: 'A' 65
char ch6 = '65'; // ch6: 'A' 65
char ch7 = '\u0041'; // ch7: 'A' 65

// 빈 문자 사용 불가, 공백(space)은 가능
char empty = ''; // error
String emptyStr = ""; // emptyStr: "" String은 빈 문자열 가능
char space = ' '; // space: ' ' 32

불리언 자료형: boolean

  • boolean: 1byte
boolean bool1 = true;
boolean bool2 = false;

문자열 자료형: String

  • 위의 자료형들과 달리 참조 자료형
    • 그러나 특별히 원시값과 유사하게 사용될 수 있음
  • 쌍따옴표 사용
String str1 = "Hello World!"; // 리터럴 방식
String str2 = ""; // 빈 문자열 가능
String str3 = new String("Hello World!"); // 인스턴스 생성 방식

문자열 비교

String hl1 = "Hello";
String hl2 = "Hello";
String wld = "World";

// 리터럴끼리는 == 을 사용하여 비교 가능
boolean bool1 = hl1 == hl2; // bool1: true
boolean bool2 = hl1 == wld; // bool2: false

String hl3 = new String("Hello");
String hl4 = new String("Hello");

// 인스턴스와 비교하려면 .equals 메소드를 사용해야 함
// 특별한 경우가 아니면 문자열은 .equals로 비교할 것
boolean bool3 = hl3 == hl4; // bool3: false
boolean bool4 = hl1.equals(hl2); // bool4: true
boolean bool5 = hl1.equals(hl3); // bool5: true
boolean bool6 = hl3.equals(hl4); // bool6: true
boolean bool7 = wld.equals(hl2); // bool7: false

// 같은 곳을 참조하는 인스턴스들
String hl5 = hl4;
boolean bool8 = hl4 == hl5; // bool8: true
boolean bool9 = hl4.equals(hl5); // bool9: true

리터럴 생성 vs 객체 인스턴스 생성

  • 리터럴로 생성 시: String constant pool에 중복 없이 저장됨
    • 같은 문자열이 적힌 리터럴 변수들은 같은 주소를 가리킴
  • 객체 인스턴스로 생성 시: 매번 새로 생성되어 각각 주소값을 가짐
// 리터럴로 선언했어도 객체 인스턴스로 생성되기 때문에 메소드 사용 가능
String str = "Hello";
boolean bool = str.equals("Hello"); // bool: true

Formatter

String str1 = "%s의 둘레는 반지름 X &d X %f입니다.";

String circle = "원";
int two = 2;
double PI = 3.14;

// formatted(인스턴스 메소드): 주어진 형식에 따라 문자열 생성 (13+버전에 추가됨)
String str2 = str1.formatted(circle, two, PI); // str2: "원의 둘레는 반지름 X 2 X 3.140000입니다."

// 이전 버전에서의 방식(클래스 메소드)
String str3 = String.format(str1, circle, two, PI); // str3: "원의 둘레는 반지름 X 2 X 3.140000입니다."

// 시스템의 printf 메소드: String.format과 같은 형식으로 출력 (줄바꿈X)
System.out.printf("%s의 둘레는 반지름 X &d X %f입니다.", circle, two, PI); // 원의 둘레는 반지름 X 2 X 3.140000입니다.
Formatter자료형
%b불리언
%d10진수 정수
%f실수
%c문자
%s문자열
%n(포맷 문자열 내 줄바꿈)

정수 Formatting

String[] intFormats = {
	"%d", // 1. 기본 
    "%13d", // 2. 13자리 수 확보, 오른쪽 정렬
    "%013d", // 3. 빈 자리 수 0으로 채움
    "%+13d", // 4. 양수는 앞에 + 붙임
    "%,13d", // 5. 쉼표 사용
    "%-13d", // 6. 13자리 수 확보, 왼쪽 정렬
    "%+,013d" // 7.
};

출력 결과:

실수 Formatting

String[] fltFormats = {
	"%f", // 1. 기본 (소수점 6자리, 0으로 채움)
    "%.2f", // 2. 소수점 2자리까지
    "%13.2f", // 3. 정수 자리 확보, 소수 자리 제한
    "%,f", // 4. 쉼표 사용
    "%+013.2f", // 5.
    "%-13.2f" // 6.
};

출력 결과:

문자열 Formatting

String[] strFormats = {
	"%s", // 1. 기본
    "%9s", // 2. 자리 확보
    "%.2s", // 3. 2글자만
    "%9.2s", // 4.
    "%-9s" // 5. 왼쪽 정렬
};

출력 결과:

null

"" vs null

String emptyStr = "";
String nullStr = null;

// 빈 문자열과 null은 다름
boolean bool1 = emptyStr == nullStr; // bool1: false

// null은 문자열 인스턴스 메소드 사용 불가
// 아래의 코드들은 모두 런타임 에러를 발생시킴 (NullPointerException)
int int1 = nullStr.length();
boolean bool2 = nullStr.equals(emptyStr);
String str1 = nullStr.concat("ABC");

  • 빈 문자열"": 길이 0. 힙 공간에 자리를 차지
  • null 문자열: 힙에 할당되지 않음. 가리키는 곳이 없음

초기화되지 않은 변수 vs null

String notInitStr;
String nullStr = null;

System.out.println(notInitStr); // 컴파일 에러
System.out.println(nullStr); // null

참조 자료형의 인스턴스는 null 가능

Object obj = null;
System sys = null;

// 원시값들도 참조 자료형의 인스턴스로는 null 가능
Integer nullInt1 = null;
Double nullDbl1 = null;
Boolean nullBool1 = null;
Character nullChr1 = null;

// 원시값은 불가
int nullInt2 = null; // 컴파일 에러

배열

  • 지정된 자료형과 개수만큼 메모리 공간을 나란히 확보
  • 배열 요소의 개수 변경 불가능
char[] yutnori = {'도', '개', '걸', '윷', '모'};

  • 각각이 담는 자료형의 크기만큼 요소당 메모리 차지
  • 문자열의 경우 각 문자열이 저장된 주소값을 저장 (JVM마다 4byte 또는 8byte 등 달라짐)

배열 선언과 초기화

  • 배열을 초기화하지 않고 선언하면

  • 선언과 동시에 초기화

// 선언 동시 초기화
char[] dirArr1 = {'동', '서', '남', '북'}; // 방법1
char[] dirArr2 = new char [] {'동', '서', '남', '북'}; // 방법2

char[] dirArr3;

// 선언만 먼저 한 상태에서는 방법2만 가능
dirArr3 = {'동', '서', '남', '북'}; // 컴파일 에러
dirArr3 = new char [] {'동', '서', '남', '북'};

원시 자료형(primitive type) vs 참조 자료형(reference type)

  • 원시 자료형: 값 자체를 복사
// 원시 자료형은 값 자체를 복사 - 별개의 값이 됨
boolean initTrue = true; // initTrue: true
boolean initFalse = false; // initFalse: false
initFalse = initTrue; // initFalse: true
initTrue = false; // initTrue: false
  • 참조 자료형: 주소값을 복사
// 참조 자료형은 주소값을 복사 - 두 변수가 같은 주소를 가리키게 됨
boolean[] boolArr1 = { true, true, true };
boolean[] boolArr2 = { false, false, false };
boolArr2 = boolArr1;
boolArr1[0] = false; // boolArr1: [false, true, true], boolArr2: [false, true, true]
  • 다중 배열 내 배열의 크기가 다를 수 있는 이유: 배열은 참조형(주소값)이므로

  • 문자열은 객체(참조형)지만 원시형처럼 다뤄짐

String str1 = "코인 함";
String str2 = "관심 없음";
str2 = str1;

str1 = "고점에 익절"; // str1: "고점에 익절", str2: "코인 함"
  • 상수 배열은 배열 요소를 바꾸는 것만 가능
final int[] NUMBERS = { 1, 2, 3, 4, 5 };

// 다른 배열 할당 불가
NUMBERS = new int[] { 2, 3, 4, 5, 6 }; // 컴파일 에러

// 배열 요소를 바꾸는 것은 가능
NUMBERS[0] = 11; // NUMBERS: [11, 2, 3, 4, 5]

타입 추론

  • Java 10에서 도입됨
  • var 연산자로 변수 선언 - 타입을 명시하지 않음 (대입된 값을 통해 컴파일러가 추론)
  • 지역 변수에서만 사용 가능, 클래스 필드로는 불가
var intNum = 1;
var doubleNum = 3.14;
var charLet = 'A';
var StringWord = "Hello";

// 아래와 같이는 사용 불가 (컴파일러가 타입을 추론할 수 없음)
var notItit; // 초기화 안 됨 - 컴파일 에러
var nullVar = null; // null로 초기화 - 컴파일 에러

// 자료형 변경 불가
intNum = 1.23; // 컴파일 에러
StringWord = 123; // 컴파일 에러

// 배열의 경우 초기화할 때 명시
var chars = new char[] { 'A', 'B', 'C', 'D', 'E' };
var chars2 = { 'A', 'B', 'C', 'D', 'E' }; // 불가
profile
공부 기록

0개의 댓글