본문 바로가기

언어/Java

[Java] 변수

변수란 ? 단 하나의 값을 저장할 수 있는 메모리 공간


int age; -> [int = 변수]  [age = 변수이름]


변수는 반드시 초기화하자 -> 초기화를 하지 않으면 다른 프로그램에 의해 저장된 알수없는 쓰래기값이 남아 있을 수 있기 때문

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


변수 선언 법칙
1.클래스 이름의 첫 글짜는 항상 대문자로 한다..
-변수와 메서드의 이름의 첫 글자는 항상 소문자로 한다.
2. 여러 단어로 이루어진 이름은 단어의 첫 글자를 대문자로 한다 
-(Camel case) lastIndexOf, StringBuffer
3. 상수의 이름은 모두 대문자로 한다. 여러 단어로 이루어진 경우 '_'로 구분한다.
- PI, MAX_NUMBER

변수 - (기본형)  or (참조형)
기본형 변수 - 실제 값을 저장
참조형 변수 - 어떤 값이 저장되어 있는 주소(memory address)를 값으로 가짐

참조형 변수는 변수이름 앞에 타입으로 클래스이름을 적는다
ex) 클래스이름 변수이름;
Date클래스 타입의 참조변수 today를 선언
ex) Date today = new Date(); -> Date객체를 생성해서, 그 주솔르 today에 저장 *참조형 변수는 null 또는 객체의 주소(4 byte, 0x0 ~ 0xffffffff)를 값으로 가짐

메모리공간
논리형 - boolean(1byte)
문자형 - char(2byte)
정수형 - byte(1byte), short(2byte), int(4byte), long(8byte)
실수형 - float(4byte), double(8byte)

자료형이 가질 수 있는 값의범위 - 2의 n-1승 ~ 2의 n-1승 -1 (여기서 n은 bit값)

상수 - final을 붙임. , 상수는 선언과 동시에 초기화해야함 , 선언 후에 상수 값 변경 불가
ex) final int MAX_NUM = 10;

리터럴 - '상수' 의 다른이름, 그 값자체 ex) final int MAX_VALUE = 100;
                                        여기서의 MAX_VALUE가 상수이고, 100이 리터럴이다.

실수타입 float는 리터럴에는 'f'를 반드시 붙여야한다.
double은 기본자료형이라서 접미사 d의 생략이 가능.
실수형 리터럴인데, 접미사가 없으면 double타입 리터럴임.
long형도 마찬가지! 접미사에 l, L을 붙이자.

저장범위가 넓은 타입에 좁은 타입의 값을 저장하는것이 허용!
int i = 'A'; -> int형 변수에 문자 'A'의 유니코드인 65가 저장.
long l = 123; -> 가능하다. int보다 long타입이 범위가 더 넓음
double d = 3.14f; -> 가능하다. double타입이 float보다 범위가 더 넓다.

저장범위가 좁은 타입에 넓은 타입의 값을 저장하는것은 불가!
에러 )
int i = 0x123456789;  //int 타입의 범위를 넘는다.
float f = 3.14;     //float타입보다 double타입의 범위가 더 넓다.

* 내가 생각 못한것
String str = "" 가능, 내용이 없는 빈 문자열이다.
char ch = ''; 에러, 문자리터럴은 반드시 ''안에 하나의 문자가 있어야함.
char ch = ' '; 가능, 공백문자로 변수 ch를 초기화했음.
String name = new String("Java"); -> String객체를 생성한것. 이표현도 가능.

어떤 타입의 변수라도 문자열과 덧셈연산을 수행하면 그 결과가 문자열이 된다.
ex) 문자열 + any type -> 문자열 + 문자열 -> 문자열
    any type + 문자열 -> 문자열 + 문자열 -> 문자열

7 + 7 + ""     -> 결과는 "14" 덧셈연산자는 왼 -> 오른 방향으로 연산 수행
"" + 7 + 7     -> 결과는 "77" 문자열로 변환된뒤 문자열끼리 더해짐
7과 같은 기본형 타입의 값을 문자열로 변환할 때는 빈문자열("")을 더해주면 됨.

'지시자'는 printf()를 통해 변수의 값을 여러가지 형식으로 변환하여 출력해주는 기능.  %d, %f, %s 등등
%o -> 8진수, %x -> 16진수, %s -> 2진수

비트와 바이트
1bit -> 컴퓨터가 저장 할 수 있는 최소단위
8bit = 1byte -> 데이터의 기본 단위
4byte = 1word -> CPU가 한번에 처리할 수 있는 데이터의 크기
워드는 cpu성능에 따라 다름 - 32비트 cpu에서 1워드는 32비트(4바이트), 64비트 cpu에서 1워드는 64비트(8바이트)

n비트로 표현할 수 있는 10진수
값의 개수 : 2의 n승
값의 범위 : 0 ~ 2의 n승 -1

1의 보수법
예를들어 4비트짜리 양수에서 첫번째 비트(MSB)만 1로 바꾸면 음수로 변환되는 장점이 있지만
1111(-7), 0111(7)을 더했을때 0 이 되지 않는 단점이 있고, 0이 두개 (0000, 1000) 존재하는 단점이 있다.

2의 보수법
부호 신경쓰지 않고 덧셈 가능, 
1111(-7), 0111(7)을 더했을때 자리올림 발생하여, 올림되는 수가 버려지고, 0으로 됨.ㅌㅌ

n의보수 -> 더했을때 n이되는수
7의 '10의 보수' 는 3

절대값이 같고 부호가 다른 두 10진수를 표현하는것을 '2의 보수법'이라고 함.
음수의 2진 표현을 구하는 방법
(1) 음수의 절대값을 2진수로 변환한다
(2) (1)에서 구한 2진수의 1을 0으로, 0은 1로 바꾼다. -> 1의보수를 구함.
(3) (2)에서 구한 결과에 1을 더한다. -> 1의보수에 +1을한것이 2의보수
 

기본형(primitive type)
논리형 - boolean 
문자형 - char
ex)char ch = 'A';   -> 컴퓨터는 숫자밖에 모르기 때문에 모든 데이터를 숫자로 변환하여 저장됨. 65값이 ch공간에 들어감
    char ch = 65; -> 이거와 결과가 같다.
만일 어떤 문자의 유니코드를 알고싶다면 char형 변수에 저장된 값을 정수형으로 변환하면 됨
ex) int  code = (int)ch;


인코딩과 디코딩
'A' -> 65 (인코딩과정)
65 -> 'A'(디코딩과정)
유니코드로 인코딩 디코딩하는것임!!
문자를 코드로 변환하는 것을 '문자 인코딩' -> 문자를 저장할 때 인코딩을 해서 숫자로 변환되어 저장.
코드를 문자로 변환하는 것을 '문자 디코딩' -> 저장된 문자를 읽어올 때는 디코딩을 해서 숫자를 원래의 문자로 되돌림.

ASCII -> 아스키코드로서 아스키는 128개(2의 7승)의 문자집합을 제공하는 7bit부호.
확장 아스키 -> 7bit에서 1bit가 남으므로 남는 공간을 활용해서 문자를 추가로 정의한것이 확장 아스키이다.

정수형의 표현방식 (n비트)
0, 양수 -> 2의 n-1개     0 + (n-1)비트
음수 -> 2의 n-1개        1 + (n-1)비트

8비트로 표현할 수 있는 값의 범위 -> -128 ~ 127 ( -2의 7승 ~ 2의 7승 -1)

정수형의 선택기준
JVM의 피연산자 스택이 피연산자를 4byte 단위로 저장하기 때문에 크기가 4byte보다 작은 자료형(byte, short)의 값을 계산할 때는 4byte로 변환하여 연산이 수행됨.
그래서 오히려 int를 사용하는것이 더 효율적이다.(메모리 측면에서는 byte와 short가 더 효율적 일 수 있음..)

정수형의 오버플로우
타입이 표현할 수 있는 값의 범위를 넘어서는 것을 오버플로우(overflow)라고 한다.
오버플로우가 발생했다고 에러가 발생하는 것은 아님. 다만 예상했던 결과를 얻지 못할 뿐 그러므로 충분한 크기의 타입을 선택하는것이 중요.
정수형 타입이 표현할 수 있는 최대값 + 1 -> 최소값
정수형 타입이 표현할 수 있는 최소값 - 1 -> 최대값
ex) 4bit 2진수의 최소값인 '0000'부터 '1111' 까지 계속 1씩 증가시키면 '1111'을 넘어서면 다시 '0000'이 된다. 이 범위 계속 반복.

부호있는 정수의 오버플로우
부호없는 정수는 2진수로 '0000'이 될 때 오버플로우 발생, 부호있는 정수는 부호비트가 0에서 1이될 때 오버플로우 발생.


[코드]

class PrintfEx1 {
public static void main(String[] args) {
short sMin = -32768;
short sMax = 32767;
char cMin = 0;
char cMax = 65535;
System.out.println("sMin = " + sMin);
System.out.println("sMin -1 = " + (short)(sMin-1));
System.out.println("sMax = " + sMax);
System.out.println("sMax + 1" + (short)(sMax+1));
System.out.println("cMin = "+ (int)cMin);
System.out.println("cMin-1= " + (int)--cMin);
System.out.println("cMax = " + (int)cMax);
System.out.println("cMax+1= " + (int)++cMax);
}
}


[출력결과]
sMin = -32768
sMin -1 = 32767
sMax = 32767
sMax + 1-32768
cMin = 0
cMin-1= 65535
cMax = 65535
cMax+1= 0

최소값 -1 -> 최대값
최대값 +1 -> 최소값

short와 char의 크기는 모두 16비트로 같다
short같은 경우는 절반 (양수 0) , 절반 음수를 포현하는데 사용
char같은 경우는 모두 양수와 0을 표현하는데 사용

실수형은 부호, 지수, 가수 세부분으로 이루어져 있음, 그래서 같은 비트의 float형 실수가 int형 정수보다 보다 큰 범위의 값을 저장
정수형 -> 부호(1bit) + 값(32bits)
실수형 -> 부호(1bit) + 지수부분(8bits) + 가수부분(23bits)
그러나 실수형은 오차 발생할 수 있는 단점이 있음.
float경우 정밀도가 7자리임.  -> '7자리의 10진수를 오차없이 저장할 수 있다'는 뜻.
double형은 float보다 정밀도가 약 2배인 15자리의 정밀도임. -> 훨씬 더 정밀하게 값을 표현 가능 -> double이라는 이름도 float의 2배의 정밀도이기때문에 'double'
결과적으로 실수형 타입을 선택할 때는 값의 범위 분만 아니라 '정밀도'도 고려해야 한다. 

[코드]

class PrintfEx1 {
public static void main(String[] args) {
float f = 9.12345678901234567890f;
float f2 = 1.2345678901234567890f;
double d = 9.12345678901234567890d;
System.out.printf(" 12345678901234%n");
System.out.printf("f  :  %f%n", f);
System.out.printf("f  :  %24.20f%n", f);                //24자리중 20자리는 소수점 이하의 수를 출력하라.
System.out.printf("f2 :  %24.20f%n", f2);
System.out.printf("d  :  %24.20f%n", d);
}
}


[출력결과]
12345678901234
f  :    9.123457
f  :    9.12345695495605500000
f2 :    1.23456788063049320000
d  :    9.12345678901234600000


float결과 7자리만 일치 나머지는 다른값으로 채워짐.
double결과 15자리만 일치 나머지는 다른값, 0으로 채워짐

float 는 1(부호) + 8(지수) + 23(가수) => 32bit
double은 1(부호) + 11(지수) + 52(가수) => 64bit

부동소수점수는 세부분으로 나누어 저장됨.

1. 부호(Sign bit)
부호비트는 1bit이고, 0이면 양수 1이면 음수를 의미한다.
정수형과 달리 '2의 보수법'을 사용하지 않기 때문에 양의 실수를 음의 실수로 바꾸려면 그저 부호비트만 변경하면 된다.

2. 지수(Exponent)
지수는 float경우 8bit를 가진다. 지수는 '부호있는정수'이고 8bit로는 256개의 값을 저장할 수 있으므로 -127 ~ 128의 값이 저장된다.
그 중 음의무한대, 양의무한대 와 같이 특별한 값의 표현을 위해 예약되있으므로 실제로 사용가능한 지수의 범위는 -126 ~ 127이다.

3. 가수(Mantissa)
실제값인 가수를 저장하는 부분으로 float의 경우 2진수 23자리를 저장 가능.
2진수 23자리로는 7자리의 10진수를 저장할 수 있는데 이것이 float의 정밀도가 됨.

부동소수점의 오차
실수 중에는 파이(3.141592....)와 같은 무한소수가 존재해서, 정수와 달리 실수를 저장할 때는 오차가 발생할 수도 있다.
10진수로는 유한소수여도 2진수로 변환하면 무한소수가 되는 경우도 있다.
즉, 무한소수를 저장할 때 오차가 발생하는것이 부동소수점의 오차이다.


형변환
형변환이란, 변수 또는 상수의 타입을 다른 타입으로 변환하는 것.
int타입 + float타입의 경우 먼저 두 값을 같은 타입으로 (float)타입으로 변환 후 더해야 한다.
방법 - (타입)피연산자
여기서 사용하는 괄호는 '캐스트연산자' 또는 '형변환연산자'라고 하며, 형변환을 '캐스팅'이라고도 한다.

큰타입에서 작은타입으로 형변환 될 경우 값손실이 발생할 수 있다.
ex) '300'이라는 int값을 byte로 변경할 경우 '44'가된다. (32bit)가 (8bit)가 되면서 잘려나가는 부분때매 발생

작은타입을 큰타입으로 변환할 경우 값손실은 발생하지 않는다.
변환시 원래값을 채우고 남은 빈공간을 0으로 채우는게 보통이지만 변환하려는 값이 음수일 경우는 빈공간을 1로 채운다.

보통 기존의 값을 최대한 보존할 수 있는 타입으로 자동 형변환된다.






'언어 > Java' 카테고리의 다른 글

[Java] 자바란 무엇인가?  (1) 2017.11.23

Today :
Yesterday :
Total :