3.1 형변환 (casting) 이란?

서로 다른 타입의 값으로 연산을 수행해야할 때 사용한다.

형변환이란 변수 또는 리터럴의 타입을 다른 타입으로 변환하는 것이다.

 

3.2 형변환 방법

기본형과 참조형 모두 형변환이 가능하지만, 둘 사이에는 형변환이 성립되지 않는다.

형변환하는 방법은 형변환하고자 하는 변수나 리터럴 앞에 변환하려는 타입을 괄호와 함께 붙여주면 된다.

* 오토박싱 기능이 추가되면서 기본형을 Object, wrapper 클래스 같은 참조형으로 형변환 할 수 있게 되었다.

int score = (int)85.4; //double 형 값을 int 형으로 변환한다.
byte b = (byte)score; //score 에 저장된 값을 byte 형으로 변환

형변환 할 때 사용하는 괄호는 캐스트 연산자나 형변환 연산자라고 한다.

캐스트 연산자는 피연산자의 값을 읽고 지정된 타입으로 형변환 한 후에 그 결과를 반환하기 때문에 피연산자는 형변환 후에도 아무런 변화가 없다.

public class ex2 {
	public static void main(String[]args) {
		double d = 100.0;
		int i = 100;
		int result = i+(int)d;
		System.out.println(d);
		System.out.println(result);
	}
}
[실행 결과]
100.0 //형변환 후에도 변화가 없다.
200

형변환한 결과를 덧셈연산에 사용한다.

 

3.3 기본형의 형변환

boolean 형을 제외한 나머지 기본형 간에는 서로 형변환이 가능하다.

각 자료형마다 표현가능한 값의 범위가 다르기 때문에 큰 자료형에서 범위가 작은 자료형으로의 변환은 값 손실이 일어날 수 있다. 반대의 경우에는 값 손실이 절대 일어나지 않는다.

public class ex2 {
	public static void main(String[]args) {
		int a = 300;
		byte b = (byte)a;
		System.out.println(a);
		System.out.println(b);
		int c = 100;
		byte d = (byte)c;
		System.out.println(c);
		System.out.println(d);
	}
}
[실행 결과]
300
44
100
100

int 가 byte 보다 값의 표현 범위가 큰데, byte 값을 int 값으로 변환하게 되면 1 byte에서 4 byte 로 나머지 3 byte(24자리)를 0으로 채워주면 되므로 기존의 값이 그대로 보존된다. 하지만 int 값을 byte 값으로 변환하게 되면 3 byte 를 잘라내서 1 byte 로 만드는 것이기 때문에 기존의 값이 보존될 수도 있고, 안될 수도 있다.

 

값의 표현 범위가 작은 자료형에서 큰 자료형의 변환은 값의 손실이 없기 때문에 캐스트 연산자의 생략이 가능하다. 이 경우에 JVM 내부에서 형변환이 자동으로 수행된다.

반대의 경우에는 값이 손실될 수 있기 때문에 자동적으로 형변환은 진행되지 않고 캐스트 연산자를 이용하여 명시적 형변환을 하도록 강요한다. 그렇지 않을 경우 컴파일 시 에러가 발생한다.

 

기본형의 자동형변환이 가능한 방향은 byte → short (char) → int → long → float → double이다.

실수형은 정수형과 값을 표현하는 방식이 다르다. 그래서 같은 크기라도 실수형이 정수형보다 오른쪽에 위치하게 되는 것이다.

char 와 ,short 는 모두 2 byte 이지만 서로 범위가 달라 어느쪽으로 형변환을 하더라도 값 손실이 일어날 수 있기 때문에 자동적인 형변환이 이루어지지 않는다.

'JAVA > 변수' 카테고리의 다른 글

2. 변수의 타입  (0) 2019.12.13
1. 변수 (variable)  (0) 2019.12.05

모든 변수는 타입이 있으며, 타입에 따라 저장할 수 있는 값의 종류와 범위가 달라진다.

자바는 C언어와 달리 참조형 변수 간의 연산을 할 수 없으므로 실제 연산에 사용되는 것은 모두 기본형 변수이다.

 

기본형(Primitive type)

    - boolean, char, byte, short, int, long, float, double
    계산을 위한 실제 값을 저장한다.

참조형(Reference type)

    - 8개의 기본형을 제외한 나머지 타입, 객체의 주소를 저장한다.

* 참조형 변수는 null 또는 객체의 주소(4byte)를 값으로 갖는다. null은 어떤 값도 갖고 있지 않은 상태를 뜻하므로, 어떠한 객체도 참조하고 있지 않다는 것을 의미한다.

 

참조형은 직접 추가할 수 있으므로 수가 정해져 있지 않다.

참조변수를 선언할 때는 변수의 타입으로 클래스의 이름을 사용한다. 그래서 새로운 클래스를 작성한다는 것은 새로운 참조형을 추가하는 셈이다.

Date today; // 타입이 클래스이 이름인 것들은 모두 참조변수이다.

다음은 Date 클래스 타입의 참조변수 today를 선언한 것이다. 참조변수의 초기화는 다음과 같이 한다.

Date today = null;
Date today = new Date();

객체를 생성하는 연산자 new의 연산결과는 생성된 객체의 주소이다. 이 주소가 대입연산자 '=' 에 의해서 참조변수 today에 저장되는 것이다.

* 참조형 변수에는 값이 아닌 객체의 종류에 의해서 구분되므로, 자료형대신 타입이라는 용어를 사용한다.

 

2.1 기본형 (primitive type)

기본형은 논리형, 문자형, 정수형, 실수형으로 구분된다.

 

논리형 : true와 false 중 하나를 값으로 갖으며 조건식과 논리적 계산에 사용된다.

    - boolean (1 byte)

문자형 : 문자를 저장하는 데 사용되며, 변수 당 하나의 문자만을 저장할 수 있다.

    - char (2 byte)

정수형 : 정수 값을 저장하는 데 사용된다. 주로 int와 long을 사용하며, byte는 이진데이터를 다루기 위해, short는 C언어와의 호환을 위해 추가되었다.

    - byte (1 byte), short (2 byte), int (4 byte), long (8 byte)

실수형 : 실수 값을 저장하는데 사용된다. float은 부동소수점 방식으로 저장하고, double은 float보다 두 배의 정밀도를 갖는다.

    - float (4 byte), double (8 byte)

* 4개의 정수형 중에서 int형이 기본(default) 자료형이며, 실수형에서는 double이 기본 자료형이다.

 

boolean을 제외한 나머지 7개의 자료형은 서로 변환이 가능하기 때문에 연산이 가능하다. 특히 char는 내부적으로 문자를 정수값 코드로 저장하기 때문에 정수형과 밀접한 관련이 있다.

 

정수형이 가지는 값의 범위는 $-2^{n-1}$ ~ $2^{n-1}-1$ (n은 bit 수가 들어간다) 정도로만 기억한다.

예를 들어, int 형의 경우 32bit 이므로 $-2^{31}$ ~ $2^{31}-1$ 의 범위를 갖는다.

따라서 int형은 대략 9자리 수의 값을 저장할 수 있다. 만약 int와 float의 범위를 넘는 값을 다루게 된다면, long과 double을 사용하면 된다.

* 실수값을 저장할 때는 값의 범위 뿐만 아니라 정밀도도 고려해야 한다.

 

2.2 논리형 - boolean

boolean형 변수에는 true와 false 중 하나를 저장할 수 있으며, default는 false이다. 주로 yes/no, on/off 와 같은 논리구현에 사용되며, 두 가지 값만 표현하기 때문에 가장 작은 1 byte이다.

* 2가지 값만 표현하기 때문에 1 bit만으로 충분하지만 데이터를 다루는 최소 단위가 1 byte기 때문에 1 byte로 지정.

 

아래 문장은 power라는 boolean형 변수를 선언하고 ture로 변수를 초기화 했다.

boolean power = true;

* 자바에서는 대소문자를 구별하기 때문에 TRUE와 true는 다른 것으로 간주한다.

 

2.3 문자형 - char

C언어 같은 언어는 문자형의 경우 확장된 아스키 코드를 사용하여 1 byte의 크기를 갖지만, 자바에서는 유니코드를 사용하여 2 byte의 크기를 갖는다.

char 형의 크기는 2 byte이므로 16진수로 0000부터 ffff까지 65536($2^{16}$)개의 코드를 사용할 수 있으며, char 형의 변수는 이 중 하나를 저장할 수 있다.

 

예를 들어, 아래는 알파벳 'A' 의 유니코드값은 0041이므로 char 형 변수에 문자 'A' 를 저장하는 코드이다.

char firstLetter = 'A';
char firstLetter = '\u0041'; //16진수 41은 10진수로 65이다.

char 형 변수에 문자를 저장할 때는 작은따옴표('')로 문자를 둘러싼다.

 

char 형과 short 형은 크기가 모두 2 byte지만, 범위가 다르기 때문에 같은 2진 표현이더라도 실제 의미하는 값은 다를 수 있다.

char 형은 문자의 코드를 저장하므로 음수를 필요로 하지 않기 때문에 2진수로 표현했을 때 첫 번째 자리를 부호에 사용하지 않는다. 하지만 short 형은 첫 번째 자리를 부호를 표현하는데 사용하기 때문에 서로 다른 범위를 갖게 된다.

public class ex2 {
	public static void main(String[]args) {
		char ch = 'A';	     //'\u0041'로 바꿔써도 같다.
		int code = (int)ch;  // ch에 저장된 값을 int형으로 변환하여 저장한다.
		System.out.println(ch);
		System.out.println(code);
	}
}
[실행결과]
A
65

char 형 변수에 저장되는 값은 부호 없는 정수의 형태로 저장된다. 위 코드에서 'A' 에는 유니코드인 65가 저장된다. 모든 데이터는 숫자로 저장되기 때문이다. println()은 값을 출력할 때 변수의 타입에 따라 정수값을 출력하거나 정수값에 해당하는 문자를 찾아 출력한다.

 

영문자 이외에 특수분자를 저장하려면 아래의 표를 보면 된다.

특수문자 리터럴 특수문자 리터럴
tab \t backspace \b
from feed \f new line \n
carriage return  \r 역슬래쉬(\) \\
작은따옴표 \' 큰따옴표 \"
유니코드(16진수)문자 \u 유니코드 ( ex : char a = '\u0041') 
public class ex2 {
	public static void main(String[]args) {
		char single = '\'';
		String dblQuote = "\"Hello\"";
		String root = "c:\\";
		System.out.println(single);
		System.out.println(dblQuote);
		System.out.println(root);
	}
}
[실행결과]
'
"Hello"
c:\

 

여러 문자를 저장하기 위해서는 String 클래스를 사용해야 한다.

덧셈 연산자를 이용하여 문자열을 결합할 수 있다.

String name = "Ja" + "va"; //name에는 "Java"가 저장된다.

 

덧셈 연산자의 피연산자 중 어느 한 쪽이 String이면 나머지 한 쪽을 먼저 String으로 변환한 다음 두 String을 결합한다.

int 와 같은 기본형 타입의 값을 문자열로 변환할 때는 빈 문자열("")을 더해주면 된다.

public class ex2 {
	public static void main(String[]args) {
		String a = 7 + "";
		String b = " " + 7;
		String c = 7 + 7 + "";
		String d = "" + 7 + 7;
		System.out.println(a);
		System.out.println(b);
		System.out.println(c);
		System.out.println(d);
	}
}
[실행결과]
7
 7
14
77

 

기본형과 참조형의 구별없이 어떤 타입의 변수도 문자열과 덧셈연산을 수행하면 결과는 문자열이 된다.

 

 

2.4 정수형 - byte, short, int, long

byte (1 byte)  <  short (2 byte)  <  int (4 byte)  <  long (8 byte)

byte 와 short 는 int 보다 크기가 작아 메모리를 절약할 수 있지만 저장할 수 있는 값의 범위가 작은 편이라서 연산 시에 범위가 넘어갈 수 있다.

또한, JVM의 피연산자 스택이 피연산자를 4 byte 단위로 저장하기 때문에 byte 나 short 의 값을 4 byte로 변환하여 연산이 수행된다. 따라서 int 를 사용하는 것이 효율적이다. 

 

정수형 변수의 선언과 초기화

byte b = 1;
short s = 2;
int f = 10;
long l = 100000000000L; // long 타입의 리터럴에는 접미사 L을 붙여야 한다.

* long 타입의 리터럴 뒤에 'L' 또는 'l' 을 붙이지 않으면 int 타입으로 간주한다.

* 리터럴은 그 자체로 데이터인 것을 말한다. 상수와 의미가 같지만, 프로그래밍에서는 상수를 '값을 한 번 저장하면 변경할 수 없는 저장공간' 으로 정의하기 때문에 이와 구분하기 위해 리터럴이라는 용어를 사용한다.

 

 

16진수를 표시하기 위해서는 리터럴 앞에 접두사 '0x' 또는 '0X' 를 붙이고, 8진수에서는 '0'을 붙인다.

int octnum = 010; //8진수 10, 10진수로는 8
int hexnum = 0x10; //16진수 10, 10진수로는 16

 

정수형은 0과 1로 이루어진 2진수로 저장된다.

1 byte 는 8 bit 이므로 8자리로 구성되며 $2^8$ 즉, 256가지의 값을 표현할 수 있다.

모든 정수형은 0을 포함한 양수와 음수를 저장하는 값의 범위로 하기 때문에, 왼쪽에서 첫번째 자리를 부호자리로 사용한다. 그래서 1 byte 가 실질적으로 값을 표현할 수 있는 자리수는 7개가 된다.

[실행결과]
123	123
124	124
125	125
126	126
127	127
-128	128
-127	129
-126	130
-125	131
-124	132

위 실행결과에서 왼쪽은 byte, 오른쪽은 int 형 타입의 값이 270까지 증가한다. 하지만 byte 의 표현 가능한 정수의 범위는 127까지이기 때문에 오버플로우(overflow) 가 발생하여 최소값부터 다시 반복된다. 에러없이 실행되긴 하지만 원하는 결과를 얻을 수 없다.

그러나 변수의 범위를 넘는 값으로 초기화하게 된다면 컴파일했을 때 에러가 발생한다.

 

 

2.5 실수형 - float, double

float는 4 byte, double 은 8 byte로 int 와 long의 크기와 같지만, 정수형과는 저장방식이 달라, 훤씬 더 넓은 범위의 값을 표현할 수 있다.

실수형은 부동소수점 방식으로 저장된다. 

부동소수점 : $\pm a\times10^n$ 의 형태로 표현되는데, a는 가수이고, n은 지수이다. 가수 a는 $0\le a<1$ 범위의 실수이다.

예를 들어, 3.1415를 부동소수점 방식으로 표현하면 $0.31415\times10^1$ 이며, 가수는 0.31415이고, 지수는 1이다.

float은 32 bit(4 byte) 중 S(부호)는 1, E(지수)는 8, M(가수)는 23으로 자리수가 할당되어 있다. 그에 비해, double은 64 bit(8 byte)는 S(부호)는 1, E(지수)는 11, M(가수)는 52로 자리수가 할당되어있다. 즉, double이 float 보다 가수가 두 배 이상으로 자리수가 배정되어 있기 때문에 정밀도(소수점 이하의 자리수)가 더 높은 값을 표현할 수 있다.

float은 가수를 10진수로 8자리 정도만 표현할 수 있기 때무네 높은 정밀도 계산에서는 double을 사용해야 한다.

 

public class ex2 {
	public static void main(String[]args) {
		float f = 1.2345678901234567890f;
		float f2 = 0.100000001f;
		double d2 = 0.100000001;
		System.out.println(f);
		System.out.println(f2);
		System.out.println(d2);
	}
}
[실행결과]
1.2345679  //끝자리에서 반올림되었다.
0.1
0.100000001

f2가 0.1로 출력된 이유는 저장된 값이 표현할 수 있는 가수의 자리수(정밀도)를 넘었기 대문이다.

float 형 리터럴에는 접미사 f가 사용되고, double은 d가 사용된다.

* 접미사는 대소문자를 구분하지 않는다.

 

float tpi = 3.14f; //f 대신 F 사용 사능
double velocity = 3.0e5d; //d 대신 D, e 대신 E 사용 가능
double rate = 1.618; //접미사 d 생략 가능

실수형에서는 double 이 기본 자료형이기 때문에 접미사를 생략하면 double 형 리터럴로 간주된다.

 

float pi = 3.14; //에러. float 변수에 double 형 리터럴을 저장할 수 없다.

* 리터럴에 접미사가 붙는 자료형은 long, float, double 인데, double 은 생략가능하므로, long 과 float에만 잘 붙이면 된다.

 

리터럴에 소수점이나 10의 제곱을 나타내는 E, e, 접미사 f, F, d, D, l, L 을 포함하면 실수형 리터럴로 간주된다.

 

'JAVA > 변수' 카테고리의 다른 글

3. 형변환  (0) 2019.12.19
1. 변수 (variable)  (0) 2019.12.05

1.1 변수란?

변수란, 값을 저장할 수 있는 메모리 상의 공간을 의미한다.

값을 직접 사용하는 것보다 의미있는 이름의 변수에 저장하여 사용하는 것이 더욱 바람직하다.

변수의 값은 바뀔 수 있으며, 하나의 변수에는 단 하나의 값만을 저장할 수 있다. 따라서 값을 여러 번 저장하면 마지막에 저장한 값을 갖게 된다.

 

1.2 변수의 선언

변수를 사용하기 위해서는 먼저 변수를 선언해야 한다. 변수가 선언되면 메모리에 변수의 타입에 맞는 크기의 저장공간이 확보된다.

int number; //정수형 변수 number를 선언한다.

변수의 초기화는 변수를 사용하기에 앞서 적절한 값을 저장해주는 것을 말한다. 

int number = 10; //정수형 변수 number를 선언하고 변수의 값을 10으로 초기화한다.
int number; //정수형 변수 number를 선언한다.
number = 10; //number라는 변수에 10으로 초기화(저장)한다.

int a;
int b;
int x = 0;
int y = 0;

int a, b;
int x = 0, y = 0; //콤마를 이용해서 코드를 간결하게 할 수 있다.

변수의 종류에 따라 초기화를 생력하는 경우도 있지만, 변수가 사용되기 전에 적절한 값으로 초기화 하는 것이 좋다.

* 지역변수는 사용되기 전에 초기화를 반드시 해야 하지만, 클래스 변수와 인스턴스 변수는 초기화를 생력할 수 있다.

 

1.3 명명규칙 (naming convention)

 변수, 메소드, 클래스의 이름을 지을 때는 반드시 지켜야 할 규칙이 있다.

 

1. 대소문자가 구분되며 길이에 제한이 없다.

    - True와 true는 서로 다른 것으로 간주된다.

2. 예약어를 사용해서는 안 된다.

    - true는 예약어라서 사용할 수 없지만, True는 가능하다.

3. 숫자로 시작해서는 안 된다.

    - top10은 허용되지만, 7up은 허용되지 않는다.

4. 특수문자는 '_'와 '$'만 허용한다.

    - $harp은 허용되지만, S#arp은 허용되지 않는다.

* 예약어는 keyword, reserved word라고 하는데, 프로그래밍 언어의 구문에 사용된다. 그래서 클래서, 변수, 메소드의 이름으로 사용할 수 없다.

* 유니코드를 인식하지 못하는 OS도 있기 때문에 클래스 이름만큼은 아스키 코드로 하는 것이 좋다.

 

'JAVA > 변수' 카테고리의 다른 글

3. 형변환  (0) 2019.12.19
2. 변수의 타입  (0) 2019.12.13

+ Recent posts