기본 문법

데이터 타입 분류

devdubu 2024. 6. 23. 13:08
  • 자바의 데이터 타입에는 기본 타입(원시 타입 : primitive type)과 참조 타입(reference type) 이 있습니다.

기본 타입

  • 기본 타입인 byte, int, long, float, double, boolean을 이용해서 선언된 변수는 실제 값을 변수 안에 저장합니다.
[기본 타입 변수]
int age = 25; double price = 100.5;

참조 타입

  • 참조 타입인 배역, 열거, 클래스, 인터페이스를 이용해서 선언된 변수는 메모리의 번지를 값으로 갖습니다.

[참조 타입 변수] 
String name = "신용권"; String hobby = "독서";

기본 변수 vs 참조 변수

  • 변수는 스택 영역에서 객체는 힙 영역에서 생성된다.
  • int와 double 변수인 age와 price는 직접 값을 저장합니다.
  • 하지만, String 클래스 변수인 name과 hobby는 힙 영역의 String 객체 주소 값을 가지고 있습니다.

메모리 사용 영역

  • JVM이 사용는 메모리 영역에 대해서 알아보자.
  • java.exe로 JVM이 시작되면 JVM은 운영체제에서 할당 받은 메모리 영역(Runtime Data Area)을 다음과 같이 세부 영역으로 구분해서 사용한다.

Java 메모리 구조

메소드(Method) 영역

  • 코드에서 사용되는(~.class)들을 클래스 로더로 읽어 클래스 별로,
    • 런타임 상수품(runtime contant pool)
    • 필드(field) 데이터
    • 메소드(method) 데이터
    • 메소드 코드
    • 생성자(contstructor) 코드
      등을 분류해서 저장한다.
  • 메소드 영역은 JVM이 시작할 때 생성되고 모든 스레드가 공유하는 영역이다.

힙(Heap) 영역

  • 객체와 배열이 생성되는 영역입니다.
  • 해당 영역에서 생성된 객체와 배열은 JVM 스택 영역의 변수나 다른 객체의 필드에서 참조한다.
  • 참조하는 변수나 필드가 없다면
    • JVM은 해당 변수를 쓰레기 취급하고, Garbage Collector를 실행시켜 쓰레기 객체를 힙 영역에서 자동으로 제거합니다.

JVM 스택(Stack) 영역

  • 각 스레드마다 하나씩 존재하며, 스레드가 시작될 때 할당 된다.
  • 자바 프로그램에서 추가적으로 스레드를 생성하지 않는다면, main 스레드만 존재하므로 JVM 스택도 하나이다.

JVM 스택 작동 방법

  • JVM 스택은 메소드를 호출 할 때마다 Frame을 push 하고 메소드가 종료되면 해당 프레임을 pop하는 동작을 수행
  • 예외 발생 시 printStackTrace( ) 메소드로 보여주는 Stack Trace의 각 라인은 하나의 프레임을 표현한다.
  • printStackTrace( ) 메소드는 예외 처리에서 설명한다.
  • 프레임 내부에는 로컬 변수 스택이 있는데, 기본 타입 변수와 참조 타입 변수가 push 되거나 pop 된다.
  • 변수가 이 영역에 생성되는 시점은 초기화가 될 때, 즉 최초로 변수에 값이 저장될 때이다.
  • 변수는 선언된 블록 안에서만 스택에 존재하고 블록을 벗어나면 스택에서 제거 된다.
[1] 
char v1 = 'A';
[2]  
if(v1 == 'A'){  
    int v2 = 100;  
    double v3 = 3.14;  
}  
[3]  
boolean v4 = true
  • 선언된 변수는 실행 순서에 따라서 다음과 같이 스택에 생성되고 소멸 된다.
  • v2와 v3은 if 블록 내부가 실행되고 있을 때만 스택 영역에 존재하고 실행 흐름이 if 블록을 빠져나가면 소멸 된다.

참조 타입 변수의 ==, !== 연산

  • ==, !== 연산자는 변수의 값이 같은지, 아닌지를 조사한다.
  • 참조 타입 변수의 값은 객체의 번지이므로 참조타입의 변수의 ==, !== 연산자는 번지를 비교하는 것이 된다.
  • 번지가 같다면 동일한 객체를 참조하는 것이고, 다르다면 다른 객체를 참조하는 것이다.

  • 위 그림에서 refVar1과 refVar2는 서로 다른 객체를 참조하고 있으므로 ==!== 연산의 결과는 다음 과 같다
    refVar == refVar2 
    // 결과 : false 
    refVar1 !== refVar2 
    //결과 true
  • refVar2와 refVar3 동일한 객체2를 참조하고 있으므로 ==!==연산의 결과는 다음과 같다.
refVar2 == refVar3 
// 결과 : true refVar2 !== refVar3

null과 NullPointerException

  • 참조 타입 변수는 아직 번지를 저장하고 있지 않다는 뜻으로 null 값을 가질 수 있다.
  • null도 초기값으로 사용할 수 있기 때문에 null로 초기화된 참조 변수는 스택 영역에 생성 된다.
String refVar1 = "자바"; 
String refVar2 = null;

  • Java 프로그램 실행 도중에 발생하는 오류를 예외라고 부른다.
  • 참조 벼수를 사용하면서 가장 많이 발생하는 예외 중 하나는 NullPointException이다.
  • 변수가 null인 상태에서 객체의 데이터나 메소드를 사용하려할 때 이 예외가 발생한다.

 

  • 배열 변수 intArray가 참조하는 배열 객체가 없으므로 10을 저장할 수 없기 때문이다.
int [] intArray = null; 
intArray[0] = 10; 
//NullPointException

String 타입

  • 자바의 문자열은 String 객체로 생성된다
String name; 
// String 타입 변수 name 선언 

name = "홍길동"; 
// name 변수에 문자열 대입 

String hobby = "여행" 
//String 타입 변수 hobby를 선언하고 문자열 대입

문자열 비교

  • 자바는 문자열 리터럴이 동일하다면, String 객체를 공유하도록 설계되어있다.
  • name1, name2 변수에 홍길동 을 대입할 경우,
String name1 = "홍길동"
String name2 = "홍길동";

  • - name1과 name2 변수에는 동일한 String 객체의 번지가 저장된다.
  • String 변수에 문자열 리터럴을 대입하는 것이 일반적이지만, new 연산자로 직접 String 객체를 생성하고 대입할 수도 있다.
  • new 연산자는 새로운 객체를 만드는 연산자로 객체 생성 연산자라고 한다.
String name1 = new String("홍길동"); 
String name2 = new String("홍길동");
  • 그렇기 때문에 문자열 리터럴로 생성하느나 new 연산자로 생성하느냐에 따라 비교 연산자의 결과가 달라질 수 있습니다.
  • 만약 객체의 여부가 아닌 내부 문자열을 비교할 경우에는 String 객체의 equals() 메소드를 사용하면 된다.
boolean result = str1.equals(str2); 
//문자열이 같은지 검사(대소문자 구분)

boolean result != str1.equals(str2); 
//문자열이 다른지 검사

문자 추출

  • 문자열에서 특정 위치의 문자를 얻고 싶다면 charAt( ) 메소드를 이용할 수 있다.
  • charAt( ) 메소드는 매개값으로 주어진 인덱스를 문자를 리턴한다.
  • 여기서 인덱스란 0에서부터 '문자열의 길이 -1'까지의 번호를 말한다.
String subject = "자바 프로그래밍"; 
char charValue = subject.chatAt(3);

...
문자열에 많은 함수들은 추후에 작성하겠다.

Array 타입

  • 변수는 하나의 값만 저장할 수 있습니다. 따라서 저장해야할 값의 수가 많아지면, 그만큼 많은 변수가 필요합니다.
  • 배열은 연속된 강간에 값을 나열시키고, 각 값에 인덱스를 부여해놓은 자료구조이다.

배열은 같은 타입의 값만 관리한다
배열의 길이는 늘리거나 줄일 수 없다

배열 변수 선언

  • 배열을 사용하기 위해서는 우선 배열 변수를 선언 해야 한다.
  • 배열 변수 선언은 다음과 같이 두 가지 형태로 작성할 수 있지만, 관례적으로 첫번째 방법을 주로 사용한다.
[1] 
타입 [] 변수;
[2]
타입 변수[];
  • 타입은 배열에 저장될 값의 타입을 말하는데, 다음은 타입별로 배열을 선언하는 방법이다.
[1] 
int[] intArray;

double[] doubleArray; 

String[] strArray;

[2]
int intArray[];

double doubleArray[];

String strArray[];
  • 배열 변수는 참초 변수이다. 배열도 객체이므로 힙 영역에 생성되고, 힙 영역의 배열 주소를 저장한다.
  • 참조할 배열이 없다면 배열 변수도 null로 초기화 할 수 있다.
타입[] 변수 = null;
  • 만약 배열 변수가 null 값을 가진 상태에서 변수 [인덱스]로 값을 읽거나 저장하게 되면 NullPointException이 발생한다.

값 목록으로 배열 생성

  • 배열에 저장된 값의 목록이 있다면, 다음과 같이 간단하게 배열을 생성할 수 있다.

타입[] 변수 = { 값0, 값1, 값2, 값3, ...}
  • 중괄호 { }는 나열된 값들을 항목으로 가지는 배열을 합에 생성하고, 번지를 리턴한다.
  • 배열 변수는 리턴된 번지를 저장함으로써 참조가 이루어진다.
  • "Spring", "Summer", "Fall", "Winter" 문자열을 갖는 배열은 다음과 같이 생성할 수 있다.
String[] season = { "Spring", "Summer", "Fall", "Winter" };
  • 중괄호 { }로 감싼 값의 목록을 배열 변수에 대입할 때 주의할 점이 있다.
  • 매일 변수를 미리 선언한 후에는 값 모록을 변수에 대입할 수 없다.
타입[] 변수; 
변수 = { "값0", "값1", ... }; //컴파일 에러

배열 변수를 선언한 시점과 값 목록이 대입되는 시점다르다면 다음과 같이 new 타입 [ ]을 중괄호 앞에 붙여주면 된다.

String[] names = null; 
names = new String[] {"신용권", "홍길동", "김자바"};
  • 메소드의 매개변수가 배열 타입일 경우에도 마찬가지다
  • 아래와 같이 예를 들면.
// 메소드 선언 
void printItem(int[] scores){ ... }

// 잘못된 메소드 호출  
printItem( { 95, 85, 90} );  

// 올바른 메소드 호출  
printItem( new int\[\](95, 85, 90) );

new 연산자로 배열 생성

  • 값의 목록은 없지만, 향후 값들을 저장할 목적으로 배열을 미리 생성할 수도 있습니다.
  • new 연산자를 다음과 같이 사용하면 배열 객체를 생성 시킵니다.
  • 길이는 배열이 저장할 수 있는 항목 수를 말합니다.
타입[] 변수 = new 타입[길이];
  • new 연산자는 해당 길이의 배열을 생성하고 배열의 번지를 리턴하기 때문에, 배열 분수에 대입할 수 있습니다.
  • 이미 배열 변수가 선언된 후에도 다음과 같이 대입이 가능합니다.
타입[] 변수 = null; 
변수 = new 타입[길이];
  • new 연산자로 배열을 처음 생성하면 배열 항목은 기본값으로 초기화 됩니다.

다차원 배열

  • 배열 항목에는 또 다른 배열이 대입 될 수 있는데, 이러한 배열을 다차원 배열이라고 부른다.
  • 다음은 2차원과 3차원 배열의 모양을 보여준다.

  • 배열 변수는 5번지의 1차우너 배열을 참조하고, 변수[0]은 다시 10번지 배열을 참조하고, 변수[1]은 30번지 배열을 참조한다.
  • 위 그림처럼 다차원 배열은 1차원 배열은 서로 연결한 것이라고 볼 수 있다.
  • 다 차원 배열에서 각 차원의 항목에 접근하는 방법은 아래와 같다.
변수[1차원 인덱스][2차원 인덱스][3차원 인덱스]

new 연산자로 다차원 배열 생성

  • new 연산자로 다차원 배열을 생성하려면 배열 변수 선언 시 타입 뒤에 대괄호 [ ]를 차원의 수 만큼 붙이고 ,
  • new 타입 뒤에도 차원의 수 만큼 대괄호 [ ]를 작성하면 됩니다.
  • 다음은 2차원 배열을 생성하고 변수에 대입하는 과정을 보여준다.
타입[][] 변수 = new 타입[1차원수][2차원수];

객체를 참조하는 배열

  • 기본 타입(byte, char, short, int, log, float, double, boolean) 배열은 각 항목에 값을 직접 저장하지만,
  • 참조 타입(클래스, 인터페이스) 배열은 각 항목에 객체의 번지를 저장한다.
  • 아래와 같이 String 타입의 배열을 생성하고, 각 항목에 문자열을 대입했다고 가정할 때
String[] strArray = new String[3]; 
strArray[0] = "Java"; 
strArray[1] = "C++"; strArray[2] = "C#";
  • strArray 변수와 String[] 배열을 그림으로 표현하면 위와 같다.
  • String[] 배열의 항목은 String 변수와 동일하게 참조 타입 변수로 취급된다.
저작권 및 틀린 부분 의견은 환경입니다.