변수(Variable)

프로그래밍언어에서의 변수는 값을 저장할 수 있는 메모리상의 공간

이렇게 저장된 값은 변경될 수 있기 때문에 수학적의미의 '변수'와 상통한다.

하나의 변수에는 하나의 값만 저장할 수 있으므로 새로운 값을 저장하면 기존의 값은 사라진다.

 

 

1. 변수 선언

변수에 맞는 자료형과 변수 이름으로 선언한다.

int n; //정수형 변수 타입 int

 

 

 

 

2. 변수의 초기화(Initialization)

변수를 선언한 하고 변수를 사용할 수 있지만, 그 전에 반드시 변수를 초기화해야한다. 메모리는 여러 프로그램이 공유하는 자원이므로 전에 다른 프로그램에 의해 저장된 알수없는 값(쓰레기값, garbage value)가 남아 있을 수 있기 때문이다.

대입연산자 '=' 를 사용하여 변수에 값을 저장한다. 

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

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

int n; //변수 선언
n=1; //초기화
int m = 2; //변수선언,초기화

변수선언과 초기화는 동시에 할 수도 있다.

 

 

 

 

3. 변수 명명 규칙

변수의 이름처럼 프로그래밍에서 사용하는 모든 이름을 식별자(identifier) 라고 한다.

식별자는 같은 영역내에서 서로 구분이 되어야 하고, 아래 규칙을 지켜야 한다.

 

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

2) 예약어는 사용 불가능하다.

(예약어 : 컴퓨터 프로그래밍 언어에서 이미 문법적인 용도로 사용되고 있기 때문에 식별자로 사용할 수 없는 단어)

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

3) 숫자로 시작할 수 없다.

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

 

+ 필수적이지는 않지만 권장되는 규칙들

1) 클래스 이름 첫글자는 대문자로 하고 변수와 메서드 이름의 첫글자는 소문자로 한다.

2) 여러 단어로 이루어진 이름은 단어의 첫글자를 대문자로 한다.

3) 상수의 이름은 모두 대문자로한다. 여러 단어로 이루어진 경우 _로 구분한다.

 

 

 

 

4. 변수의 타입 - primitive type, reference type

주로 사용하는 데이터(값)의 종류(type)은 크게 문자와 숫자로 나눌 수 있고, 숫자는 다시 정수와 실수로 나눌 수 있다. 이러한 데이터 타입에 따라 값이 저장될 공간의 크기와 저장형식을 정의한 것이 자료형(data type) 이다.

 

데이터 형태 - 정수 실수 문자 논리

정수 : 양수,음수,0

실수 : 소수점이 추가 된 형태

문자 : 한글자

논리 : 참(true), 거짓(false)

 

자료형 변수는 기본형과 참조형으로 나눌 수 있다.

기본형 변수는 실제값(data)를 저장하고 참조형변수는 어떤값이 저장되어있는 주소(memory address)를 값으로 가진다.

자바에서는 참조형 변수간의 연산을 할 수 없기 때문에 실제 연산에 사용되는 변수는 모두 기본형이다.

자료형(data type) 기본형(primitive type) 계산을 위한 실제 값을 저장한다. 
할당되는 메모리 크기가 정해져있기 때문에 최대/최소값이 정해져 있다. 고정형이라고도 한다. 
논리형(boolean), 문자형(char), 정수형(byte,short,int,long), 실수형(float,double). 모두 8개
참조형(reference type) 저장된 데이터가 있는 메모리 주소(위치)를 저장한다. 
primitive type 8개 기본형을 제외한 나머지 타입

 

기본형은 8개이고, 참조형은 만들어서 추가할 수 있기 때문에 정해진 개수가 없다.

기본형은 실제 값을 저장하지만 참조형은 값을 가지고 있는 메모리 주소를 저장한다.

기본형은 타입마다 크기가 다르고 정해져있다.

 

참조형은 타입에 관계없이 메모리주소를 4byte 만큼 저장할 수 있다. (32bit JVM)

메모리 주소 4byte로 표현할 수 있는 최대값은 40억byte로 4GB정도를 저장가능하다.

64bit JVM 에서는 8byte 메모리 주소 저장 가능하다. 

 

 

기본형 변수의 메모리 크기, 숫자 범위

정수형의 default type은 int / 실수형의 default type은 double이다.

 

1byte 는 8bit이고 1bit는 0이나 1이 들어갈 수 있는 2진수 한자리를 저장하는 공간이다. 8bit에서 나올수 있는 숫자는 2^8개이고 이것이 부호가 없는 정수 (양수)만 저장된다면 0부터 2^8-1까지 될 것이다. 음수를 포함한 부호가 있는 정수를 저장한다면 -2^7부터 2^7-1까지 저장할 수 있다.

이러한 방식으로 데이터타입마다 정해진 범위를 확인할 수 있다.

 

type 타입명 저장 크기 저장 가능한 최소값 저장 가능한 최대값
정수형 byte 1byte (8bit) 2^7 2^7-1
  short 2byte (16bit) -2^15 2^15-1
  int 4byte (32bit) -2^31 (약 -20억) 2^31-1 (약 20억)
  long 8byte (64bit) 2^63-1 2^63-1
실수형 float 4byte / 정밀도 7자리 -3.4e38 ~ -1.4e-45
1.4e-45 ~ 3.4e38
  double 8byte / 정밀도 15자리 -1.8e308~ -4.9e-324
4.9e-324 ~ 1.8e308
문자형 char 2byte (8bit) u0000
0
uFFFF
65535 (2^7-1)
논리형 boolean 1byte    

 

 

실수형 float는 4byte로 32bit이다. int와 같은 4byte인데 저장범위가 훨씬 큰 것을 확인할 수 있다. 

float는 값을 부호, 지수, 가수로 나누어서 저장된다.

3.4e38(3.4*10^38)에서 가수는 3.4 / 지수는 38을 의미한다. 이 값들을 따로 저장하기 때문에 int보다 더 큰 값을 저장할 수 있다.

 

정밀도

실수형에는 정밀도라는 것이 있다.

실수형은 원래 저장하려던 값과 실제로 저장된 값 사이에 오차가 발생할 수 있는데, 정밀도란 값을 몇자리까지 오차없이 정확하게 표현할 수 있는지를 의미한다. (오차없는 자리수)

정밀도 이후의 자리수에 나오는 숫자는 의미없는 수이다.

float는 7자리까지 오차없이 표현할 수 있다. double의 정밀도는 15자리로 정밀도가 중요할 때는 double을 사용하는 것이 낫다. 실수형의 기본타입은 double이다.

 

 

 

참조형 변수 , 참조변수 : 생성되는 인스턴스의 주소 값을 저장하는 변수

primitive type인 char은 하나의 문자를 저장할 수있는 2byte (16bit) 기본형 변수이다.

eference type인 String은 문자열을 저장하는 클래스이고 참조형변수를 선언할 수 있다. 아래 코드를 통해 String에 대해 자세히 알아보도록 한다.

String str1 = "Exit"; //str1:"Exit"문자열 있는 메모리주소 저장
String str2 = new String("Exit"); //메모리를 새로 만들었다.
//String은 기본형변수가 아니라 참조형변수이다. 값이 저장되는 것이 아니고 값이 저장된 메모리 주소를 가지고 있는 변수이다.
//같은 값이 들어가도 새로운 String 인스턴스를 생성했으므로 메모리를 새로 만들고, 새로운 메모리에 값을 저장하게 된다.

System.out.println(str1);
System.out.println(str2);
//출력되는 값은 모두 Exit로 동일하다.

System.out.println(str1==str2); //false
//str1,str2를 같은지 비교해보았다. 정수로 되어있는 메모리주소가 각자 다르기 때문에 false가 나오게 된다.	

System.out.println(str1.equals(str2)); //문자열 동일, true
//참조형변수를 ==으로 비교하면 메모리주소 비교였다. 
//참조형변수가 저장하고 있는 주소에 있는 문자열을 비교하기 위해 equals를 사용했고 문자열이 동일함을 확인했다.

기본형 변수를 제외하면 모두 참조형변수이다. 참조형변수를 선언할 때는 변수타입으로 클래스 이름을 사용하므로 클래스이름의 참조변수의 타입이 되는 것이다. 위에서는 String 클래스가 참조형 변수의 타입이 된 것이다.

클래스이름 변수이름; 으로 선언한다.

String 클래스에서 인스턴스를 생성할 때 new String을 써도 되지만 String 같은 클래스는 바로 문자열을 입력할 수 있도록 설정되어 있다. 이와 동일하게 Integer(정수 저장)와 같은 클래스 또한 바로 값을 입력하면 인스턴스가 생성된다. 

 

Date today = new Date();

Date 클래스 타입의 참조변수 today를 선언한 것이다. Date 객체를 생성해서 그 주소를 참조변수 today에 저장하였다.

 

 

 

5. 형변환, 자동형변환

형변환(casting, 캐스팅)이란 변수 또는 상수의 타입을 다른 타입으로 변환하는 것이다. 형변환은 변환하고자 하는 타입을 괄호로 붙여주기만 하면 된다. 형변환 후 결과를 반환할 뿐 피연산자인 변수의 값은 형변환 후에도 변화가 없다. 실수형은 정수형보다 큰 저장범위를 가지기 때문에 정수형을 실수형으로 변환하는 것은 무리가 없지만 실수형을 정수형으로 변환하면 소수점 이하 값은 버려진다. 

 

서로 다른 타입간의 대입이나 연산을 할 때 형변환으로 타입을 일치시키는 것이 원칙이지만 편의상의 이유로 형변환을 생략할 수 있다.

컴파일러가 생략된 형변환을 자동으로 추가하는데, 변수가 저장할 수 있는 값의 범위보다 더 큰 값을 저장하려는 경우에는 값 손실이 발생할 수 있기 때문에 형변환을 생략하면 에러가 발생한다. 

기존의 값을 최대한 보존할 수 있는 타입으로 자동형변환된다. 표현범위가 좁은 타입에서 넓은 타입으로 형변환 하는 경우에는 값 손실이 없기 때문에 더 넓은 쪽으로 형변환 된다.

 

byte -> short -> int -> long -> float -> double

char -> int -> long -> float -> double

방향으로  자동형변환 가능하다.

 

1) boolean을 제외한 나머지 7개 기본형은 서로 형변환이 가능하다.

2) 기본형과 참조형은 서로 형변환할 수 없다.

3) 서로 다른 타입의 변수간의 연산은 형변환을 해야하는 것이 원칙이지만 값의 범위가 작은타입에서 큰 타입으로의 형변환은 생략 가능하다.

 

 

 

 

6. 선언위치에 따른 변수의 종류

변수의 종류를 결정짓는 요소는 '변수의 선언된 위치'이기 때문에 변수가 어느 영역에 선언되었는지를 확인해야 한다.

변수 선언위치  
멤버변수 클래스 클래스변수, 인스턴스변수
지역변수 메서드  

선언위치가 클래스영역이면 멤버변수, 선언위치가 메소드나 생성자내부라면 지역변수이다.

멤버변수 중에 static이 붙은 것은 클래스변수, 붙지 않은 것은 인스턴스변수이다.

 

* 클래스, 인스턴스, 객체 ? 

객체(Object) : 소프트웨어 세계에 구현할 대상, 클래스에 정의댄 대로 메모리에 생성된 것

클래스(Class) : 객체를 생성하기 위한 설계도, 틀

인스턴스(Instance) : 설계도에 따라 구현된 실체

 

 

1) 멤버변수 : 클래스 영역에 선언된 변수 - 인스턴스 변수, 클래스 변수

1-2) 인스턴스 변수

인스턴스변수는 클래스 영역에 선언되고, 클래스의 인스턴스를 생성할 때 만들어진다. 그래서 인스턴스 변수의 값을 읽어 오거나 저장하기 위해서는 먼저 인스턴스(객체)를 생성해야 한다. 객체는 인스턴스 변수를 묶어놓은 것이라고 할 수 있다.

인스턴스는 독립적인 저장공간 가지며 서로 다른 값 가질 수 있다.

인스턴스마다 서로 다른 고유한 상태를 유지해야하는 속성은 인스턴스 변수로 선언한다.

 

 

1-3) 클래스변수 (static + 인스턴스변수)

클래스변수는 클래스 영역에 선언되고, 인스턴스변수 앞에 static을 붙이면 된다. 모든 인스턴스가 공통된 저장공간(변수)를 공유하므로 모든 인스턴스들이 공통된 값을 유지해야하는 속성은 클래스 변수로 선언한다. 

클래스변수는 인스턴스(객체)를 생성하지 않고도 언제든지 바로 사용할 수 있다. (클래스이름.클래스변수)

public을 앞에 붙이면 같은 프로그램 내에서 어디서나 접근할 수 있는 전역변수(global variable) 성격을 가진다.

참조변수의 선언이나 객체의 생성과 같이 클래스의 정보가 필요할 때 클래스는 메모리에 로딩되고, 메모리에 로딩될 때 클래스변수가 생성되어 프로그램이 종료될 때까지 유지된다.

 

 

1-4) 인스턴스 변수 & 클래스 변수

클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하는 공통된 값, 인스턴스 변수는 인스턴스가 생성될 때마다 다른 값이다.

class Card {
	String kind ;			// 카드의 무늬 - 인스턴스 변수
	int number;			// 카드의 숫자 - 인스턴스 변수
	static int width = 100;		// 카드의 폭  - 클래스 변수
	static int height = 250;	// 카드의 높이 - 클래스 변수
}

카드 클래스를 만들었고 클래스 내에 변수를 선언해준다. 클래스 내의 변수는 클래스변수, 인스턴스변수가 있다.

모든 카드가 동일하게 가지고 있는 속성과, 카드마다 다른 속성을 구분해준다.

여러장의 카드를 각각 인스턴스로 생성할 것이고, 카드의 무늬와 숫자는 인스턴스(카드)마다 달라질 것이다. 무늬와 숫자는 인스턴스 변수로 선언한다.

모든 카드가 동일하게 가지는 속성인 카드의 폭, 높이는 static을 붙여서 클래스 변수로 선언한다.

 

인스턴스변수는 인스턴스를 생성해야 값을 저장할 수 있기 때문에 클래스영역에서 선언만 되는 것이고, 인스턴스 생성 후 개별 값을 저장해야한다.

 

클래스 변수는 인스턴스를 생성하지 않고도 '클래스이름.클래스변수' 같은 방식으로 직접 사용할 수 있다.

모든 인스턴스는 클래스 변수를 공유하고, 한 인스턴스의 클래스변수 속성값만 변경해도 모든 인스턴스에 반영된다.

class CardTest{
public static void main(String args[]) {
System.out.println("Card.width = "  + Card.width); //Card.width=100 출력
System.out.println("Card.height = " + Card.height); //Card.height=250 출력
//width, height는 card클래스에서 클래스변수로 선언후 값을 넣어주었다.
//클래스변수는 객체 인스턴스를 만들지 않아도 사용가능하다. 
//인스턴스 만들지 않았지만 클래스명 Card와 클래스변수명 width, height 을 이용해서 클래스 변수를 사용했다.

Card c1 = new Card();
c1.kind = "Heart";
c1.number = 7;
//인스턴스를 생성하여 참조변수 c1에 저장하였다. c1 인스턴스의 인스턴스변수를 사용할 수 있게 되었다.
//인스턴스 변수인 카드무늬 kind, 카드숫자 number를 지정해주었다.

Card c2 = new Card();
c2.kind = "Spade";
c2.number = 4;
//또 다른 인스턴스를 생성하여 참조변수 c2에 저장하였다.

System.out.println("c1은 "+c1.kind+", "+c1.number+", (" + c1.width + ", " + c1.height + ")" );
System.out.println("c2는 "+c2.kind+", "+c2.number+", (" + c2.width + ", " + c2.height + ")" );		
//출력 : c1은 Heart, 7, (100,250)
//출력 : c2는 Spade, 4, (100,250)
//c1, c2 각각 객체의 width, height는 설정해주지 않았지만 card 클래스에서 선언해준 값이 동일하게 나온다.

System.out.println("c1의 width와 height를 각각 50, 80으로 변경합니다.");
c1.width = 50;
c1.height = 80;
//한 인스턴스의 클래스변수값을 변경했다.

System.out.println("c1은 "+c1.kind+", "+c1.number+", (" + c1.width + ", " + c1.height + ")" );
System.out.println("c2는 "+c2.kind+", "+c2.number+", (" + c2.width + ", " + c2.height + ")" );	
//출력 : c1은 Heart, 7, (50,80)
//출력 : c2는 Spade, 4, (50,80)
//인스턴스는 클래스 변수를 공유한다.
//한 인스턴스의 클래스변수 값만 변경했는데, 모든 인스턴스에 적용된 것을 확인했다.
        }
 }

주석을 확인하면서 클래스변수, 인스턴스변수를 구분할 수 있다.

 

 

2) 지역변수 : 메서드 내에 선언된 변수

메서드 내에 선언되어 메서드 내에서만 사용 가능한 변수이다. 메서드가 종료되면 소멸되어 사용할 수 없다.

for, while문의 블럭 내에 선언된 지역변수는 { } 블럭 내에서만 사용가능 하고 { } 블럭을 벗어나면 소멸된다.

매개변수도 메서드 내에 선언된 것으로 간주하여 지역변수이다.

 

 

 

7. 변수의 초기화

변수를 선언하고 처음으로 값을 저장하는 것을 변수의 초기화 라고한다.

멤버변수(클래스변수, 인스턴스변수)는 초기화 하지 않아도 자동적으로 변수의 자료형에 맞는 기본값으로 초기화가 된다. 하지만 지역변수는 반드시 수동으로 초기화해야한다. 

 

7-1. 멤버변수 초기화 방법

1) 명시적 초기화 : 변수 선언과 동시에 대입연산자(=)를 이용하여 초기화 한다. 가장 우선적으로 고려된다.

2) 초기화 블럭 - 인스턴스 초기화 블럭 {}, 클래스 초기화 블럭 static{}

: 인스턴스변수의 복잡한 초기화는 인스턴스초기화블럭을 이용하고, 클래스변수의 복잡한 초기화는 클래스 초기화 블럭을 이요한다.

인스턴스변수 초기화 하는 방법은 두가지로 생성자보다 초기화블럭이 수행된다. 

일반적으로 클래스변수는 블럭을 이용하고 인스턴스변수는 생성자를 이용하여 초기화 한다.

3) 생성자 : 인스턴스변수 초기화 방법

 

 

7-2. 멤버변수 초기화 시기와 순서

1) 클래스변수 

클래스가 처음 로딩될 때 단 한번 초기화 된다. 클래스가 이미 메모리에 로딩되어 있으면 또다시 로딩하지 않고, 초기화도 다시 수행하지 않는다.

기본값 -> 명시적초기화 -> 클래스초기화블럭

 

2) 인스턴스변수

인스턴스가 생성될 때 마다 각 인스턴스별로 초기화가 이루어진다.

기본값 -> 명시적초기화 -> 인스턴스 초기화 블럭 -> 생성자