변수(variable)란?
o 변수란, 단 하나의 값을 저장할 수 있는 메모리 공간을 뜻한다.
o 하나의 값만 저장할 수 있으므로 새로운 값을 저장 시 기존의 값은 사라진다.
변수의 선언과 초기화
o 변수 타입 : 변수에 저장될 값이 어떤 타입인지 지정하는 것이다.
o 변수 이름 : 변수에 붙이는 이름으로 사용할 메모리 공간이 이름을 붙여주는 것이다. 이 이름을 이용하여 값을 저장하기도 하고 값을 불러오기도 하기에 중복되어서는 안된다.
o 변수를 선언 시 메모리 빈 공간에 변수 타입에 따라 알맞은 공간이 할당되며 변수 이름을 통해 사용한다.
o 변수의 초기화란, 변수를 사용하기 전 처음으로 값을 저장하는 것이다.
o 메모리는 여러 프로그램이 사용하는 공간이기에 변수를 선언한 이후 초기화를 해주어야 한다. 이전에 다른 프로그램에 의해 알 수 없는 값(쓰레기 값 : garbage value)이 남아있을 수 있기 때문이다.
o 변수에 값을 저장할 때는 대입 연산자 '='를 이용하며 우변의 계산이 끝난 후에 수행된다.
int age = 10 + 1;
변수 명명규칙
o 변수 이름처럼 프로그래밍에서 사용하는 이름을 식별자(identifier)라고 한다. 식별자는 같은 영역 내에서 구분이 되어야 하며 다음과 같은 규칙을 가진다.
1. 대소문자 구분되며 길이 제한은 없다.
2. 예약어를 사용해서는 안 된다. (예약어 : boolean, if, int 등..)
3. 숫자로 시작해서는 안 된다.
4. 특수문자는 '_'와 '$'만 허용된다.
o 필수적인 것은 아니지만 프로그래머에게 권장되는 규칙은 다음과 같다.
1. 클래스 이름의 첫 글자는 항상 대문자로 시작한다 – 변수, 메소드 이름의 첫 글자는 소문자로 한다.
2. 여러 단어로 이루어진 이름은 단어의 첫 글자를 대문자로 한다 – 예) StringBuffer
3. 상수의 이름은 모두 대문자로 한다. 여러 단어로 이루어진 경우 '_'로 구분한다.
변수의 타입
o 값이 저장될 공간의 크기와 저장 형식을 정의한 것을 자료형(data type)이라고 하며 문자형(char), 정수형(byte, shot, int, long), 실수형(float, double) 등이 있다.
o 자료형(data type)은 기본형(primitive type)과 참조형(reference type)으로 나눌 수 있다.
- 기본형(primitive type)
계산에 사용되는 실제 값을 저장한다.
논리형(boolean), 문자형(char), 정수형(byte, short, int, log), 실수형(float, double) 모두 8개
- 참조형(reference type)
객체가 사용하는 메모리 주소를 저장한다. (8개 기본형을 제외한 나머지 타입)
참조 변수를 선언할 때는 변수 타입을 클래스 이름을 사용기에 클래스 이름이 참조변수 타입이 된다.
선언 방법 : 클래스이름 변수이름; // 기본형이 아닌 변수 타입은 모두 참조 변수이다.
기본형(primitive type)
o 기본형에는 8개의 타입이 있으며, 논리형, 문자형, 정수형, 실수형으로 구분된다.
o 타입마다 저장할 수 있는 값의 범위가 다르기에 저장할 값의 범위에 맞게 사용하면 된다.
o 정수형 int타입 변수는 대략 10자리를 저장할 수 있는데 7~9자리 수를 계산할 시에는 넉넉하게 long타입 변수를 사용하는 것이 좋다. 연산 중에 저장범위를 넘어설 경우 원치 않는 결과를 얻게 된다.
o 실수형은 정수형과 저장 형식이 달라 같은 크기라도 더 많은 값을 표현 할 수 있으나 오차가 발생할 수 있어 정밀도가 중요하다. float형식의 정밀도는 7자리, double형식의 정밀도는 15자리로 10진수로 7,15자리 수를 오차 없이 저장할 수 있다는 뜻이다.
상수와 리터럴(constant & literal)
상수(constant)
o 상수는 변수와 마찬가지로 값을 저장할 수 있는 공간이다. 그러나 변수와 달리 값을 한 번만 저장할 수 있으며 상수는 선언 이후부터는 상수의 값을 변경할 수 없다.
o 상수 이름은 모두 대문자로 하는 것이 암묵적인 관례이며 여러 단어로 이루어진 경우 '_'로 구분한다.
final int MAX_VALUE = 1000;
final int MIN_VALUE;
MAX_VALUE = 100; //에러. 상수의 값은 변경할 수 없다.
MIN_VALUE = 200;
리터럴(literal)
o 원래 12,100'A'와 같은 값들이 상수라고 불리는데 프로그래밍에서는 다른 의미로 정의하였기 때문에 구분하기 위해 다른 이름인 리터럴로 불린다.
int month = 06;
final int MAX = 12;
변수(variable) : 하나의 값을 저장하기 위한 공간 -> month
상수(constant) : 값을 한 번만 저장할 수 있는 공간 -> MAX
리터럴(literal) : 그 자초로 값을 의미하는 것 -> 06, 12
리터럴의 타입과 접미사
o 변수 타입은 저장될 값의 타입에 의해 결정되기에 저장될 값인 리터럴에도 타입이 있다.
o 리터럴은 접미사를 붙여 타입을 구분하며 정수형은 long타입 -> ‘ㅣ’또는 ‘L’을 붙이고 없는 경우 int형이다.
o 실수형 리터럴은 float타입 -> 'f', double타입 -> 'd'를 붙여서 구분하며 없는 경우 double 타입이다.
float flo = 3.114; //에러, float타입에 double 리터럴 저장 불가
float flo = 3.114f;
double dou = 3.12; //접미사 d생략 가능
long ll = 145; //int형 리터럴 저장 가능
타입의 불일치
o 리터럴 타입은 변수 타입과 일치시키는 것이 일반적이지만 타입이 달라도 저장 범위가 넓은 타입에 좁은 타입을 저장하는 것은 가능하다.
int a = 'a'; // 문자 'a'의 유니코드 값이 변수 a에 저장된다.
long b= 123; // int보다 long 범위가 더 넓다.
double d = 3.14f; //float보다 double이 범위가 더 넓다.
문자 리터럴과 문자열 리터럴
o 문자 리터럴은 작은 따음표로 문자 하나만 감싼 것이고, 문자열 리터럴은 큰 따음표로 두 문자 이상을 감싼 것이다.
o 덧셈 연산자(+)는 피 연산자가 모두 숫자일 때는 두 수를 더하지만 피 연산자중 어느 한 쪽이 String이면 한 쪽을 먼저 String으로 변환 후 String 결합을 한다.
예) 7 + "7" = 77, 7+7+"" = 14, ""+7+7 = 77, 7+7+"7" = 147)
형식화된 출력 – printf()
o println()은 변수의 값을 그대로 사용하므로 값을 변환하여 출력하고 싶을 때 원하는 대로 출력할 수 없다.
o printf()는 지시자(specifier)를 통해서 변수의 값을 원하는 형식으로 변환하여 출력할 수 있다.
System.out.printf("a : %d",a); //%d 지시자를 사용하여 정수형을 입력받는다.
System.out.printf("a : %5d",a); //앞에 빈자리를 공백으로 채운다.
System.out.printf("a : %05d",a); //앞에 빈자리를 0으로 채운다.
논리형 - boolean
o boolean 변수는 true와 false 중 하나를 저장할 수 있으며 기본값은 false다.
o 자바에서는 대소문자 구별이 되기에 true와 True가 다르다. True로 초기화를 할 경우 에러가 난다.
문자형 - char
o char 변수는 문자를 저장하기 위한 변수를 선언할 때 사용하며 문자 하나만 저장할 수 있다. 사실 변수에 문자 저장되는 것 같지만 컴퓨터는 숫자밖에 모르기 때문에 유니코드인 숫자로 변환되어 실제 컴퓨터에 저장된다.
o 문자의 유니 코드를 알고 싶은 경우 리터럴 앞에 형변환을 해주면 알 수 있다.
int i = (int)'A';
char 타입의 표현형식
o char 타입은 2byte의 크기로 문자를 저장하는 변수를 선언하지만 실제로는 유니코드(정수)로 변환되어 저장되고 표현형식 또한 정수형과 동일하다. 다만 음수를 나타낼 필요가 없으므로 0~65535의 범위를 가지며 정수형의 같은 크기인 short는 -32768 ~ 32768의 범위를 가진다.
o char ch = 'A' 와 short s = 65를 저장하면 둘 다 이진수로 같은 값이 저장되나 출력 값은 'A', 65로 다른데 이는 println()에서 타입이 정수형이면 10진수로 해석하여 출력하고 문자형이면 저장된 숫자에 해당하는 유니코드 문자를 출력하기 때문이다.
인코딩과 디코딩
o 문자 인코딩(encoding) : 문자를 코드로 변환하는 것
문자 디코딩(decoding) : 코드를 문자로 변환하는 것
o 문자를 저장할 때는 인코딩하여 숫자로 변환해서 저장하고, 문자를 읽어올 때는 디코딩하여 숫자를 문자로 되돌린다.
유니코드(Unicode)
o 인터넷이 발명되면서 서로 다른 언어를 사용하는 컴퓨터 간의 문서교환이 활발해짐에 따라 인코딩을 하는 컴퓨터의 문서 교환에 어려움을 겪었다. 전 세계의 모든 문자를 하나의 통일된 문자집합으로 표현한 것이 유니코드다.
o 유니코드 인코딩에는 UTF-8, UTF-16, UTF-32 등 여러 종류가 있는데 유니코드 문자 셋(또는 character set)이라고 하며 유니코드에 포함시킨 문자들의 집합을 정의한 것이다.
o 자바는 UTF-16을 사용하고 있으며 모든 문자를 2byte 고정크기로 표현한다.
정수형 – byte, short, int, long
정수형의 표현형식과 범위
o 어떤 진법의 변수를 저장하여도 실제로는 2진수로 저장된다. 2진수를 저장하는 형식은 정수형과 실수형이 있으며 정수형 저장방식은 다음과 같다.
o 8비트로 표현할 수 있는 정수 범위 : 2^8 개( = 2^7 +2^7 )
o 8비트로 표현할 수 있는 부호 있는 정수 범위 : -2^7 ~2^7 -1개(-128 ~ 127), 최대 값에서 1을 빼는 이유는 0이 포함되기 때문이다.
정수형 선택의 기준
o 정수형을 사용할 때에는 가능하면 int형을 사용하도록 한다. Byte, short는 크기가 작아서 메모리를 절약할 수는 있지만 값의 범위가 작아 연산 시 범위를 넘어서 잘못된 결과가 나올 수 있다. 또한 JVM의 피연자 스택(operand stack)이 피연자를 4byte로 저장하기 때문에 크기가 4byte보다 작은 자료형의 값은 4byte로 변환하여 연산한다.
o 정수를 선언할 때는 int타입으로 하고, int의 범위(약 20억)를 넘어서는 수를 다뤄야 할 때는 long타입을 사용한다.
정수형의 오버플로우
o 해당 타입이 표현할 수 있는 값의 범위를 넘어서는 것을 오버플로우라고 한다.
o 오버플로우가 발생했다고 해서 에러가 발생하는 것은 아니며 최대값의 범위를 넘을 시 올림 값을 저장할 공간이 없기에 버려지고 0부터 다시 시작하게 된다. 반대로 0(최소값)에서 값을 감소 시 최대 값이 표현된다.
최대값 +1 -> 최소값, 최소값 -1 -> 최대값
부호있는 정수의 오버플로우
o 부호있는 정수는 부호비트가 0에서 1이 될 때 오버플로우가 발생한다. -8 ~ 7의 표현 범위를 같는 경우 -8에서 -1을 빼주면 7이된다.
실수형 – float, double
o 실수형도 정수형과 마찬가지로 표현 범위의 최대 값을 넘어서면 오버플로우가 발생한다. 그러나 정수형과 달리 실수형에서 오버플로우가 발생하면 변수의 값은 '무한대(infinity)'가 된다.
o 실수형은 정수형에는 없는 ‘언더플로우’가 있는데 ‘언더플로우’는 실수형으로 표현하기 힘든 아주 작은 값으로 최소값보다 작은 값이 될 경우 변수 값은 0이 된다.
o 실수형은 ‘부호(S), 지수(E), 가수(M)’로 이루어져 있어 큰 범위의 값을 저장한다. 그러나 실수형은 오차 범위가 있기에 정밀도가 중요하다. float는 7자리 10진수를 오차 없이 저장할 수 있다는 뜻이며 double은 약 2배인 15자리의 정밀도를 가진다.
o 실수형 double을 사용할 때는 값의 범위 보다는 정밀도가 필요해서 사용한다.
형변환(캐스팅, casting)이란?
o 형변환이란, 변수 또는 상수의 타입을 다른 타입으로 변환하는 것이다.
예) Int형 타입과 float타입의 값을 더할 경우 두 값을 float 타입으로 변환한 다음에 더해야 한다.
형변환 방법
o 형변환하는 방법은 변환하고자 하는 변수나 리터럴 앞에 변환하고자 하는 타입을 괄호와 같이 붙여주면 된다. 여기서 괄호()는 캐스트 연산자 또는 형변환 연산자라고 하며 형변환을 캐스팅(casting)이라고 한다.
사용 예시 : (타입) 피연산자 -> (int)3.14
o 형변환 연산자는 그저 피연산자의 값을 읽어 지정된 타입으로 형변환 후 결과를 반환하기에 피연산자인 'dd'는 형변환 후에도 아무런 변화가 없다.
자동 형변환
o 서로 다른 타입간 연산을 할 때 형변환으로 형식을 일치시키는 것이 원칙이나 편의상 생략할 수도 있다. 이럴 경우 컴파일러에 의해 자동으로 이루어진다.
o 형변환 시 값이 변수가 저장할 수 있는 값의 범위보다 작으면 상관없지만 범위 보다 더 큰 값을 저장하려는 경우 에러가 발생한다.
o 명시적 형변환은 프로그래머 실수가 아닌 의도적으로 작성한 것으로 간주하고 컴파일러는 에러를 발생시키지 않는다.
o 서로 다른 두 타입의 연산에서는 형변환으로 타입을 일치시키고 연산이 이루어지므로 연산과정에서 형변환이 자동으로 이루어진다. 두 타입 중 표현범위가 더 넓은 것으로 타입을 형변환하여 일치시킨 다음 연산을 수행하며 이렇이 하는 것이 값손실 위험이 더 적다.
float f = 1112; // int -> float 자동 형변환 (float)1112
byte b = 1000; // 에러, 범위 초과
char ch = (char)97; // 실수가 아니라는 명시적 형변환
int i = 5;
double d= 1.0 + i; // (double)i의 형변환이 생략 됨
자동 형변환의 규칙
o 자동 형변환 시 컴파일러는 기존의 값을 최대한 보존할 수 있는 타입으로 자동 형변환한다. 즉 표현 범위가 더 넓은 쪽으로 형변환을 한다.
o 형변환이 가능한 7개의 기본형을 왼쪽부터 오른쪽으로 표현할 수 있는 값의 범위가 작은 것부터 큰 순으로 나열했다. 왼쪽에서 오른쪽 방향의 변환은 형변환 연산자를 사용하지 않아도 자동 형변환이 된다. 반대 방향은 반드시 형변환 연산자를 사용해야 한다.
o char와 short은 둘 다 2byte로 크기가 같지만 char는 표현범위가 0~2^16 -1(0~65535)이고, short은 -2^15 ~2^15 -1(-32768 ~ 32768)로 서로 범위가 달라서 자동 형변환이 수행될 수 없다.
o 형변환의 규칙을 정리하면 다음과 같다.
1. Boolean을 제외한 7개의 기본형은 서로 형변환이 가능하다.
2. 기본형과 참조형은 서로 형변환 할 수 없다.
3. 서로 다른 타입의 변수 간의 연산은 형변환을 하는 것이 원칙이지만, 값의 범위가 작은 타입에서 큰 타입으로의 형변환은 생략할 수 있다.
'언어 > 자바의 정석' 카테고리의 다른 글
[자바의 정석] Chapter 6 객체 지향 프로그래밍 요약(2) (0) | 2021.02.03 |
---|---|
[자바의 정석] Chapter 6 객체 지향 프로그래밍 요약(1) (0) | 2021.02.03 |
[자바의 정석] Chapter 5 배열(Array) 요약 (0) | 2021.01.27 |
[자바의 정석] Chapter 3 연산자(Operator) (0) | 2021.01.21 |
[자바의 정석] Chapter 1 자바를 시작하기 전 (0) | 2021.01.18 |