『자바의 신 3판』 을 읽고 내용 정리 및 공부한 내용을 정리한 글입니다.
서적: 자바의 신 3판 구입처
자바에는 총 4개의 변수가 존재한다.
지역 변수 (local variables)
매개 변수 (parameters)
인스턴스 변수 (instance variables)
클래스 변수 (class variables)
※ 인스턴스 변수와 클래스 변수는 static 이냐 아니냐에 따라 달라진다.
💡 할당 해제
C나 C++이라는 언어는 할당(allocation)을 한 변수에 어떤 값을 지정했으면, 개발자가 추후 할당을 해제할 수 있다. 그러면 바로 메모리에서 사라진다.
하지만 자바에서는 가비지 콜렉터(Garbage collector)가 알아서 메모리를 청소해 주기 때문에, 개발자가 임의로 할당 해제할 수가 없고 해서도 안 된다.
한글로 변수 이름을 지정해도 컴파일하는 데 문제는 없지만, 기본적인 규칙은 다음과 같다.
책의 내용이 아닌, 추가로 찾아서 기입한 것이다.
출처
변수, 함수, 클래스 등 이름을 짓는 다양한 표기법들이 있다. 카멜 표기법, 스네이크 표기법, 파스칼 표기법이 그 대표적인 예다.
자바의 타입(자료형)은 크게 기본 자료형(Primitive data type)과 참조형(Reference data type)으로 나뉜다. 참조 자료형은 우리가 마음대로 만들 수 있지만, 기본 자료형은 정해져 있다.
자료형을 초기화할 때 new라는 예약어를 사용해 초기화하는 것을 참조 자료형, 그렇지 않고 바로 초기화할 수 있는 것을 기본 자료형이라고 한다.
어떤 변수든 값을 저장하기 위해서 만든다. 저장할 값이 정해져 있다면, 그 값을 지정해주면 되겠지만 항상 저장할 값이 정해져 있지는 않다.
그래서 변수를 선언할 때에는 초기화를 해줘야 변수가 사용할 수 있는 상황이 된다고 기억하면 된다.
초기화할 때 예외로는 참조형 중 String이 있다. String은 두 가지 방식으로 초기화할 수 있다.
String만이 참조 자료형이지만 new를 사용해서 객체를 생성하지 않아도 되는 유일한 타입이다. 상세한 내용은 15장에서 설명한다.
기본 자료형은 총 8개다. 기본 자료형은 숫자와 boolean 타입 두 가지로 나뉜다. 그리고 숫자는 정수형과 소수형으로 나뉜다.
byte, short, int, long, float, double 은 순서대로 해당 타입의 범위가 정해진다.
정수형에는 byte, short, int, long, char 가 있다. 방금 타입의 범위가 정해진다고 했는데, 자바에서는 숫자의 크기에 제한이 있다.
만약 제한이 없다면, π 같은 무한 소수도 엄청나게 길게 저장할 수 있을 것이다.
정수형 중에서 unsigned(부호가 없는)인 것은 char 뿐이고, 나머지는 부호가 있는 signed 타입들이다.
각 정수형의 타입별 숫자의 범위는 다음과 같다.
타입 | 최소 | 최대 |
---|---|---|
byte | (-128) | (127) |
short | (-32,768) | (32,767) |
int | (-2,147,483,648) | (2,147,483,647) |
long | (-9,223,372,036,854,775,808) | (9,223,372,036,854,775,807) |
char | (’\u0000’) | (’\uffff’) |
컴퓨터는 0과 1을 사용하는 2진법으로 숫자를 표현한다. 따라서 모든 자바의 숫자 타입들은 2의 배수로 그 범위가 정해진다.
byte부터 long까지의 범위를 보면, 8 → 16 → 32 → 64 순으로 두 배씩 범위가 증가하고 있는 것을 볼 수 있다.
가 아닌, 로 표기되고 있는 이유는 바로 부호가 있기(signed) 때문이다. 앞서 말했듯이 컴퓨터는 0과 1로 숫자를 표현하는데, 음수와 양수를 표현해주기 위해 맨 앞의 있는 값을 사용한다.
맨 앞자리의 값이 0이면 양수, 1이면 음수
여기에서 최대값에는 을 해주고 있는 이유는 바로 0 때문이다. 8비트(1byte)에서 표현하자면 다음과 같다.
0에는 양수와 음수라는 개념이 없다. 뒤에서 비트 연산자를 배울 때 자세히 알아보겠지만, 일단은 맨 앞자리가 1인 0은 0이 아니라 128()으로 취급한다.
그러므로 절대값만으로 따지자면 최소값의 절대값이 최대값의 절대값보다 딱 1이 더 크다는 것을 알 수 있다.
책에서는 비트를 더하고 빼서 설명을 하는데, 비트의 연산에 대한 설명이 없어 추가한다.
컴퓨터는 0과 1로 된 2진수를 사용한다. 그리고 이러한 2진수의 덧셈은 일반 숫자를 더하는 것과 유사하게 생각하면 된다.
2진수 덧셈 예제
이렇게 1과 1을 더했을 때 앞에 1이 나가며, 이를 캐리(carry)라고 부른다. 만약 앞의 비트가 없으면 이 캐리는 버린다.
컴퓨터에서는 덧셈만 존재하므로, 뺄셈을 할 경우에는 비트를 2의 보수를 취해 더해줘야 한다.
관련 내용은 CS 지식을 정리할 때 자세히 나오겠지만, 일단은 단순히 아래처럼 생각하면 된다.
1의 보수: 모든 비트를 0은 1로, 1은 0으로 바꿔준다.
2의 보수: 1의 보수를 한 상태에서 +1을 해준다.
아래는 십진수 와 을 2진수로 변환하여 계산하는 과정이다.
책에 나온 예제를 이용해 정수형들의 최소값과 최대값에서 각각 1을 더하고 빼보는 코드이다.
기본적으로 자바에서는 숫자를 명시하면 int로 생각하기 때문에, long타입의 숫자를 명시적으로 지정해 줄 때에는 반드시 숫자 가장 뒤에 L을 붙여주어야만 한다.
public void checkByte() {
byte byteMin = -128;
byte byteMax = 127;
System.out.println("byteMin="+byteMin);
System.out.println("byteMax="+byteMax);
byteMin = (byte) (byteMin - 1);
byteMax = (byte) (byteMax + 1);
System.out.println("byteMin="+byteMin);
System.out.println("byteMax="+byteMax);
short shortMax=32767;
int intMax = 2147483647;
long longMax = 9223372036854775807L;
System.out.println(shortMax + ", " + intMax + ", " + longMax);
shortMax = (short) (shortMax + 1);
intMax = intMax + 1;
// longMax + 1 으로 써도 문제없이 실행된다.
longMax = (long) (longMax + 1);
System.out.println(shortMax + ", " + intMax + ", " + longMax);
}
(byte) (bytemin-1)
이런 식으로 감싸 형 변환을 시켜준 이유는, 이전 버전의 자바에서는 정상적으로 수행이 되었지만 자바8에서는 컴파일 오류가 발생하게 되어서라고 한다.
작성 중, (short) (shortMax+1)
이렇게 괄호를 빼먹는 실수를 했다.
그러자 위와 같이, int를 short로 바꿀 수 없다는 오류가 발생했다. 그런데, long 형 연산에서는 동일하게 괄호를 빼먹어도 오류가 발생하지 않았다.
이건 자바에서 int보다 작은 정수형의 연산은 모두 int로 취급해서 그렇다고 한다. 따라서 long 형 연산에서는 형 변환을 시키지 않아도 오류없이 실행되는 것이다.
동영상을 저장하고, 이미지를 저장할 때 int를 사용하면 단순히 숫자 하나를 표현하기 위해서 32개의 비트를 표시하기 위한 공간이 필요하다. 즉, byte대비 4배의 저장공간이 더 필요하게 되는 것이다. 그래서 많은 부분에서 데이터를 저장할 때 byte 값들을 조합해서 사용한다. 그래야 적은 공간에 보다 많은 내용을 저장할 수 있다.
JDK 7부터는 숫자 표현을 보다 명확하고 편하게 할 수 있도록 되어 있다. 자세한 내용은 30장의 JDK 7 관련 부분을 참조.
float 와 double 모두 소수점 값을 처리하기 위해서 사용된다. float는 32비트이며, double은 64비트로 표현된다. 그런데, 이 두 가지의 소수점은 간단한 계산에서는 사용해도 무방하지만 돈 계산과 같이 중요한 부분에서는 사용해서는 안 된다.
왜냐하면 이 타입들은 32비트와 64비트로 제공할 수 있는 범위를 넘어서면 그 값의 정확성을 보장하지 못하기 때문이다. 그래서 자바에서는 돈 계산과 같이 정확한 계산이 요구될 때에는 java.math.BigDecimal
이라는 클래스를 사용해야만 한다. 부록 13의 java.util 패키지 참조.
Oracle의 자바 설명서에는 다음과 같이 정의되어 있다.
- float: single-precision 32-bit IEEE 754 floating point
- double: double-precision 64-bit IEEE 754 floating point
float는 “단일-정확도를 가지는 32비트 IEEE 754 부동 소수점”이라고 해석할 수 있다.
소수점 처리를 할 때 일반적으로는 double을 많이 사용한다. 그리고, 대량으로 소수점 자리수가 적은 데이터를 저장하려고할 경우에는 float를 사용하면된다.
이 타입들의 범위를 알려면 복잡한 수학 공식을 알아야 한다. 자세한 설명은 부록을 참고하고, 일단 아래처럼 구성된다는 것만 알아두자.
- float: 부호(1자리) + 지수(8자리) + 가수(23자리) = 32 비트
- double: 부호(1자리) + 지수(11자리) + 가수(52자리) = 64 비트
💡 IEEE란?
IEEE는 국제적인 표준을 의미하고, 754는 그 표준의 번호다.
각 번호마다 명칭이 있는데, IEEE 754의 정식 명칭은 Standard for Binary Floating-Point Arithmetic이다.
char 는 “캐릭터-character-”라고 읽는다. 보통 문자열과 관련된 부분에서 사용하며, 정의할 때 홑따옴표를 사용한다.
char는 정수형이므로, 아래와 같이 사용해도 문제는 없다. 왜냐하면 char의 범위(0~65,535)는 int보다 좁기 때문에 이와 같은 형 변환은 가능해야 한다.
int intValue = 'a' // char to int
결과는 아스키코드인 97
로 나온다.
💡 ASCII 코드란?
미국에서 만들어진 1 byte 단위의 문자들.
알파벳, 숫자, 기호를 포함하며 각 문자마다 고정되어 있는 번호가 할당되어 있다. 이 번호는 어떤 컴퓨터, 언어, OS를 가더라도 동일하다.
자바에서는 Unicode라는 2 byte를 사용하기 때문에 ASCII가 할당된 값들이 먼저 나오고, 그 다음에 미리 정해져 있는 유니코드들이 존재한다.
char의 값을 지정하는 방법은 크게 세 가지다.
char의 올바른 예
char test0 = 'a';
char test1 = '가';
char test2 = '\u1188';
char test3 = 44032;
💡 한글은 대부분 2 바이트로 표현하며 유니코드에 포함되어 있다. 그러므로 사용할 수 있다.
char의 잘못된 예
char test4 = ''; // Invalid character constant
char test5 = '\u11'; // Invalid unicode
char test6 = 'ab'; // Invalid character constant
char test7 = ""; // Type mismatch: cannot convert from String to char
char test8 = -1; // Type mismatch: cannot convert from int to char
boolean은 “true”와 “false”, 두 개의 값밖에 없다. 다시 말해서, “참”과 “거짓”밖에 없는 타입이다.
참일 경우 true를, 거짓일 경우 false를 넣는다.
boolean flag1 = true;
boolean flag2 = false;
자바의 모든 자료형은 값을 지정하지 않으면 기본값을 사용한다. 그런데, 지역 변수로 기본 자료형을 사용할 때에는 기본 값이 자동으로 적용되지 않고, 반드시 값을 지정해야만 한다.
즉, 메소드 안에서 정의한 변수에 값을 지정하지 않고 사용하려고 하면, 컴파일 시 오류가 난다. 인스턴스 변수, 클래스 변수, 매개 변수는 값을 지정하지 않아도 컴파일이 되기는 한다.
하지만, 이렇게 값을 지정하지 않고 개발하는 것은 매우 안좋은 습관이다. 만약 그 변수의 값이 기본 값이라고 할지라도, 명시적으로 기본값을 지정하자.
아래 코드를 컴파일 및 실행해보면 정상적으로 동작한다.
public class PrimitiveTypes {
int intDefault1;
public void defaultValues() {
int intDefault2;
}
}
여기서 왜 지역 변수인 intDefault2
를 초기화하지 않았는데도 컴파일과 실행이 되는 이유는, intDefault2
를 사용하는 부분이 없기 때문이다.
다음과 같이 intDefault2
를 출력하는 코드를 추가하면 컴파일 시 초기화가 되지 않았다는 에러가 난다.
public class PrimitiveTypes {
int intDefault1;
public void defaultValues() {
int intDefault2;
System.out.println(intDefault1);
System.out.println(intDefault2);
}
}
즉, 지역 변수를 만들어 놓고 사용하지 않을 때에는 초기화를 하지 않아도 되지만, 사용할 때에는 반드시 초기화를 해야 한다.
Me: 인스턴스 변수, 지역 변수, 매개 변수, 클래스 변수가 있다. 위치로 우선 구분하고, 클래스 변수와 인스턴스 변수는 static으로 구분한다.
Me: 아니오
Me: 기본 자료형과 참조 자료형이 있다.
Me: 8가지
순서를 제대로 쓰지 않으면 구글 폼 제출이 안된다.
Me: int, long, char, byte, short
Me: 8비트
Me: 저장공간을 효율적으로 사용하기 위해 int보다 작은 숫자를 사용하는 이미지, 동영상 등에 사용한다.
Me: long
Me: float와 double이 있다.
Me: 예
Me: '’
Me: boolean
💡 책에 있는 내용이 아닙니다.
책을 읽으며 설명이 더 필요하거나, 추가로 궁금한 점에 대해 질문 형식으로 작성 후, 답을 구해보고 있습니다.
참고한 사이트나 영상은 [출처]로 달아두었으며, 오류 지적은 언제나 환영합니다.
전역변수(global variable)는 함수의 외부에서 선언된 변수이다. 프로그램의 어디에서나 접근할 수 있으며, 프로그램이 종료되어야만 메모리에서 사라진다.
그 이유는 디자인적인 이유에서라고 한다. 자바는 개체지향 언어이고 캡슐화를 통해 은닉성을 보장한다. 전역변수는 해당 언어의 목적과 상반되는 개념이다.
전역변수를 구현하고 싶으면 public static
(불변성을 가지고 싶다면 final
을 포함)을 사용할 수 있다.
다만, 위의 이유에서 public static 으로 구현하는 것은 상수를 제외하고는 만들지 않는 게 좋다.
이미지는 픽셀 단위로 구성되어 있는데, 이미지의 종류에 따라 다르지만 1픽셀이 1Bit(이진 영상)이기도 하고, 1Byte이기도 하다. 굳이 int나 long을 써서 사용하지 않는 메모리도 잡는 것보단, 최소 단위인 Byte를 쓰는 게 아닌가 한다.
유의미한 결과는 못 찾았고, 아래 사이트만 찾았다.
A collection of bytes is the simplest way to represent an image file as data. A string would not be suitable as it contains character codes, and an image file does not consist of characters. There is no special class for holding the data of an image file, as a byte array works just fine for that.
Any file can be treated as a collection of bytes, so a byte array is the result of reading a file as binary data. A file can also be decoded as a specific format, like a text file which results in a string, or a compressed image format (JPEG, GIF, PNG et.c.) which results in a Bitmap object containing the decompressed image.
이미지 뿐만 아니라 모든 파일은 바이트로 처리할 수 있다. 일단 이 정도만 알고 넘어가자. 나중에 이미지 처리 책을 한 번 찾아봐야겠다.
자바에서는 length와 size라는 길이를 구하는 함수를 제공하고 있다. 또한 byte로 변환하는 함수도 있어서 변환 후 length 체크하는 식으로 구할 수 있다.
찾아보니 “{기본자료형의 래퍼클래스}.BYTES” 로도 쓸 수 있는 모양이다.
당연히 다른 자료형을 아래처럼 초기화하는 것은 오류가 난다.
당연히 오류가 난다. 쌍따옴표는 String을 뜻하기 때문이다.
Java는 2Byte를 사용하는 유니코드 문자 체계를 사용하기 때문이다. C 언어같은 경우엔 ASCII 코드를 사용하기 때문에 char가 1Byte이다.
if문에서 논리적으로 0은 false로, 1은 true로 사용되지만, boolean과 int는 다른 형이기 때문에 숫자를 넣어줄 수는 없다. (자동 형 변환은 안된다)
C언어에서는 초기화하지 않으면 쓰레기 값이 들어가므로 반드시 초기화해주는 것이 좋았다. 그렇다면 기본값을 넣어주는 자바에서는 왜 초기값을 선언해주는게 좋을까?
지역 변수의 경우에는 자동으로 기본값을 넣어주지 않으므로, 미연의 사고를 방지하기 위함인 것 같다.
그리고 개인적인 생각이지만, 초기값을 선언해주는게 프로그램을 이해하는데 더 편리할 거 같다. ‘이 변수는 기본값이 이거구나’ 하는 게 가시적으로 보이니까.