Primitive Type의 종류와 범위 그리고 기본 값은 무엇인가요?
타입 | size | 최대 | 최소 | 기본값 |
boolean | 1 | X | X | false |
byte | 16 | -2^7 | 2^7 | 0 |
char | 16 | 0 | 2^16-1 | \u0000 |
short | 16 | -2^15 | 2^15-1 | 0 |
int | 32 | -2^31 | 2^31-1 | 0 |
long | 64 | -2^63 | 2^63-1 | 0 |
float | 32 | -2^-149 | (2-2^-23)*2^127 | 0.0 |
double | 64 | -2^-1074 | (2-2-52)*2^1023 | 0.0 |
static 변수는 값을 초기화하지 않으면 기본값으로 초기화가 되므로 테스트를 작성할 때 static 변수로 선언한 뒤 기본값을 출력했다
char의 기본값이 무엇을 나타내는지 몰라 찾아보니 인텔리제이에선 \u0000을 저렇게 나타낸다
public class BasicTest {
static int a;
static long b;
static double c;
static char d;
static boolean e;
static float f;
static short g;
static byte h;
@Test
void primitiveType() throws Exception {
System.out.println("int = " + a);
System.out.println("long = " + b);
System.out.println("double = " + c);
System.out.println("char = " + d);
System.out.println("boolean = " + e);
System.out.println("float = " + f);
System.out.println("short = " + g);
System.out.println("byte = " + h);
System.out.println("\u0000");
}
}
Reference Type은 어떤 것들이 있나요?
Reference Type 특징
- Java에서 primitive type이 아닌 data type은 모두 reference type이다
- reference type은 그 자체로 address를 가지고 있다
- null이 가능하다
Reference Type 종류
크게 6종류로 나눌 수 있다
- Array
- 배열에 저장되는 모든 요소는 동일한 유형을 가지며, 크기가 고정되어있다
- Class
- 우리가 작성하는 class를 생각하면 된다
- Interface
- class에 의해 구현되는 reference type
- String
- Enumeration
- type-safe한 클래스의 종류
- 각 요소는 enum의 인스턴스를 가진다
- Annotations
- meta data를 프로그램 요소와 연결하는 방법을 제공?? 질문
Literal은 무엇인가요?
- primitive type, string type, null type 값의 source code representation이다(oracle)
숫자를 나타내는 Literal
integer
integer는 10진수, 16진수, 8진수, 2진수로 나타낼 수 있다
- 16진수는 suffix에 0x, 2진수는 0b, 8진수는 0
- 따라서 10진수 리터럴은 초기 숫자가 0이 아닌 숫자가 뒤에 나옴
@Test
void integerLiteral() throws Exception {
int hexa = 0x16; //16진수
int deci = 42; //10진수
int bi = 0b11; //2진수
int octa = 011; //8진수
System.out.println("hexa = " + hexa);
System.out.println("bi = " + bi);
System.out.println("octa = " + octa);
System.out.println("deci = " + deci);
}
long
- long은 suffix에 L을 붙인다
- l보다는 L을 붙이는 이유는 1과 구별하기 어려워서라고 한다~
float
- float는 suffix에 f라고 붙인다
double
- float와 동일하게 10진수로만 나타낼 수 있다
- 16진수로 나타낼 경우 "컴파일 에러" 발생
- 8진수로 나타낼 경우에 컴파일은 되지만 결국 10진수처럼 동작한다
@Test
void doubleLiteral() throws Exception {
double a = 0x44.44;
double b = 044.44;
double c = 44.44;
System.out.println("b = " + b);
System.out.println("c = " + c);
System.out.println("a = " + a);
}
@Test
void doubleLiteral() throws Exception {
// double a = 0x44.44;
double b = 044.44;
double c = 44.44;
System.out.println("b = " + b);
System.out.println("c = " + c);
// System.out.println("a = " + a);
}
character literal
character literal은 character로 표현되거나 escape sequence로 표현된다
'', 아스키 코드, 유니코드를 사용하여 표현할 수 있다
'\n'은 한 줄 띄우는 escape sequence로, "d는 한칸 띄운다!"라는 글자가 println으로 바로 다음 줄에 와야하지만 \n이 잘 동작하여 한 줄이 비어진 것을 알 수 있다
@Test
void characterLiteral() throws Exception {
char a = 'a';
char b = 97;
char c = '\u0061';
char d = '\n'; //escape sequence
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("c = " + c);
System.out.println("d = " + d);
System.out.println("d는 한칸 띄운다!");
}
String
String literal은 String으로 표현되거나 escape sequence로 표현된다
@Test
void stringLiteral() throws Exception {
String a = "a";
String b = "\n";
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("b는 한 줄 띄운다");
}
변수 선언 및 초기화
변수 선언
변수를 선언하기 위해서 필요한 것은 "타입"과 "이름"이다
java에서는 int a; 처럼 [변수타입] [변수 이름]; 으로 변수 선언을 할 수 있다
초기화
변수를 사용하기 전에 "처음"에 값을 저장하는 것인데, 우리는 대부분 변수 선언과 동시에 초기화를 한다
초기화를 하지 않으면 "쓰레기 값"으로 남아 있기 때문에 프로그래밍하면서 예상치 못한 결과값을 가져올 수 있다
int a = 4; 와 같이 =을 이용하여 해당 변수에 "값"을 초기화 할 수 있다
이외에도 여러가지 초기화 방법이 있다
initialization block
- 인스턴스 변수를 초기화할 수 있다
- static 변수를 해당 블럭에서 초기화할 수 있다
static initialization block
- static 필드를 초기화는 데 사용되는 코드 블록이다
- 인스턴스 변수를 해당 블럭에서는 초기화할 수 없다
class A{
int a;
static int b;
{
a = 5;
b = 4;
}
static {
b = 6;
// a = 7; // Non-static field 'a' cannot be referenced from a static context
}
public void aa() {
System.out.println("a = " + a);
System.out.println("b = " + b);
}
}
결과를 보면 b는 4, a는 5로 저장되있는 것을 볼 수 있다
따라서 static 블럭, instance 블럭이 있을 경우에 instance 블럭에 있는 값으로 저장된다
왜 그럴까?
static 블럭은 클래스가 메모리에 load될 때 한번만 실행하기 때문에,
javac가 컴파일할 때, static 블럭은 실행이 됐고, A 클래스의 인스턴스를 생성할 때 인스턴스 블록이 실행된다
따라서 인스턴스 블록에 있는 b의 값이 저장된다 ~
변수의 scope와 life time
instance variable
클래스 내부, 메서드나 block 외부에 선언된 변수는 "인스턴스 변수"이다
인스턴스 변수의 scope는 static method를 제외하고 클래스 전체이다
인스턴스 변수의 life time은 객체가 메모리에 머무를 때까지이다
class variable
static 변수를 class 변수라고 한다
즉, 클래스 내부에 있고 모든 블록 외부에 선언된 변수이다
클래스 변수의 scope는 클래스 전체이다
클래스 변수의 life time은 프로그램이 끝날 때까지다
local variable
인스턴스 변수, 클래스 변수가 아닌 모든 변수를 지역 변수라고 한다
지역 변수는 메서드의 매개 변수도 포함한다
지역 변수의 scope은 block 내에 있다
지역 변수의 life time은 컨트롤이 선언된 블록을 떠날 때까지이다
타입 변환, 캐스팅, 타입 프로모션
타입 변환(type conversion)
데이터 유형을 다른 데이터 유형으로 convert할 때, "대상" 데이터 유형이 "원본" 데이터 유형보다 클 경우를 말한다
이를 widening conversion이라 한다
여기서 크다 작다는 primitive에선 "범위"를 말하는 것이고, reference에선 포함 관계를 의미한다
캐스팅(casting)
데이터 유형을 다른 데이터 유형으로 convert할 때, "대상" 데이터 유형이 "원본" 데이터 유형보다 작은 경우를 말한다
이를 narrowing conversion이라 한다
@Test
void typeCasting() throws Exception {
int a = 4;
char b = a; //컴파일 에러
char c = (char) a; //casting
}
char의 범위는 int보다 작다
따라서 int를 char로 변환시키려면 컴파일 에러가 발생하기 때문에 타입을 명시적으료 표현해줌으로써 casting할 수 있다
이때 값 손실이 발생할 수 있다
타입 프로모션(type promotion)
암시적 type conversion을 type promotion이라고 한다
type conversion이 이뤄졌기 때문에 widening conversion이다
promotion이 되기 위해서는 conversion의 조건처럼 "대상" 데이터 유형이 "원본" 데이터 유형보다 커야한다
1, 2차 배열 선언
배열은 아래와 같이 선언할 수 있다
b, c배열을 생성과 동시에 초기화하는 방법이다
기본은 타입[] 배열이름 = new 타입[배열 길이];
@Test
void array() throws Exception {
int[] a = new int[3];
System.out.println("a = " + a[0]);
//생성과 동시에 초기화
int[] b = new int[]{1, 2, 3};
int[] c = {1, 2, 3};
}
2차원 배열도 1차원 배열 선언할 때와 거의 비슷하다
타입[][] 배열이름 = new 타입[행 길이][열 길이]
@Test
void array() throws Exception {
int[][] a = new int[3][3];
//생성과 동시에 초기화
int[][] b = new int[][]{{1, 2, 3}, {4,5,6}};
int[][] c = {{1, 2, 3}, {4,5,6}};
}
타입 추론
자바 컴파일러에서 데이터의 타입을 추론(얘는 무슨 타입이지?)하는 것은 type inference이라 한다
타입 추론이라는 말을 듣는 순간 우리는 바로 제네릭을 생각할 수 있다
제네릭의 큰 장점은 컴파일 시점에 타입을 체킹하고, 코드 재사용성, 형 변환이 필요 없으며, type-safe하다
var
Java 10부터 Local Variable Type Inference는 var를 이용하여 컴파일러에게 타입을 추론할 수 있게 됐다
var 사용
- 명시적 초기화 된 지역 변수에만 사용
- enhance for-loop에서 사용
- 람다에서 사용(type annotation 필요)
@Test
void var() throws Exception {
var a = Arrays.asList(1, 2, 3);
for (var integer : a) {
System.out.println("integer = " + integer);
}
Function function = (@NotNull var o1) -> o1 + "4";
Object apply = function.apply(4);
System.out.println("apply = " + apply);
}
var 사용하면 안되는 곳
- 필드 및 메서드 signature
- 명서적 초기화가 없는 지역 변수
- null로 초기화할 수 없음
java 10에서는 var가 람다식에 사용할 수 없다고 했다
하지만 java 11에서부터 type annotation을 정의하여 사용할 수 있게 됐다
var를 사용하여 다형성 사용 문제
B, C는 A의 sub class이다
A클래스를 참조하는 변수인 a는 상속관계에 의해 C 인스턴스를 참조할 수 있다
하지만 var를 이용한 참조변수 b는 현재 A 인스턴스를 참조하는지 B 인스턴스를 참조하는지 알 수 없다
그래서 컴파일러는 참조변수 b는 B 클래스를 참조하는 변수라고 추론한다
B와 C는 서로 상속관계가 형성되어있지 않기 때문에 b는 C 인스턴스를 참조할 수 없기 때문에 컴파일 에러가 발생한다
따라서 다형성에서 var를 사용하는 것은 좋지 않다고 한다
REFERENCE
'Java' 카테고리의 다른 글
throw vs throws (0) | 2022.05.17 |
---|---|
java 연산자 (0) | 2022.05.06 |
Java volatile keyword (0) | 2022.04.18 |
final 키워드 (0) | 2022.03.05 |
스트림 (0) | 2022.01.04 |