-
2주차 과제: 자바 데이터 타입, 변수 그리고 배열객체지향 2021. 1. 19. 23:57
목표
자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을 익힙니다.
학습할 것
- 프리미티브 타입 종류와 값의 범위 그리고 기본 값
- 프리미티브 타입과 레퍼런스 타입
- 리터럴
- 변수 선언 및 초기화하는 방법
- 변수의 스코프와 라이프타임
- 타입 변환, 캐스팅 그리고 타입 프로모션
- 1차 및 2차 배열 선언하기
- 타입 추론, var
1. 프리미티브 타입 종류와 값의 범위 그리고 기본 값
프리미티브 타입, 영어로 primitive 또는 원시 타입 또는 기본형 타입 이라고 한다.
우선 타입이란 데이터 타입을 줄인 말로 자료형 이라고 한다.
그럼 데이터 타입이란 무엇일까?
컴퓨터 관점에서 타입은 데이터가 메모리에 어떻게 저장될 것이고 또 어떻게 다뤄져야 하는지에 대해 알려주는 것이다.
즉, 데이터 타입을 보면 컴퓨터에서 어떤 형태를 가지며 어떻게 처리될 수 있는지 머릿속에 그릴 수 있다.
그 중에서 프리미티브(기본형) 타입에 대해서 알아보자.
구분 프리미티브 타입 메모리 크기 기본 값 표현 범위 논리형 boolean 1byte false true, false 정수형 byte 1byte 0 - 128 ~ 127 short 2byte 0 - 32,768 ~ 32,767 int 4byte 0 - 2,147,483,638 ~ 2,147,483,647 long 8byte 0L - 9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 실수형 float 4byte 0.0F (3.4 X 10^-38) ~ (3.4 X 10^38)의 근사값 문자형 double 8byte 0.0 (1.7 X 10^-308) ~ (1.7 X 10^308)의 근사값 char 2byte(유니코드) '\u0000' 0 ~ 65,535 2. 프리미티브 타입과 레퍼런스 타입
Java에서 데이터 타입 즉 변수형은 프리미티브 타입과 레퍼런스 타입으로 나뉜다.
프리미티브 타입: 변수에 할당될 때 메모리 상에 고정된 크기로 저장되고 해당 변수가 원시 데이터의 값을 보관한다. 원시 타입 자료형은 모두 변수 선언, 초기화, 할당시 값이 저장된 메모리 영역에 직접적으로 접근한다, 즉 변수에 새 값이 할당 될 때 변수에 할당된 메모리 블럭에 저장된 값을 바로 변경한다는 뜻이다.
레퍼런스 타입: reference 참고, 참조의 뜻을 가지고 있다. 크기가 정해져 있지 않고 변수에 할당될 때 값이 직접 해당 변수에 저장될 수 없으며, 변수에는 데이터에 대한 참조만 저장된다. 변수의 값이 저장된 힙(Heap) 메모리의 주소값을 저장한다.
참조 한다는 것은 무엇일까?
여러가지 의미로 해석할 수 있겠지만, 자바 언어에서는 실제 값이 저장되어 있는 곳의 위치를 저장한 값(주소값)을 뜻한다.
참조 타입의 종류는 배열, 열거, 클래스 그리고 인터페이스가 있다.
기본 타입과 참조 타입을 구분하는 방법은 생각보다 단순하다.
저장되는 값이 실제 값 그 자체이냐 아니면 메모리의 주소값이냐에 따라 구분할 수 있다.
그럼 이 값은 어디에 저장 되는 걸까?
지난 1주자에 공부한 JVM의 Runtime Data Area이다.
그 중에서도 런타입 스택 영역과 가비지 컬렉션 힙 영역에 저장 된다.
예를 들어 다음과 같은 코드가 있다.
public class Test_01 { public static void ...{ String sex = "남자"; int age = 28; } }
레퍼런스 타입의 sex 변수와 프리미티브 타입의 age 변수는 런타입 스택 영역에 생성된다.
그리고 레퍼런스 타입의 값인 성별값(남자)과, 프리미티브 타입의 값인 나이값(28) 역시 런타입 스택 영역에 저장된다.
다만, 레퍼런스 타입의 값인 주소값이 가리키는 실제 값은 가비지 컬렉션 힙 영역에 객체가 생성된다.
그래서 값을 복사할 때 조심해야 한다.
그 이유는 래퍼런스 타입의 경우 실제 값이 아닌 주소값이 복사되기 때문이다.
보통 기본서에서는 값에 의한 복사와 참조 또는 주소에 의한 복사 라고 한다.
값에 의한 복사가 아닌 경우 두 가지 경우가 있는데 얕은 복사와 깊은 복사가 있다.
얕은 복사는 주소값을 복사하여 동일한 가비지 컬렉션 힙 영역의 객체를 참조한다.
그래서 이런 복사를 의도하지 않았을 경우 치명적인 오류가 발생할 수 있다.
깊은 복사는 프리미티브 타입에서 값에 의한 복사처럼 완전히 똑같은 새로운 객체를 만들어 복사하는 것을 뜻한다.
어느 방식이 좋다 나쁘다는 없고, 의도한 상황에 맞게 적절히 판단하여 사용해야 한다.
3. 리터럴
리터럴은 데이터 그 자체를 의미합니다. 상수와 많은 착각을 일으키고는 하는데 상수의 경우 한 번만 값을 저장 가능한 변수를 의미하고 리터럴의 경우 데이터 그자체를 의미하기 때문에 차이가 있습니다. 예를 들어 아래의 코드에서 int에 대입하는 1이 리터럴이 되는 것이며 앞에 final을 붙이면 상수가 되는 것입니다. 따라서 각각의 변수 타입에 따라 표현범위에 있는 값이 리터럴로 입력 가능합니다.
int a = 1; //리터럴은 1 final int b = 1; //상수로 선언
4. 변수 선언 및 초기화하는 방법
변수를 선언한다는 것은 메모리에 데이터를 저장할 공간을 지정해 주는 것입니다. 변수를 선언하는 방식은 아래 코드와 같습니다.
int num; //변수타입 변수명
이렇게 변수가 선언되면 변수타입에 해당하는 크기만큼 메모리에 용량이 할당됩니다.
변수의 종류
- 클래스 변수: 클래스가 참조될때 활용되어 전체 클래스에 적용
- 인스턴스 변수: 객체가 생성될때 같이 생성됩니다.
- 지역 변수: 경우에서는 메소드안에서 선언되고 메소드안에서만 사용가능합니다.
public class Car{ private int iv; //인스턴스 변수 static int cv; //클래스 변수 public void method() { int lv; // 지역 변수 } }
초기화 방식
- 명시적 초기화
//변수타입 변수명 = 초기화할 값 int num = 0;
- 생성자 활용 초기화
Car car1 = new Car(); car1.num = 1; car1.modelName = 'A'; car1.name = "KSB"; //만약 기본 생성자가 아닌 매개변수가 정해진 생성자가 정의되어 있다면 이렇게 초기화 할 수 도 있다. Car car2 = new Car(2,'B',"SKB");
- 초기화 블록을 활용한 클래스, 인스턴스 변수 초기화
public class Car{ static { } //클래스 초기화 블럭 { } //인스턴스 초기화 블럭 }
5. 변수의 스코프와 라이프타임
변수의 스코프란 변수에 대하여 접근과 변수가 존재할 수 있는 영역을 의미합니다.
이런 변수의 스코프로 구분해보면 클래스 변수, 인스턴스 변수, 지역 변수로 나누어 볼 수 있습니다. 이런 변수의 종류를 결정하는 것은 '변수가 선언된 위치'가 결정하게 됩니다.
먼저 클래스 변수와 인스턴스 변수는 클래스의 내부에 선언하여야 하는데 그 중 클래스 변수는 static을 앞에 붙여서 선언해주어야 합니다. 지역변수는 메소드 안에서 선언을 하면 지역변수로 선언되게 됩니다.
변수의 종류 선언 위치 생성시기 변수의 스코프 클래스 변수 클래스 영역 클래스가 메모리에 올라갈 때 클래스 전역 인스턴스 변수 클래스 영역 인스턴스가 생성 될 때 각각의 인스턴스 지역 변수 메소드 영역 변수 선언문이 수행되었을 때 메소드안 각각의 변수의 라이프타임은 클래스 변수의 경우 프로그램이 종료할때까지 적용되고 인스턴스 변수의 경우는 인스턴스가 참조 되고 있을때에는 유지되다가 객체를 참조하는 변수가 없을 경우 JVM의 Garbage Collector가 제거하게 됩니다. 지역변수의 경우 메소드가 끝나면 소멸되어 사용할 수 없게 됩니다.
6. 타입 변환, 캐스팅 그리고 타입 프로모션
타입 변환은 자바의 연산에 도움을 주기 위한 방법입니다.
자바에서 연산은 동일한 데이터 타입에서만 가능합니다. 하지만 프로그램을 구성하다보면 서로 다른 데이터 타입끼리의 연산이 필요로 한 경우가 있습니다. 이럴때 필요한 것이 타입 변환으로 종류로는 캐스팅(강제 형변환)과 타입 프로모션이 있습니다(자동 형변환).
먼저 타입 프로모션은 프로그램을 실행하면 자동적으로 형변환이 일어나는 것입니다. 타입 프로모션은 작은 메모리 크기의 데이터 타입을 큰 메모리 타입으로 변환시키게 됩니다. 먼저 예를 한번 들어보겠습니다.
byte a = 10; int b = a;
이런 경우에는 1byte의 byte타입을 4byte인 int에 넣기 때문에 별다른 오류나 문법의 필요없이 형변환이 자동으로 이뤄지게됩니다. 이처럼 자동 형변환이 이루어지는 순서는 다음과 같습니다.
byte(1) < short(2) < int(4) < long(8) < float(4) < double(8)
float와 double의 경우는 용량은 작지만 표현할 수 있는 값이 더 크기 때문에 자동형변환이 가능합니다.
또한 문자형을 정수로 변환하게되면 유니코드 값이 저장되게 됩니다.
다음으로 캐스팅은 타입 프로모팅이 이뤄지는 경우를 제외한 상황에 연산을 하기위해 강제로 형변환을 시켜주는 것입니다.
캐스팅의 문법은 변환시킬 변수 앞에 괄호하고 변환하고자 하는 데이터 타입을 적으면 변환시키게됩니다.
여기서 주의해야 할것은 표현할 범위가 더 작은 데이터타입으로 변환하여 넣을때 작은 데이터타입의 표현 범위를 벗어나게되면 입력한 데이터와는 전혀 다른 값이 나올수도 있어 주의해야합니다.
String a = "7410"; byte b = (byte) a;
위 그림을 보면 넣은 값은 7410이지만 강제 형변환으로 앞의 1byte가 사라져 11110010(2) 가 남게되며 첫자가 1이기 때문에 음수로 판단되어 실제값은 2의 보수인 -14라는 값이 출력됩니다.
7. 1차 및 2차 배열 선언하기
자바에서 배열의 선언은 두 가지 방법으로 가능합니다.
변수 선언에서 데이터타입 뒤에 []를 입력하는 방법과 변수 명뒤에 []를 입력하는 방법입니다.
int[] array; //가능 int array[]; //가능
이처럼 선언하면 배열은 null값을 가지고 있습니다.
이후 초기화를 하면 배열의 주소가 할당되어 사용을 할 수 있게됩니다. 초기화의 방식은 여러가지가 있습니다.
int[] array = new int[3]; // OR int[] array = {0, 1, 2}; // OR int[] array; Arrays.fill(array,1); // OR for(int i=0;i<i_array.length;i++) { array[i]=i; }
2차원 배열도 크게 다르지 않습니다. []를 추가해주는 것으로 2차원,3차원 배열을 구성할 수 있습니다.
int[][] array; //가능 int array[][]; //가능
2차원 배열의 초기화 방법입니다.
int[][] array = new int[4][3]; // OR int[][] array = [{0, 1, 2},{3, 4, 5},{6, 7, 8},{9, 10, 11}]; // OR for(int i=0;i<array.length;i++) { for(int j=0;j<array[i].length(); j++) array[j]=j; } }
8. 타입 추론, var
타입 추론이란 코드 작성당시에는 타입이 정해지지 않았지만, 컴파일러가 그 타입을 유추하는 것을 의미합니다. 자바 9까지는 generics나 lamda식에 대해서만 타입추론을 지원했지만 자바 10부터 타입추론을 지원하는 var이라는 키워드가 추가되어 자바에서도 타입추론을 사용가능하게 되었습니다. var은 지역변수로 사용해야하고 선언과 동시에 초기화가 필요합니다.
'객체지향' 카테고리의 다른 글
1주차 과제: JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가. (0) 2021.01.17 고급 객체지향 프로그래밍(3) (0) 2020.01.20 고급 객체지향 프로그래밍(2) (2) 2020.01.17 고급 객체지향 프로그래밍(1) (1) 2020.01.17