목표
자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을 익힙니다.
학습할 것
- 프리미티브(primitive) 타입 종류와 값의 범위 그리고 기본 값
- 프리미티브(primitive) 타입과 레퍼런스(reference) 타입
- 리터럴
- 변수 선언 및 초기화하는 방법
- 변수의 스코프와 라이프타임
- 타입 변환, 캐스팅 그리고 타입 프로모션
- 1차 및 2차 배열 선언하기
- 타입 추론, var
프리미티브(primitive) 타입 종류와 값의 범위 그리고 기본 값
타입 | 할당되는 메모리 크기 | 기본값 | 데이터의 표현 범위 | |
논리형 | boolean | 1 byte | false | true, false |
정수형 | byte | 1 byte | 0 | -128 ~ 127 |
short | 2 byte | 0 | -32,768 ~ 32,767 | |
int(기본) | 4 byte | 0 | -2,147,483,648 ~ 2,147,483,647 | |
long | 8 byte | 0L | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 | |
실수형 | float | 4 byte | 0.0F | (3.4 X 10-38) ~ (3.4 X 1038) 의 근사값 |
double(기본) | 8 byte | 0.0 | (1.7 X 10-308) ~ (1.7 X 10308) 의 근사값 | |
문자형 | char | 2 byte (유니코드) | '\u0000' | 0 ~ 65,535 |
프리미티브(primitive) 타입과 레퍼런스(reference) 타입
Java는 변수의 데이터 타입에 primitive type과 reference type이 존재한다
primitive type(기본형 변수)은 언어에서 사전 정의 되어있는 데이터 타입이다.
반면 reference type(참조형 변수)은 primitive type의 wrapper 객체로서 object를 상속한 객체형으로 나타난다.
기본형 변수는 실제 값을 저장하는 반면, 참조형 변수는 어떤 값이 저장되어 있는 주소를 값으로 갖는다.
Java는 C언어와 달리 String을 제외한 참조형 변수 간의 연산이 불가능하므로 실제 연산에 사용되는 것은
모두 기본형 변수이다.
빈 객체를 의미하는 Null이 존재한다.
값이 저장되어 있는 곳의 주소값을 저장하는 공간으로 힙(HEAP) 메모리에 저장된다.
문법상으로는 에러가 없지만 실행시켰을 때 에러가 나는 런타임 에러가 발생한다.
예를 들어 객체나 배열을 Null 값으로 받으면 NullPointException이 발생하므로 변수값을 넣어야 한다.
기본형 타입을 제외한 타입들이 모두 참조형 타입(Reference type)이다.
타입 | 예시 | 기본값 | 할당되는 메모리 크기 |
배열(Array) | int[] arr = new int[5] | Null | 4byte(객체의 주소값) |
열거 (Enumeration) | Null | ||
클래스(Class) | String str = "test"; Student sujin = new Student(); |
Null | |
인터페이스(Interface) | Null |
리터럴 ( literal ) - 프로그램에서 직접 표현한 값
소스 코드의 고정된 값을 대표하는 용어이다.
종류로는 정수, 실수, 문자, 논리, 문자열 리터럴이 있다.
변수 선언 및 초기화하는 방법
1. 지역 변수 초기화 : 명시적 초기화 ( 직접 대입 ) , 생성자, 클래스/인스턴스 초기화 블럭
변수를 선언하고 처음으로 값을 저장하는 것을 변수 초기화 라고 한다. 변수의 초기화는 경우에 따라 필수적, 선택적일 수도 있지만, 가능하면 선언과 동시에 적절한 값으로 초기화 하는 것이 바람직하다.
멤버 변수는 초기화를 하지 않아도 변수의 타입에 맞는 기본값으로 초기화가 이루어지지만 지역 변수는 사용하기 전에 반드시 초기화가 이루어져야 한다.
멤버 변수를 초기화 하는 방법
- 명시적 초기화( explicit initialization )
변수 선언과 동시에 초기화 하는 것을 명시적 초기화라고 한다.
가장 간단하고 기본적이면서 가장 우선적으로 고려되어야 한다.
class Car {
int door = 4; // 기본형 변수의 초기화
Engine engine = new Engine(); // 참조형 변수의 초기화
}
- 생성자 ( constructor )
- 초기화 블럭 ( initialization block )
클래스 초기화 블럭 : 클래스를 초기화하는데 사용
- 클래스를 초기화 하는데 사용한다.
- 클래스가 처음 메모리에 로딩될 때 한번만 수행한다.
인스턴스 초기화 블럭 : 인스턴스 변수를 초기화 하는데 사용
- 인스턴스 변수를 초기화 하는데 사용한다.
- 생성자와 같이 인스턴스가 생성될 때 수행된다.
- 인스턴스 초기화 블럭이 생성자 보다 먼저 수행된다.
초기화 블럭 내에는 메서드 내에서와 같이 조건문, 반복문, 예외 처리 구문 등을 자유롭게 사용할 수 있으므로,
초기화 작업이 복잡하여 명시적 초기화 만으로는 부족한 경우 초기화 블럭을 사용한다.
class InitBlock {
// 클래스 초기화 블럭
static {
}
// 인스턴스 초기화 블럭
{
}
}
인스턴스 변수의 초기화는 주로 생성자를 사용하고, 인스턴스 초기화 블럭은 모든 생성자에서 공통으로 수행되어야하는 코드를 넣는데 사용한다. 아래와 같이 모든 생성자에서 공통으로 수행되어야하는 문장들이 있을 때, 이 문장들을 각 생성자마다 써주기 보다는 인스턴스 블럭에 넣어줌으로써 코드가 보다 간결하게 작성할 수 있다.
Car() {
count++; //코드 중복
serialNo = count; //코드 중복
color = "white";
gearType = "auto";
}
Car(String color, String gearType) {
count++; //코드 중복
serialNo = count; //코드 중복
this.color = color;
this.gearType = gearType;
}
// 인스턴스 초기화 블럭을 통해 중복 제거
{
count++;
serialNo = count;
}
Car() {
color = "white";
gearType = "auto";
}
Car(String color, String gearType) {
this.color = color;
this.gearType = gearType;
}
초기화 블럭 예제 1 : 초기화 순서
예제를 통해 초기화 순서가 어떻게 진행되는지 본다.
public class BlockTest {
public static void main(String[] args) {
System.out.println("BlockTest blockTest = new BlockTest()");
BlockTest blockTest = new BlockTest();
System.out.println();
System.out.println("BlockTest blockTest2 = new BlockTest()");
BlockTest blockTest2 = new BlockTest();
}
// 클래스 초기화 블럭
static {
System.out.println("static{} class init block");
}
//인스턴스 초기화 블럭
{
System.out.println("{} : instance init block");
}
//생성자
public BlockTest() {
System.out.println("BlockTest() : constructor");
}
}
초기화 진행 순서는
클래스 초기화 블럭 -> 인스턴스 블럭 -> 생성자 순으로 초기화가 진행되고,
클래스 초기화 블럭의 경우 메모리에 로딩될 때 한번만 초기화가 이루어진다.
static{} class init block
BlockTest blockTest = new BlockTest()
{} : instance init block
BlockTest() : constructor
BlockTest blockTest2 = new BlockTest()
{} : instance init block
BlockTest() : constructor
static 초기화 블럭 ( 클래스 초기화 블럭 )
public class StaticBlockTest {
public static void main(String[] args) {
for (int i = 0; i < arr.length; i++) {
System.out.println("arr["+i+"] : " + arr[i]);
}
}
// 명시적 배열 초기화
static int[] arr = new int[10];
//클래스 초기화 블럭 : 배열의 각요소들을 random() 로 임의의 값을 채움
static {
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() * 10) + 1;
}
}
}
멤버변수 초기화
클래스 변수
- 초기화 시점 : 클래스가 처음 로딩될 때 딱 한번
- 초기화 순서 : 기본값 -> 명시적 초기화 -> 클래스 초기화 블럭
인스턴스 변수
- 초기화 시점 : 인스턴스가 생성될 때마다 각 인스턴스 별로 초기화
- 초기화 순서 : 기본값 -> 명시적 초기화 -> 인스턴스 초기화 블럭 -> 생성자
class InitTest {
// 명시적 초기화
static int cv = 1;
int iv = 1;
// 클래스 초기화 블럭
static {
cv = 2;
}
// 인스턴스 초기화 블럭
{
iv = 2;
}
// 생성자
InitTest() {
iv = 3;
}
}
( 출처 : doublesprogramming.tistory.com/73 )
배열 선언 및 초기화 하기
< 참고 자료 >
변수의 스코프와 라이프타임
Scope와 Life time
인스턴스 변수
- scope : 정적 메서드를 제외한 클래스 전체
- life time : 객체가 메모리에 남아있을 때까지
클래스 ( static ) 변수
- scope : 클래스 전체
- life time : 프로그램이 끝날 때까지 또는 클래스가 메모리에 로드 되는 동안
지역 ( local ) 변수
- scope : 선언된 블록 내에 있음
- life time : 컨트롤이 선언 된 블록을 떠날때까지
(출처 : https://www.tutorialspoint.com/scope-and-lifetime-of-variables-in-java)
타입 변환, 캐스팅 그리고 타입 프로모션
캐스팅? ( 형 변환 ) 연산자 : 특정 자료형을 다른 자료형으로 변환하는 연산자
Primitive 타입 간 변환 : 자유롭게 변환 가능, 일부 데이터 손실 가능성이 있다.
Reference 타입 간 변환 : 기본적으로 타입 캐스팅이 불가능하다.
하지만, 다형성을 이용해서 클래스 타입도 타입 캐스팅이 가능하다는 것을 알 수 있다.
단, 타입 캐스팅이 되는 조건은 상속관계여야 한다.
상속관계는 상하 관계가 존재하기 때문에,
클래스의 타입 캐스팅의 경우,
1. 부모 클래스는 명시적인 타입 캐스팅 없이 자식과 연결할 수 있다. - 업 캐스팅 ( Up-Casting )
2. 자식 클래스는 명시적인 타입 캐스팅이 있다면 부모와 연결할 수 있다. - 다운 캐스팅 ( Down-Casting )
3. 상속관계가 아니면 타입 캐스팅이 불가능하다.
public class Main {
public static void main(String[] args) {
Shape r = new Rectangle(0, 0, 10, 20);
Shape c = new Circle(0, 0, 9, 9);
System.out.println(r.getArea());
System.out.println(c.getArea());
}
}
Rectangle클래스는 Shape를 상속받았다.
다형성에 의해서 Shape=Rectangle라는 코드가 가능하다.
그러나 정확하게 말하면 이 둘의 연결은 이런 개념이 아니다.
자바에서는 왼쪽과 오른쪽을 무조건 동등하게 맞춰야한다.
이걸 항상 인식해야한다. 왼쪽 변수와 오른쪽 변수는 동등해야한다.
이는 기본타입이건 프리미티브타입이건 똑같다.
int a=5;
float f = a;
이런 코드는 아무 에러가 뜨지 않는다. 사실 위의 코드는 암묵적으로 아래와 같은 형식이 된다.
float f = (float)a;
우리가 코드를 입력하지 않아도 자동으로 타입캐스팅이된다.
클래스 관계에서는 두가지의 상황이 있다고 했다.
부모클래스가 자식과 연결되는 업캐스팅, 그리고 자식클래스가 부모와 연결되는 다운캐스팅이 있다고했다.
Rectangle은 Shape의 모든 것을 가지고 있다. 따라서 Shape=Rectangle이라는 코드가 가능하다.
이는 암묵적으로 Shape=(Shape)Rectangle이라는 코드가 된다.
그러나 반대의 경우는 조금 다르다.
public class Main {
public static void main(String[] args) {
Shape r = new Rectangle(0, 0, 10, 20);
Circle c = new Shape(0, 0, 9, 9);
System.out.println(r.getArea());
System.out.println(c.getArea());
}
}
Circle클래스는 Shape를 상속받았다. 이 경우에 실행이 안된다. 그 이유는 Circle=Shape 구문은 다운캐스팅이다.
따라서 다운캐스팅은 명시적으로 해야만한다.
public class Main {
public static void main(String[] args) {
Shape r = new Rectangle(0, 0, 10, 20);
Circle c = (Circle) new Shape(0, 0, 9, 9);
System.out.println(r.getArea());
System.out.println(c.getArea());
}
}
이 겨우 이제 에러는 나지 않는다. 이렇게 명시적으로 캐스팅해주면 된다.
정작 실행해보면 에러가 뜨는 것을 알 수 있다. 그 이유는 Circle에 연결된게 원래는 Shape이기 때문이다.
왜냐하면 Circle이 Shape보다 범위가 더 넓기 때문이다.
Shape가 아무래도 부모클래스이다보니 Circle의 클래스가 더 범위가 넓고 메소드가 다를 수 있기 때문이다.
그래서 Circle에 연결되는애도 원래는 Circle이여야 가능하다.
public class Main {
public static void main(String[] args) {
Shape r = new Rectangle(0, 0, 10, 20);
Shape sc = new Circle(0, 0, 9, 9);
Circle c = (Circle) sc;
System.out.println(r.getArea());
System.out.println(c.getArea());
}
}
여기서 보면 sc는 원래는 Circle이다. 따라서 이렇게 짜면 이제는 제대로 실행됨을 확인할 수 있다.
타입 프로모션?
원본 데이터가 담긴 데이터 타입의 표현 범위를 변환할 데이터 타입의 표현 범위가 모두 수용하지 못할 경우,
데이터 손실이 발생 할 수 있는데, 이것을 타입 캐스팅이라고 한다.
반대로 모두 수용할 수 있다면, 타입 프로모션이라고 한다.
(출처 : https://kamang-it.tistory.com/entry/Java-19타입형-변환Type-Casting)
1차 및 2차 배열 선언하기
class Main {
public static void main(String[] args) {
int[] a = {1,3,5,7};
int[][] b = {{2, 5, 3}, {4, 4, 1}, {1, 7, 3}, {3, 4, 5}};
System.out.println(a[3]); // 7
System.out.println(b[2][2]) // 3
}
}
타입 추론, var
타입 추론이란, 값을 보고 컴파일러가 데이터 타입이 무엇인지 추론한다는 것을 의미한다.
javascript 를 예로 들면, 모든 변수를 var,let,const 등을 사용해서 선언한다.
자바에서 처럼 int, long, boolean 등의 데이터 타입을 명시하지 않고 사용한다.
자바 10에 추가된 기능으로, var 키워드를 통해서 변수를 선언할 수 있게 된다.
var 를 사용할 경우, 제약 사항이 몇가지 존재한다.
1. 로컬 변수 이면서,
2. 선언과 동시에 값이 할당되어야 한다는 것이다.
다른 언어에 비해 타입 추론 개념이 늦게 도입된 이유는 자바 개발진들이 하위 호환성을 매우 중요하게 생각하며 보수적이기 때문이라고 한다.
dev.to/composite/java-10-var-3o67
'java' 카테고리의 다른 글
오버로딩과 오버라이딩 (0) | 2021.01.19 |
---|---|
자바 메모리 관리 ? (0) | 2021.01.19 |
4주차 제어문 (0) | 2021.01.12 |
3주차 과제 연산자 (0) | 2021.01.12 |
1주차 과제 JVM 은 무엇이며 자바 코드는 어떻게 실행하는 것인가? (0) | 2021.01.09 |