자바 데이터 타입, 변수 그리고 배열

Lee Seung Jae·2022년 2월 21일
0

2주차

주차마다 원래 관리를 해주어야 하는 스터디 이지만 이미 끝났으므로 공부하면 바로 포스팅을 할 계획이다.

  • 프리미티브 타입 종류와 값의 범위 그리고 기본 값
  • 프리미티브 타입과 레퍼런스 타입
  • 리터럴
  • 변수 선언 및 초기화하는 방법
  • 변수의 스코프와 라이프타임
  • 타입 변환, 캐스팅 그리고 타입 프로모션
  • 1차 및 2차 배열 선언하기
  • 타입 추론, var

primitive 타입 종류와 값의 범위 그리고 기본 값

자바의 변수 타입에는 primitive와 reference 타입 두가지가 있다.
프리미티브 타입의 경우 정수, 실수, 그리고 논리값 으로 이루어져있다.

이 변수의 타입들의 범위는 조금만 생각해보면 왜 저렇게 정해져있는지 알 수 있다.
연관성은 바로 이진수의 제곱 의 범위 이다.

1bit 당 가질수 있는 경우의 수는 2개이다. 0, 1 이렇게 말이다.
그러니까 비트가 늘어날 때마다 자연스럽게 제곱범위로 늘어나는 것이다.
근데 이것을 반으로 갈라서 음수부분, 양수 이렇게 나누기 때문에
범위는 아래 표와 같다. 근데 반이면 반이지 절대값으로 봤을때 1이 차이가 나는데
그 이유는 0 때문에 그렇다.

타입설명사이즈값의 범위기본값
byte부호 있는 정숫값8bit-128 ~ 1270
short부호 있는 정숫값16bit-32768 ~ 327670
int부호 있는 정숫값32bit-2147483648~21474836470
long부호 있는 정숫값64bit-2의63승 ~ +2의63승-10L
char유니코드 문자16bit'\u0000' ~ '\uffff'/ 0~65535'\u0000'
floatIEEE754 부동소수점수32bit(3.4 X 10-38) ~ (3.4 X 1038)의 근사값0.0d
doubleIEEE754 부동소수점수64bit(1.7 X 10-308) ~ (1.7 X 10308)의 근사값0.0d
boolean논리값1bittrue, falsefalse

프리미티브 타입과 레퍼런스 타입

프리미티브 타입은 stack에 적재가 된다.

반대로 레퍼런스 타입은 Heap내에 저장이 된다.

그래서 참조 타입 변수의 주소값에는 직접적인 값이 아니라 Heap 영역에 할당된 주소가 저장이 된다.

참조형 타입에는 클래스(Class) 안에 문자열(String) 포함, 배열(Array), 열거형(Enumeration), interface 가 있다.

int a = 10;
double b = 19.2;
Car c = new Car("제네시스", "gv80");

image
{: .text-center}

이렇게 저장이 된다고 보면 된다.

참조형 타입에는 빈 객체를 의미하는 null이 존재한다.
예를 들어 객체나 배열을 Null 값으로 받으면 NullPointException이 발생하므로 변수값을 넣어야 한다.

Literal

리터럴은 변수나 상수에 저장되는 값 그 자체이다.

위에서 보면 10이나 19.2가 그에 해당한다.

고정된 값을 표현하는 리터럴은 정수, 실수, 문자, boolean, 문자열 을 표현하는 리터럴 등이 있다.

정수형 리터럴

정수를 표현하는 리터럴은 이렇게 구성되어 있다.

int a = 10;       //10진수 리터럴
int a = 012;      //8진수 리터럴
int a = 0x1a;     //16진수 리터럴
int a = 0b110101; //2진수 리터럴

실수 리터럴

실수 타입의 리터럴은 기본적으로 double 타입이고, float 타입으로 표현하려면 f를 명시적으로 붙여야한다.

double b = 1.1;
double b = 1E-1;
float b = 1.1f; 

문자 리터럴

문자 리터럴은 작은 따옴표 안에 할당할 수 있다.

char a = 'A';

이스케이프 문자열

그리고 이스케이프 문자열을 사용할 수 있다.

이스케이프 문자
{: .text-center}

참조타입인데도 불구하고 리터럴을 지원하는 문자열이다.

문자열 타입은 리터럴 을 지원하는데, 리터럴 방식으로 String 에 값을 주면 Heap 영역에서 String constant pool 이라는 특수한 영역에 값이 저장된다.

동일한 값을 쓰는 경우에 다른 일반적인 레퍼런스타입 처럼 Heap 에 또 올라가지 않고, String constant pool 에 존재하는 값을 참조하는 방식으로 작동한다.

String s1 = "java";
String s2 = "java";

이렇게 하면 둘의 주소는 같다.

스크린샷 2021-08-14 오전 11 37 52

스크린샷 2021-08-14 오전 11 38 11

그래서 위와같이 주소값은 같아지게 된다.

변수 선언 및 초기화 방법

저번 포스팅에서 봤듯이 클래스의 필드에선 자동으로 선언만 해줘도 초기화가 기본값으로 진행이 된다.

선언을 하는 순간 이 변수를 저장할거야 저장공간을 할당해줘 라고 해석된다.

메소드 내에서는 선언만하고 초기화를 안해준다면

java: variable a might not have been initialized

에러가 발생한다.

그래서 선언만 해주고 진행을 해 나가다가 무조건적으로 결국엔 값을 할당해서 초기화를 시켜주어야 한다는 것이다.

선언과 초기화

선언과 초기화를 같이 진행할 수도 있다.

String s;
s = "java";

String s = "java";

두개 다 사용이 가능한 방법

변수의 스코프와 라이프타입

scope

변수의 스코프는 해당 변수를 사용할 수 있는 영역 범위를 뜻한다.
변수의 경우 scope 에 따라 Instance 변수, class 변수, Local 변수 로 나눌 수 있다.

lifetime

해당 변수가 메모리에 언제까지 살아있는지를 의미한다.

인스턴스 변수

인스턴스 변수는 클래스안에서 생성된 변수이며 필드라고 부른다.

  • scope: static 메서드를 제외한 전체
  • lifetime: 해당 클래스를 인스턴스화 한 객체가 메모리에서 제거될 때까지

클래스 변수

class 변수는 클래스 내에 필드에 생성이 되지만 static 키워드가 붙어있는 변수

  • scope: 클래스 전체
  • lifetime: 프로그램 종료시

로컬 변수

Local 변수는 지역변수라고도 부르며 위의 두 변수를 제외한 모든 변수가 이것에 해당된다.

  • scope: 변수가 선언된 메서드 내부
  • lifetime: 프로그램이 해당 메서드를 제어하는 동안

타입 변환, 캐스팅 그리고 타입 프로모션

타입 변환

자료형이 자기 자신보다 큰 자료형에 넣게되면 그건 타입 변환이 필요없고 자동 캐스팅으로 변환이 된다.

하지만 큰 자료형이 작은 자료형으로 가려면 타입 변환이 필요하다.

int a = 1;
byte b = (byte)a; //변형이 오지 않음

만약 작은 자료형의 데이터 범위를 넘어선 변수가 타입 변환을 한다면?
데이터의 손실이나 변형이 올 수 있다.

int a = 10000;
byte b = (byte)a; //byte 최대 범위를 넘었기 때문에 변형이 생긴다.

타입 프로모션

타입 캐스팅과 반대로 크기가 더 작은 자료형을 더 큰 자료형에 대입하는 것을 의미한다. 예를 들어, byte타입의 데이터를 int타입에 대입하는 경우이다.

이 경우에는 데이터 손실이나, 변형이 오지 않음으로 캐스팅할 때 처럼 명시적으로 적지 않아도 자동으로 변환이 가능하다.

그냥 캐스팅과 프로모션은 같이 생각해야 안 헷갈릴 것 같다 구분하는 필요를 안둬도 될것 같은? 느낌

이 타입 변환들은 primitive 타입에서만 사용되는게 아니라 참조 타입에서도 가능하다.
부모클래스로의 타입변환은 자동적으로 가능하지만 자식클래스로의 타입변환은 타입캐스팅이 필요하다. 하위 클래스는 상위 클래스의 필드나 메소드를 물려받음으로 하위 타입의 객체를 상위 타입으로 바꾼다고 해서 데이터의 손실이나 변형이 일어나진 않으니까 말이다.

1차 및 2차 배열 선언하기

배열은 하나의 동일 타입을 여러개 담을 수 있다.

[]로 감싸진 0으로 부터 시작하는 index가 배열의 길이나 순서를 나타낸다.

배열도 type에 따라 기본 값(default value)로 채워진다. (명시적으로 값을 넣어주지 않는다면)

참조 타입의 경우 Null

1차원 배열

int[] a = new int[5]; //[0,0,0,0,0] 로 초기화
int[] b = {1,2,3,4,5}; // 명시적으로 값을 넣어주면 이대로 초기화가 된다.

int[] c = new int[5];
//값 넣기 이렇게도 가능하다.
c[0] = 1;
c[1] = 2;
c[2] = 3;
c[3] = 4;
c[4] = 5;

1차원 배열은 이렇게 선언하면 된다.

2차원 배열

2차원 배열은 행렬(matrix)를 생각하면 된다.

int[행][렬] = new int[행][렬]

가령 3행 3열의 행렬이 이렇게 있다고 가정하면

1 2 3
4 5 6
7 8 9

자바로 표현되는 선언식은 아래와 같다.

int[][] arr = { {1,2,3}, {4,5,6}, {7,8,9} };

지정된 값 말고 동적으로 추가하는 느낌이라면

int[][] arr = new int[3][3];

for(int i = 0; i < 3; i++) {
    for(int j = 0; j < 3; j++) {
        arr[i][j] = 넣을 변수값
    }
}

하면된다.

타입추론, var

타입 추론이란 데이터 타입을 코드에 명시하지 않아도, 컴파일 단계에서 컴파일러가 타입을 유추해 정해주는 것을 뜻한다. 1.5버전 부터 추가된 Generic 이나 자바 8에서 추가된 람다에서 타입추론이 사용된다. 그리고 자바10 에서는 이러한 타입추론을 사용하는 var 이라는 Local Variable Type-Inference 가 추가되었다.

아직 많이 사용할지는 잘 모르겠다.

  • foreach
    • 그냥 우리가 리스트 열거할 때 쓰던 for문, for(Person person : personList) 문에서 변수 선언할 때 var로 쓰면 편하다. 이클립스나 인텔리제이나 for문 쓸때, 타입 추론하기엔 열거 타입을 정의할 때까지 타입을 직접 작성하거나, 템플릿을 작성해야 해서 난감할 때를 많이 겪어봤을 것이다. 이를 var 키워드가 순식간에 해결해준다.
List<Person> people = new ArrayList<>();
people.add(new Person("a"));
people.add(new Person("b"));
people.add(new Person("c"));

for (var person : people) {
    //....
}

이렇게 작성하면 IDE 에서는 var 키워드를 Person 클래스로 인식할 수 있는 기회가 주어지게 되고, 컴파일할 때도 var 키워드를 Person 으로 변환하게 될 것이다. 타이핑이 정말 간결해진다. Object 타입으로 미리 단정지을 필요도 없다.

profile
💻 많이 짜보고 많이 경험해보자 https://lsj8367.tistory.com/ 블로그 주소 옮김

0개의 댓글