티스토리 뷰

[기본형 타입(Primitive type)]

- 총 8가지의 기본형 타입(Primitive type)을 미리 정의하여 제공한다.

- 기본 값이 있기 때문에 Null이 존재하지 않는다. 

- 실제 값을 저장하는 공간으로 스택(Stack) 메모리에 저장된다.

- 만약 컴파일 시점에 담을 수 있는 크기를 벗어나면 에러를 발생시키는 컴파일 에러가 발생한다. 

 

출처: https://velog.io/@bsjp400/JAVA-%EB%8D%B0%EC%9D%B4%ED%84%B0%ED%83%80%EC%9E%85-Datatype

[참조형 타입(Reference type)]

- 기본형 타입을 제외한 타입들이 모두 참조형 타입(Reference type)이다.

- 빈 객체를 의미하는 Null이 존재한다.

- 값이 저장되어 있는 곳의 주소 값을 저장하는 공간으로 힙(Heap)메모리에 저장된다. 

- 문법상으로는 에러가 없지만 실행시켰을 때 에러가 나는 런타임 에러가 발생한다. 예를 들어 객체나 배열을 Null 값으로 받으면 NullPointException이 발생하므로 변수 값을 넣어야 한다. 

 

[리터럴(Literal)]

소스코드 내에 직접 입력된 값(데이터)을 의미한다. 

(변수 초기화 시 '저장할 값'에 해당되기도 한다.)

 

cf) 상수(constant)

값을 한 번 저장하면 변경할 수 없는 "변수"를 뜻한다. 

int num = 157;

 

 

[정수 리터럴]

정수 형태의 값으로 byte, char, short, int, long의 정수 타입 기본 데이터 타입에 저장될 수 있다. 

- 소수점이 없는 정수 리터럴: 10진수

ex) 0, 35, -356

- 0으로 시작하는 리터럴: 8진수

ex) 02, -06, 045

- 0x 또는 0X로 시작하고 0~9 숫자, A, B, C, D, E, F 또는 a, b, c, d, e, f 로 구성된 리터럴: 16진수

ex) 0x5, 0XA, 0XB5, 0XAC35 

 

[실수 리터럴]

실수 형태의 값으로 float, double의 실수 타입 기본 데이터 타입에 저장될 수 있다.

- 소수점이 있는 리터럴: 10진수 실수

ex) 0.25, -5.56623

- E 또는 e가 숫자 뒤에 존재하는 리터럴: 10진수 지수와 가수 표현

ex) 5E8 = 5 x 10^8

 

[문자 리터럴]

작은 따옴표 ' ' 로 묶인 하나의 텍스트

ex) 'C', '나'

 

[이스케이프 문자]

역슬레쉬 '\' 가 붙은 문자 리터럴로 특수한 용도로 사용된다.

 

[논리 리터럴]

boolean 논리 기본 데이터 타입에 저장될 수 있고, true, false 값을 가진다.

 

[변수 선언 및 초기화]

(1) 변수 선언

public class ResultObject{
	int number;
	String name;
}

(2) 변수 초기화 하기

public class ResultObject {
    int number = 123;
    String name = "leaguecat";
}

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

(1) 변수의 스코프(영역)이란?

변수에 접근하거나 접근할 수 있는 유효 범위/영역

개발자는 자신이 선언한 또는 선언된 변수에 접근할 수 있는 영역에 대해서 이해해야 한다. 

일반적인 규칙은 변수가 선언된 블록내에서만 액세스 할 수 있다는 것이다.

블록은 왼쪽 중괄호 { 로 시작하고 오른쪽 중괄호 } 로 끝난다. 

 

(2) 변수의 라이프 타임(Lifetime) 이란?

변수가 메모리에서 살아있는 기간

 

1. Instance variables

- 클래스 내부와 모든 메소드 및 블록 외부에서 선언된 변수 

- 스코프: 정적 메서드를 제외한 클래스 전체

- 라이프 타임: 객체가 메모리에 남아 있을 때까지

2. Class variables

- 클래스 내부, 모든 블록 외부에서 선언되고 static으로 표시된 변수 

- 스코프: 클래스 전체

- 라이프 타임: 프로그램이 끝날 때까지 또는 클래스가 메모리에 로드되는 동안 

 

 

3. Local variables

- 인스턴스 및 클래스 변수가 아닌 모든 변수 

- 스코프: 선언된 블록 내에 있음

- 라이프 타임: 컨트롤이 선언된 블록을 떠날 때까지

 

 

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

1) 타입 형 변환?

변수 또는 상수의 타입을 다른 타입으로 변환

연산을 수행하는 코드에서는 같은 타입 끼리만 가능하다. 그래서 연산을 수행하기 전에 같은 타입으로 만들어야 하는데, 타입 변환을 하는것을 형 변환 이라고 한다. 

 

2) 프로모션과 캐스팅?

- 프로모션(자동/묵시적 형변환): 작은 데이터 타입에서 큰 데이터 타입으로 형 변환

- 캐스팅(명시적 형 변환): 큰 데이터 타입에서 작은 데이터 타입으로 형 변환

 

자동 형변환이 가능한 방향

 

예를 들어 short 타입은 16 bit 정수이고, int 타입은 32 bit 정수 이므로 short 타입의 값을 int 타입의 값으로 취급해도 값이 변하는 문제는 발생하지 않는다. long 데이터 타입의 메모리 크기는 8byte이고, float 데이터 타입의 메모리 크기는 4byte인데, long 데이터 타입에서 float 데이터 타입으로 자동 형 변환이 가능하다. 그 이유는 표현할 수 있는 값의 범위가 float이 더 크기 때문이다. 즉, 타입의 데이터 크기가 커지는 변환인(Widening conversion)의 경우에는 호환성이 보장되어 새로운 타입으로 변환된다. 

 

short shortNum = 100;

int intNum = shortNum;                // 확장성에 의한 자동 변환 (short -> int)
System.out.println(intNum);

 

(1) 자동 형변환(프로모션)/확장 변환(Widening conversion)과 축소 변환(Narrowing conversion)

자바는 타입이 서로 일치하지 않는 경우에도 타입끼리 서로 호환성이 있으면 자동으로 변환을 실시한다. 

 

(2) 강제/명시적 형변환(캐스팅)

위에서 말한 호환성이 없는 경우지만 형 변환을 하고 싶을 때 사용하는 것이 강제, 명시적 형 변환이다. 

int intNum = 1;
short shortNum = (short)intNum;

 

[1차 및 2차 배열 선언]

(1) 1차 배열 선언

int []array = new int[10];

- int 배열 선언시 {0,0,0,0,0,0,0,0,0,0} 와 같이 0으로 10개의 값이 초기화된다.

int[] array = new int[5];
array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 2;
array[4] = 1;

System.out.println(array[0]) // 배열에서 값 추출

 

(2) 2차 배열 선언

int [][]array = new int[10][10]
int[][] array = new int[5][5];
array[0][0] = 1;
array[0][1] = 1;
array[1][0] = 2;
array[1][1] = 2;
...

 

[타입 추론, var]

1) 타입 추론이란?

- 타입 추론은 말 그대로 개발자가 변수의 타입을 명시적으로 적어주지 않고도, 컴파일러가 알아서 이 변수의 타입을 대입된 리터럴로 추론하는 것이다. 

 

2) var

- Java 10 에서 도입된 var는 변수를 선언할 때 타입을 생략할 수 있으며, 컴파일러가 타입을 추론한다.

var string = "Hello, World";

- 자바에서 var은 지역 변수에서만 사용할 수 있다. 또한 컴파일러가 타입을 추론할 수 없는 애매한 상황일 때 컴파일 에러가 발생한다. 

- var 은 초기화가 필요하다. 

- null 로 초기화 할 수 없다.

- 배열에 사용할 수 없다. 

- Lambda에 사용할 수 없다. 

 

[Wrapper Class]

기본 자료 타입(Primitive type)을 객체로 다루기 위해 사용하는 클래스들을 래퍼 클래스(Wrapper class)라고 한다.

 

- 래퍼 클래스(Wrapper class)는 java.lang 패키지에 포함되어 있다. 다음과 같이 기본 타입에 대응되는 래퍼 클래스 들이 있다.

- char 타입과 int 타입은 Character 과 Integer의 래퍼 클래스를 가지고 있고 나머지는 기본 타입의 첫 글자를 대문자로 바꾼 이름을 갖는다.

 

[Wrapper class 구조도]

 

- Wrapper class의 부모는 Object이다.

- 내부적으로 숫자를 다루는 Wrapper class의 부모 클래스는 Number 클래스이다. 

 

[박싱(Boxing)과 언박싱(Unboxing)]

 

기본 타입의 값을 포장 객체로 만드는 과정을 박싱 이라고 하고, 포장 객체에서 기본타입의 값을 얻어내는 과정을 언박싱 이라고 한다. 

public class Wrapper_Ex {
    public static void main(String[] args)  {
        Integer num = new Integer(17); // 박싱
        int n = num.intValue(); //언박싱
        System.out.println(n);
    }
}

 

[자동 박싱(AutoBoxing)과 자동 언박싱(AutoUnBoxing)]

자동 박싱의 포장 클래스 타입에 기본 값이 대입되는 경우 발생한다. 예를 들어, int 타입의 값을 Integer 클래스 변수에 대입하면 자동 박싱이 일어나 힙 영역에 Integer 객체가 생성된다.

public class Wrapper_Ex {
    public static void main(String[] args)  {
        Integer num = 17; // 자동 박싱
        int n = num; //자동 언박싱
        System.out.println(n);
    }
}

 

[Java final과 불변 객체]

1) final 란? 

final의 의미는 최종적이라는 뜻을 가지며, final 필드는 초기 값이 저장되면 최종적인 값이 되어 프로그램 실행 도중에 수정할 수 없다.

 

2) final을 사용하는 이유?

- 실수를 예방하기 위해 사용한다. 

- 값에 대한 검증이 필요 없이 로직 구현에만 집중할 수 있다.

- 버그 발생 가능성이 줄어준다.

- 코드 품질이 높아져 변화에 좀 더 빠르게 대응할 수 있다.

 

2) 불변객체란 ?

객체 지향 프로그래밍에 있어서 불변객체(immutable object)는 생성 후 그 상태를 바꿀 수 없는 객체를 말한다.

불변 객체는 read-only 메소드 만을 제공하며, 객체의 내부 상태를 제공하는 메소드를 제공하지 않거나 제공하는 경우 방어적 복사(defensive-copy)를 통해 제공한다. 

 

대표적으로 String, Boolean, Integer, Float, Long 등등이 있다. 이러한 Immutable Class들은 heap영역에서 변경불가능 한 것이지 재할당을 못하는 것은 아니다. 즉 String a = "aa"; 에서 a = "bb" 로 재할당이 가능하다.  a가 참조하고 있는 heap영역의 객체가 바뀌는 것이지 heap영역에 있는 값이 바뀌는 것이 아니다.

 

String name = "Old"; 

name = "New";

// 출처: https://mangkyu.tistory.com/131 [MangKyu's Diary]

- Java의 String은 불변 클래스 이기 때문에 위와 같이 name이라는 변수에 "New"를 할당하는 것은 새로운 값을 지니는 객체를 생성하는 것이다. 

- Java 에서는 배열이나 객체 등의 참조(Reference)를 전달한다. 참조를 통해 값을 수정하면 내부의 상태가 변하기 때문에 내부를 복사하여 전달하고 있는데, 이를 방어적 복사(defensive-copy)라고 한다. 

 

(1) 불변객체

public class Team{
	private final String teamName;
    
    public Team(String teamName){
    	this.teamName = teamName;
       }
 }

- 필드의 접근 제한자는 private이며, final 선언자를 통해 변수를 변경할 수 없도록 제한하였다.

- final 선언자가 부여된 필드의 경우, 생성자에서 최초 1회 초기화가 가능하다.

 

(2) 불변 객체 및 final을 사용하는 이유

1. Thread-safe 하여 병렬 프로그래밍에 유용하며, 동기화를 고려하지 않아도 된다.

멀티 쓰레드 환경에서 동기화 문제가 발생하는 이유는 공유 자원에 동시에 쓰기(write) 때문이다. 하지만 만약 공유자원이 불변의 자원이라면, 더 이상 동기화를 고려하지 않아도 될 것이다. 왜냐하면 항상 동일한 값을 반환할 것이기 때문이다. 이는 안정성 보장 및 동기화를 하지 않음으로써 성능상의 이점도 가져다 준다. 

 

2. 부수효과(side effect)를 피해 오류 가능성을 최소화 할 수 있다. 

부수효과란 변수의 값이 변경되거나, 필드 값이 설정되는 등의 변화가 발생하는 효과를 의미한다. 만약 객체의 수정자(setter)가 구현되어 있고, 여러 메소드에서 객체의 값이 변경된다면 객체를 예측하기가 어려워 질 것이다. 객체의 바뀐 상태를 파악하기 위해서는 메소드를 살펴보아야 할 것이며 이러한 부분은 유지 보수성을 떨어뜨린다. 따라서 이러한 부수효과가 없는 순수 함수들을 만드는 것이 상당히 중요하다. 불변 객체는 기본적으로 값의 수정이 불가능하기 때문에 변경 가능성이 적으며, 객체의 생성과 사용이 상당히 제한된다. 그렇기 때문에 메소드들은 자연스럽게 순수 함수들로 구성될 것이고, 다른 메소드가 호출되어도 객체의 상태가 유지되기 때문에 안전하게 객체를 다시 사용할 수 있다. 이러한 불변 객체는 오류를 줄여 유지 보수성이 높은 코드를 작성하도록 도와준다. 

댓글