[Java]Day02 - 자바 데이터타입,변수 그리고 배열
2021-01-20 # Java

Review Day01

오늘 포스트에 앞서 지난 시간에 다뤘던 Compile에 대해서 다시 한 번 다뤄보겠다.

Q1. java14로 compile한 파일을 java8로 실행하면 어떻게 될 것인가?
Q2. java8로 compile한 파일을 java14로 실행하면 어떻게 될 것인가?

Q1의 정답은 Error, Q2의 정답은 Success이다. 쉽게 생각하면 낮은 버젼의 컴파일러로 컴파일 시 높은 버젼의 자바로 실행은 가능하지만 높은 버젼의 컴파일러로 컴파일 시 낮은 버젼의 자바로 실행은 불가능하다.

Q3. 그렇다면 java14버젼으로 compile시에는 java8로는 절대 실행불가능한 것인가?

Q3의 정답은 False이다. javac -source 1.6 -target 1.6옵션을 줌으로써 컴파일시 실행도 가능해진다. 높은 버젼에서만 사용할 수 있는 기능도 컴파일러가 낮은버젼에 호환되도록 컴파일을 하기 때문에 실행이 가능하지는것이다. (모든 기능이 가능한 것은 아니니까 굳이 그러진말자!)
그러나 정말 안타깝게도, 일부 Maven plugin이 간혹 특정버젼으로 만들어지고 낮은버젼으로 호환이 안되어 프로젝트 시 확인을 해야한다.

높은 버젼의 컴파일시 낮은 버젼으로 실행하면 다음과 같은 에러가 뜬다.

1
2
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.InsupportedClassVersionError: 파일명 has been compiled by a more recent version of the Java Runtime (class file version 58.0), this version of the Java Runtime only recognizes class file versions up to 52.0

이는 위에 설명했던 그대로의 말을 의미한다.

Q4. javac는 어디에 들어있는가?

Q4의 정답은 JDK이다. compile을 하는 것은 개발자의 몫이기 때문에 JDK에만 들어가있다. JAVA9부터는 JRE는 따로 배포 안하므로 나중에 확인해보자.

Q5. 바이트코드는 왜 바이트코드에요?

Q5의 정답은 opcode가 1바이트이기 때문이다. 시스템프로그래밍 수업을 들었다면 알겠지만 기계어로 바꾸는 과정 중에 바이트코드나 어셈블리어같은 것들은 opcode라는 것이 존재한다. 이것이 1바이트이기 때문에 바이트코드라고 한다. 또한, java뿐만 아니라 다른 언어들도 적절한 컴파일러로 통해 바이트코드로 변환이 된다면 jvm은 이를 실행할 수 있다.


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


프리미티브 타입 종류와 값의 범위 그리고 기본 값

변수의 타입에는 크게 두가지로 나눌 수 있다.

  1. Primitive Type
  2. Reference Type

이중 Primitive Type에는 총 8개의 타입이 있으며, 크게 논리형, 문자형, 정수형, 실수형으로 구분된다.
문자형인 char는 문자를 내부적으로 정수(유니코드)로 저장하기 때문에 정수형과 별반 다르지 않으며, 정수형 또는 실수형과 연산도 가능하다. 반면에 boolean은 다른 기본형과의 연산이 불가능하다. 즉, boolean을 제외한 나머지 7개의 기본형은 서로 연산과 변환이 가능하다. 정수는 가장 ㅁ많이 사용되므로 타입을 4가지나 제공한다. 각 타입마다 저장할 수 있는 값의 범위가 다르므로 저장할 값의 범위에 맞는 타입을 선택하면 되지만, 일반적으로 int를 많이 사용한다. 왜냐하면, int는 CPU가 가장 효율적으로 처리할 수 있는 타입이기 때문이다. 효율적인 실행보다 메모리를 절약하려면, byte나 short를 선택하자.

Reference Type은 다음과 같다.

“The basic difference is that primitive variables store the actual values, whereas reference variables store the addresses of the objects they refer to.” 출처

상수와 리터럴

‘상수(constant)’는 변수와 마찬가지로 ‘값을 저장할 수 있는 공간’이다. 하지만 말그대로 변수는 변할 수 있는 공간이지만 상수는 변할 수 없는 공간이다. 상수의 이름은 모두 대문자로 하는 것이 암묵적인 관례이며, 여러 단어로 이루어져있는경우 ‘_’로 구분한다. (ex. final int MAX_SPEED)
‘리터럴(literal)’은 상수와 구분짓기 위해 만든 것으로 그 자체로 값을 의미한다.

“A literal is the source code representation of a fixed value; literals are represented directly in your code without requiring computation. As shown below, it’s possible to assign a literal to a variable of a primitive type” 출처

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

변수의 스코프란 말그대로 스코프이다. 즉, 변수가 살아있는 범위에 대해 말하는 것이다. 라이프타임과 스코프는 붙어다니는 단어들이다.
이제 우리는 변수를 instance, static, local로 나눌 수 있는데 이는 다음과 같이 쓸 수 있다. 출처

  1. Instance Variable
    Scope : throughout the class except in static methods
    Lifetime : until the object stays in memory.

  2. Static(Class) Variable
    Scope : throughout the class
    Lifetime : until the end of the program or as long as the class is loaded in memory.

  3. Local Variable
    Scope : within the block in which it is declared
    Lifetime : until the control leaves the block in which it is declared.

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

타입 변환이란 말 그대로 타입 변환이다.(Dejavu..) byte로 선언했던 변수를 int 또는 기타 type으로 변환시키는 것이다. 하지만 이는 굉장히 중요한 문제이다. C를 처음 접했었다면 처음에 부딪혔던 난관이 있을것이다. 0.5를 표현하는 것이다. int형 변수 a,b를 각각 1, 2로 했다면 우리는 0.5는 당연히 a/b일 것이라 생각했겠지만 절대 0.5가 출력되지 않는다. 이는 변수의 자료형이 int로 반환되기 때문에 절대 원하는 값인 0.5가 아닌 0이 출력이 되었던걸 경험했을 것이다. 그래서 필요한 것이 이런 타입변환이다.

1
double c = (double)(a/b);

이런식으로 하는 것이 캐스팅이다. 굉장히 간단하지 않은가? 원하는 타입으로 앞에 괄호를 붙여쓰기만 하면되는 것이다.
하지만 세상은 그렇게 녹록치 않다. boolean을 제외한 Primitive Type간에는 자유롭게 변환이 가능하지만(물론 데이터 손실은 있을 수 있다.) Primitive Type간에도 형변환을 하는것이 원칙이지만, 값의 범위가 작은 타입에서 큰 타입으로의 형변환은 생략이 가능하다. Reference Type간에는 implicit up-casting, explicit down-casting이 이루어진다.

1차 및 2차 배열 선언하기

1
2
3
int[] a = {1,2,3};
int[][] b = {{2,3,4},{5,6,7}};
이부분은 이정도로만 해두고 다음시간에 Review를 통해 더 자세히 다뤄보도록 하겠다.

타입 추론, var

코틀린을 써보며 자주 사용했던 var이다. 그때는 뭔지도 모르고 무조건! var로 선언했었다. 물론 차이가 있겠지만 우선 자바로 배워보도록 하겠다. 우선 var은 java10에서 생겨난 것이다. var로 선언한다면 런타임시 변수의 종류를 파악해 알아서 변환시켜준다. 타입추론이란 자바자체적으로 어떤 타입인지 예측하고, 그것을 사용하는 것을 의미한다.

올바른 사용과 잘못된 사용

1
2
3
4
5
6
var a = 1;            // Legal
var b = 2, c = 3.0; // Illegal: multiple declarators
var d[] = new int[4]; // Illegal: extra bracket pairs
var e; // Illegal: no initializer
var f = { 6 }; // Illegal: array initializer
var g = (g = 7); // Illegal: self reference in initializer

타입

1
2
3
4
5
6
7
8
9
var a = 1;                // a has type 'int'
var b = java.util.List.of(1, 2); // b has type 'List<Integer>'
var c = "x".getClass();
// (see JLS 15.12.2.6)
var d = new Object() {}; // d has the type of the anonymous class
var e = (CharSequence & Comparable<String>) "x";
// e has type CharSequence & Comparable<String>
var f = () -> "hello"; // Illegal: lambda not in an assignment context
var g = null; // Illegal: null type

엄청 편해보여서 모든 변수를 var로 선언해버리는 것이 어떻겠냐는 생각을 할 수 있겠지만 아쉽게도 그러면 안된다. 예상치못한 에러에 대처할 수 없어진다. 그렇다면 언제 사용하는 것이냐?에 대해서는 다음의 글을 살펴보는 것이 좋겠다. 제네릭,람다,foreach구문 등 쓰는 부분이 굉장히 많다. 이는 추후에 더 자세히 다뤄보도록 하겠다.