java 데이터 참조 타입

개미Coder
|2024. 4. 18. 10:21
반응형

## 데이터 타입 분류


프로그램이 히는 일은 결국 데이터를 처리하는 것이다. 
따라서 데이터를 얼마나 잘 다루느냐가 좋은 프로그램을 작성할 수 있는 관건이 된다. 
데이터를 잘 다루기 위해서는 자바에서 지원히는 데이터 타입에 대해서 제대로 이해할 필요가 있다.   
자바의 데이터 타입에는 크게 기본 타입 (원시 타입: primitive type)과 참조 타입(reference type)으로 분류된다. 
기본 타입이란 정수, 실수, 문자, 리 리터럴을 저장하는 타입을 말한다. 
지금까지 우리는 기본 타입으로 변수를 선언하고 데이터를 저장하는 연습을 했다. 
이번 장부터는 참조 타입에 중점을 두려고 한다. 
참조 타입이란 객체(Object)의 번지를 참조하는 타입으로 배열, 열거, 클래스, 인터페이스 타입을 말한다.


기본 타입으로 선언된 변수와 참조 타입으로 선언된 변수의 차이점은 저장되는 값이 무엇이냐이다. 
기본타입인 byte, char, short, int, long, float , double, boolean을 이용해서 선언된 변수는 
실제 값을 변수 안에 저장하지만, 참조 타입인 배열, 열거, 클래스, 인터페이스를 이용해서 선언된 변수는 
메모리의 번지를 값으로 갖는다. 번지를 통해 객체를 참조한다는 뜻에서 참조 타입이라고 부른다.



예를 들어 int와 double로 선언된 변수 age와 pnce가 있고. String 클래스로 선언된 
name과 hobby가 다음과 같이 선언되어 있다고 가정해보자.

 

 

// 기본 타입 변수
int age = 25; 
double price = 100.5;

// 참조 타입 변수
String name = "김자바";
String hobby = "독서";



 

-String도 참조 변수이기에 호출을 저런 방식으로 해야하고 값으로 출력할 때도 데이터 주소가 나와야하지만, 워낙 많이 사용하는 변수이기에 예외로 처리된다.

String name = new String("홍길동");
String name2 = "홍길동";

System.out.println(name2);

 

 

-참조 타입의 특은 첫 글자가 대문자이다.

 

-자바 가상 머신(Java Virtual Machine)에서는 3가지 영역으로 나뉘는데 메서드 영역, 힙 영역, 스택 영역으로 나뉜다.

-메서드 영역 = 바이트 코드 / 힙 영역 = 객체가 저장 / 스택 영역 = 변수가 저장 됨

 

 

 


 

 

# 참조 변수의 == , != 연산



기본 타입 변수의 == , !=  연산은 변수의 값이 같은지, 아닌지를 조사하지만 
참조 타입 변수들 간의 == , != 연산은 동일한 객체를 참조하는지, 다른 객체를 참조하는지 알아볼 때 사용된다. 
참조 타입 변수의 값은 힙 영역의 객체 주소이므로 결국 주소값을 비교히는 것이 된다. 
동일한 주소값을 갖고 있다는 것은 동일한 객체를 참조한다는 의미이다. 
따라서 동일한 객체를 참조하고 있을 경우 연산의 결과는 true이고 != 연산의 결과는 false이다.


 # 기본타입(스택영역)
value1 = 10
value2 = 10

value1 == value2  // 결과 : true (변수안에 값이 있기 때문에 값을 비교할 수 있다.)
value1 != value2  // 결과 : false (변수안에 값이 있기 때문에 값을 비교할 수 있다.)


# ==와 != 연산자로 객체를 비교하는 코드는 일반적으로 if문에서 많이 사용된다. 
# 다음은 변수 reVar2와 reVar3이 같은 객체를 참조할 경우 if 블록을 실행하도록 코딩한 것이다

if(refVar1  ==  refVar2) {
// 실행문
}

 

 

 

 

-참조형 변수 == 참조형 변수는 같은 데이터 주소인지를 확인한다.

-그래서 문자와 문자가 같은지 확인하려면 (컴퓨터 == 컴퓨터) equals를 사용해야 한다.

 

 

 

 

-new 연산자를 사용하지 않고 만들었을 때는 같은 주소의 값을 가진다.

String str1 = "java";
String str2 = "java";

 

-new 연산자를 사용하면, 다른 주소의 값을 가진다.

String str1 = "java";
String str3 = new String("java");
System.out.println(str3 == str1);
// 값은 false가 나온다. (new String으로 새로운 메모리를 생성했기 때문에)

 

 

-즉, == 연산자는 값을 비교할 수 있는게 아니다. (equlas를 사용해야 값 비교가 가능하다)

 

String name1 = "홍길동";
String name2 = "홍길동";
String name3 = new String("홍길동");

if (name1 == name3) {
    System.out.println("둘은 같은 값입니다.");
} else {
    System.out.println("둘은 다른 값입니다."); // 값
}

if (name1.equals(name3)) {
    System.out.println("둘은 같은 값입니다."); // 값
} else {
    System.out.println("둘은 다른 값입니다.");
}

boolean result = name1.equals(name3);
if (result) {
    System.out.println("둘은 같은 값입니다."); // 값
} else {
    System.out.println("둘은 다른 값입니다.");
}

 

 

 


 

 

 

 

## Null과 NullPointerException

 

 

 

 

 



참조 타입 변수는 힙 영역의 객체를 참조하지 않는다는 뜻으로 null값을 가질 수 있다. 
null 값도 초기값으로 사용할 수 있기 때문에 null로 초기화된 참조 변수는 스택 영역에 생성된다.

참조 타입 변수가 null 값을 가지는지 확인하려면 다음과 같이 == , 1=  연산을 수행하면 된다.

String refVar1 = "홍길동";
String refVar1 = null;

refVar1 == null  // 결과 : false 
refVar1 != null  // 결과 : true

refVar2 == null  // 결과 : true
refVar2 != null  // 결과: false



자바는 프로그램 실행 도중에 발생하는 오류를 예외(Exception)라고 부른다.
예외는 사용자의 잘못된 입력으로 발생할 수도 있고, 프로그래머가 코드를 잘못 작성해서 발생할 수도 있다.  
참조 변수를 사용하면서 가장 많이 발생하는 예외 중 하나로 NullPointerException이 있다.

 

-100개의 문장 중에 51번째 문장에서 예외가 발생되면 아래 문장은 읽지도 않고 중단된다.


이 예외는 참조 타입 변수를 잘못 사용하면 발생한다. 
참조 타입 변수가 null을 가지고 있을 경우, 참조 타입 변수는 사용할 수 없다. 
참조 타입 변수를 사용하는 것은 곧 객체를 사용하는 것을 의미하는데, 참조할 객체가 없으므로 사용할 수가 없는 것이다.  
그러나 프로그래머의 실수로 null 값을 가지고 있는 참조 타입 변수를 사용하면 
NullPointerException이 발생한다.

 



int[]  intArray = null;
intArray[0] 10;  // NullPointerException



상기 코드에서 intArray는 배열 타입 변수이므로 참조 타입 변수이다. 
그래서 null로 초기화가 가능하다. 
이 상태에서 intArray[0]에 10을 저장하려고 하면 NullPointerException이 발생한다.
이유는 intArray 변수가 참조하는 배열 객체가 없기 때문이다. 

String str = null;
System.out.println("총 문자수" + str.length());   // NullPointerException



String은 클래스타입이므로 참조타입이다. 따라서 str 변수도 null로 초기화가가능하다. 
이 상태에서 String 객체의 length() 라는 메소드를 호출하면 NullPointerException이 발생한다. 
이유는 str 변수가 참조하는 String 객체가 없기 때문이다. 
프로그램 실행도중 NullPointerException이 발생하면, 예외가 발생된 곳에서 
객체를 참조하지 않은 상태로 참조 타입 변수를 사용하고 있음을 알아야 한다. 
대처 방법은 이 변수를 추적해서 객체를 참조하도록 수정해야 한다.

 

 

-변수명.length();는 해당 변수에 저장되어 있는 값의 길이를 출력하는 메서드이다.

String str = "자바를 공부합니다.";

int result = str.length();

System.out.println(result); // 10
String str = null;

int result = str.length();

System.out.println(result);

값이 들어 있지 않은데, 값을 읽으려고 하니 null 관련 오류가 뜬다.

 

 

 

 


 

 

 

 

# String 타입

자바는 문자열을 String변수에 사용하기 위해서는 변수를 선언하고 초기화 해야 한다.
 (null도 초기화 값으로 사용할 수 있다.)

String  str =  "문자열";

다음은 두 개의 String 변수를 선언하고 문자열을 저장한다.
String name = "김자바";
String hobby  = "독서";



일반적으로 변수에 문자열을 저장할 경우에는 문자열 리터럴을 사용하지만. 
new 연산자를 사용해서 직접 String 객체를 생성시킬 수도 있다. 
new 연산자는 협 영역에 새로운 객체를 만들 때 사용하는 연산자로 객체 생성 연산자라고 한다.

String name1 = new String("김자바"); 
String name2 = new String("김자바"); 

이 경우 namel과 name2는 서로 다른 String 객체를 참조한다.


문자열 리터럴로 생성하느냐 new 연산자로 생성하느냐에 따라 비교 연산자의 결과가 달라질 수 있다. 
통일한 문자열 리터렬로 String 객체를 생성했을 경우 연산의 결과는 true가 나오지만, 
new 연산자로 String 객체를 생성했을 경우 연산의 결과는 false가 나온다. 
연산자는 변수에 저장된 객체 번지가 동일한지를 검사하기 때문이다.

String name1 = "박자바";
String name2 = "박자바";
String name3 = new String("박자바");

name1과 name2는 동일한 문자열 리터럴로 생성된 객체를 참조하기 때문에 name1 == name2의 결과는 true가 나온다. 
그러나 name3은 new 연산자로 String 객체를 별도로 생성했기 때문에 name1 == name3은 false가 나온다. 

동일한 String 객체이건 다른 String 객체이건 상관없이 
문자열만의 값을 비교할 때에는 String 객체의 equals() 메소드를 사용해야 한다. 
equals() 메소드는 원본 문자열과 매개값으로 주어진 비교 문자열의 값이 동일한지 비교한 후 true 또는 false를 리턴한다.

boolean result = name1.equals(name3);
                    원본문자열     비교문자열


String str1 = "김자바";
String str2 = "김자바";

if(str1 == str2) { // == 값 비교
System.out.println("str1과 str2는 참조 주소가 같음");
} else {
System.out.println("str1과 str2는 참조 주소가 다름");
System.out.println();
}
System.out.println();
if(str1.equals(str2)) { // equals() 메소드 사용
System.out.println("str1과 str2는 문자열이 같음");
}




String str3 = new String("이자바");
String str4 = new String("이자바");

if(str3 == str4) { // == 값 비교
System.out.println("str3과 str4는 참조 주소가 같음");
} else {
System.out.println("str3과 str4는 참조 주소가 다름");
}
System.out.println();

if(str3.equals(str4)) { // equals() 메소드 사용
System.out.println("str3과 str4는 문자열이 같음");

 

 

 


 

 

 

## 배열 타입


 
# 배열이란?

변수는 한 개의 데이터만 저장할 수 있다. 
따라서 저장해야 할 데이터의 수가 많아지면 그만큼 많은 변수가 필요하다.   
예를 들어 학생 30 명의 성적을 저장하고, 평균값을 구한다고 가정해보자. 
먼저 학생 30 명의 성적을 저장하기 위해 변수 30개를 선언해야 한다.
그리고 평점을 구하기 위해 변수들을 모두 더해야 한다.

만약 전교 학생들에 대한 성적을 처리할 경우 수백 개의 변수 선언해야 한다.
같은 타입의 많은 양의 데이터를 다루는 프로그램에서는 좀 더 효율적인 방법이 필요한데 이것이 배열이다. 
배열은 같은 타입의 데이터를 연속된 공간에 나열시키고, 각 데이터에 인덱스(index)를 부여해 놓은 자료구조이다. 



score배열의 각 인텍스는 각 항목의 데이터를 읽거나, 저장하는데 사용되며 
다음과 같이 배열 이름 옆에 대괄호 [ ]에 기입된다.

score[인덱스]         EX) score[0], score[1]

예를 들어 score[0]은 83, score[1]은 90, score[2]는 87값을 가진다.

 

 

 

-배열에 인덱스 값이 하나만 빠져도 참조형의 기본값이 null이기 때문에, NullPointerException 오류가 발생한다.

 

-타입 앞에 []를 넣던, 변수 앞에 []를 넣던 무관하다.

int age[];
int[] age;

 

 

 

-데이터타입[] 변수명 = {값, 값2, 값3...};

-값을 아는 방법 : 데이터타입[인덱스 값];

int[] intArray = {5000, 1500, 3000};
System.out.println(intArray[0]); // 5000
System.out.println(intArray[1]); // 1500
System.out.println(intArray[2]); // 3000

 

 

 

-이런식으로 각각의 인덱스에 값을 저장해줄 수 있다.

int[] intExArray = {89, 78, 90, 84, 71};
intArray[0] = 10;
intArray[1] = 10;
intArray[2] = 10;
intArray[3] = 10;
intArray[4] = 10;

 

 

 

-배열의 값을 for문을 이용해서 모두 출력하는 예시

int[] intValue = {50, 1500, 3500, 15000, 9000};

for (int i=0; i<5; i++) {
    System.out.println(intValue[i]);
}

 

-내가 배열의 길이를 모를 때 범위를 지정을 못해주게 될 수 있는데, 그때에는 intValue.length를 적어서 숫자를 대체한다.

for (int i=0; i<intValue.length; i++) {

 

-각각의 인덱스에 값을 저장해주고, 배열의 길이 만큼 for문의 조건식을 적어준다.

int [] arr1 = new int[3];

for (int i = 0; i < arr1.length ; i++) {
    System.out.println("arr1[" + i + "] : " + arr1[i]);
}

arr1[0] = 10;
arr1[1] = 20;
arr1[2] = 30;

for (int i = 0; i < arr1.length ; i++) {
    System.out.println("arr1[" + i + "] : " + arr1[i]);
}

 

 

-모든 배열의 더한 값을 for문을 이용해서 모두 출력하는 예시

int[] intValue = {50, 1500, 3500, 15000, 9000};

int sum = 0;

for (int i=0; i<5; i++) {
    sum += intValue[i];
    System.out.println("현재 sum의 값 = " + sum);
}
System.out.println("모든 값의 합은 = " + sum);
for (int i=0; i<intValue.length; i++) {

 

 

 

-배열을 선언시에 코드를 간결하게 쓰는 이유

// 아래의 코드는 오류가 뜬다.
int[] intArray2;
intArray2 = {50, 1500, 3500, 15000, 9000};

// 아래의 코드는 정상적으로 값이 저장된다.
int[] intArray2;
intArray2 = new int[]{50, 1500, 3500, 15000, 9000};

// 이게 번거롭기 때문에, 아래 코드처럼 간결하게 적어준다.
int[] intArray2 = {50, 1500, 3500, 15000, 9000};

 

 

 

-값의 목록으로 배열 객체를 생성할 때 주의할 점이 있는데 
배열 변수를 이미 선언한 후에 다른 실행문에서 중괄호를 사용한 배열 생성은 허용되지 않는다.

타입[] 변수;
변수 = { 값0, 값1, 값2, 값3, ...  };    //컴파일 에러

배열 변수를 미리 선언한 후, 값 목록들이 나중에 결정되는 상황이라면 
다음과 같이 new 연산자를 사용해서 값 목록을 지정해주변 된다. 



new 연산자 바로 뒤에는 배열 변수 선언에서 사용한 "타입[]" 를 붙여주고 중괄호 { }에는 값들을 나열해주면 된다.

타입[] 변수;
변수 = new  타입[] { 값0, 값1, 값2, 값3, ...  };

 

 

 

 

// intArray 배열에 총 5개의 공간이 만들어진다 인덱스 0~4
int[] intArray = new int[5];
// names 배열에 총 10개의 공간이 만들어진다 인덱스 0~9
String [] names = new String[10];

 

 

 

-길이가 10인 정수 배열을 1부터 10까지의 값을 반복문을 통해 넣고 출력하는 예시

// 길이가 10인 정수 배열을 선언하고 1부터 10까지의 값을 반복문을 이용하여 순서대로 배열 인덱스에 넣은 후 그 값을 출력하세요.

int [] intArr = new int [10];


for (int i = 0; i < intArr.length ; i++) {
    intArr[i] = i + 1;
    System.out.print("인덱스 [" + i + "]안에 들어 있는 값은 " + intArr[i] + " 입니다.");

    if (i < intArr.length-1) {
        System.out.println(", ");
    }
}

 

 

int[] arr2 = new int[10];

for (int i = 9; i >= 0; i--) {
    arr2[i] = i + 1;
    System.out.print(arr2[i] + " ");
}
System.out.println();


int [] arr3 = new int[10];
int num = arr3.length;

for (int i = 0; i < arr3.length; i++) {
    arr3[i] = num;
    num--;
    System.out.print(arr3[i]+ " " );
}

int [] arr4 = new int [10];
int k = 0;

for (int i = 9; i >=0; i--) {
    arr4[i] = k++;
    System.out.println("인덱스 [" + i + "]안에 들어 있는 값은 " + arr4[i] + " 입니다.");
}

 

 

-Scanner에 숫자를 입력받고 그 숫자만큼 배열의 길이를 만들고, 인덱스에 값을 저장하는 for문 예제

Scanner sc = new Scanner(System.in);
System.out.print("숫자를 입력하세요.");
int num = sc.nextInt();

int[] intArray = new int[num];

for(int i = 0; i < intArray.length; i++) {
    intArray[i] = i +1;
    System.out.print("intArray[" + i + "] : " + intArray[i] + " ");
}

 

 

★ 헷갈리는 예제 문제 ★

 

-1부터 10까지의 배열을 랜덤 값으로 받아서 모든 숫자가 배열에 나올 수 있게 출력하는 방법

for(int i = 0; i < arr.length; i++) {
    arr[i] = (int) (Math.random()*10) + 1;
    // 즉, 값이 전에 저장되어있던 배열의 인덱스와 같다면, 다시 외부 for문으로 돌아가는 것이다.
    for (int j = 0; j < i; j++) {
        if(arr[i] == arr[j]) {
            i--;
        }
    }
}


for (int i = 0; i < arr.length; i++) {
    System.out.print(arr[i] + " ");
}

 

 

-인덱스 길이가 10인 배열을 1~20 사이에 난수를 통해서 가장 큰 값과 가장 작은 값을 출력

int [] numArr = new int [10];

for (int i = 0; i < numArr.length; i++) {
    numArr[i] = (int) (Math.random()*20) + 1;
    System.out.print(numArr[i] + "  ");
}

int max = numArr[0];

for(int i = 0; i < numArr.length ; i++) {
    if (max < numArr[i]) {
        max = numArr[i];
    }
}
System.out.println();
System.out.println("배열안에서 가장 큰 값 : " + max);

int min = numArr[0];

for(int i = 0; i < numArr.length; i++) {
    if (min >=  numArr[i]) {
        min = numArr[i];
    }
}
System.out.println();
System.out.println("배열안에서 가장 작은 값 : " + min);

 

 

-로또 번호 출력 예제

int arr[] = new int[7];

for(int i = 0; i < arr.length; i++) {
    arr[i] = (int) (Math.random()*45) + 1;
    for (int j = 0; j < i; j++) {
        if(arr[i] == arr[j]) {
            i--;
        }
    }
}

for(int i = 0; i < arr.length; i++) {
    for (int j = i+1; j < arr.length; j++) {
        if(arr[i] > arr[j]) {
            int tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
        } 
    }
}

for (int i = 0; i < arr.length; i++) {
    System.out.print(arr[i] + " ");
}

 

 

-Scanner 이용해서 메뉴 주문받기

Scanner sc = new Scanner (System.in);

String[] arr = {"파스타", "피자", "샌드위치", "커피", "콜라", "콘치즈"};
System.out.println("메뉴 : 파스타, 피자, 샌드위치, 콘치즈, 커피, 콜라");
System.out.println("주문할 메뉴를 입력하세요 : ");
String food = sc.nextLine();

int delivery = 0;

for (int i = 0; i < arr.length; i++) {
    if(arr[i].equals(food)) {
        delivery += 1;
    }
}
if(delivery == 1) {
    System.out.println(food + "는 배달 가능한 메뉴입니다.");
} else {
    System.out.println(food + "는 없는 메뉴입니다");
}

 

 

 


 

 

 

 

## 향상된 for문

 

-위 아래 코드 동일한 값이 출력된다.

int[] number = {1,2,3,4,5,6};

for (int i = 0; i < number.length; i++) {
    int num = number[i];
    System.out.print(num + "  ");
}
System.out.println();
// ----------------------------------------//
for (int num1 : number) {
    System.out.print(num1 + "  ");
}
String[] str = {"데이터1" , "데이터2" , "데이터3" , "데이터4" , "데이터5"};

for (String str1 : str) {
    System.out.print(str1 + "  ");
}

 

 

 

 

 


 

 

 

 

## 다차원 배열

 

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

arr[0][0] = 1;
arr[0][1] = 2;
arr[0][2] = 3;
arr[1][0] = 4;
arr[1][1] = 5;
arr[1][2] = 6;

System.out.println("arr[0][0] = " + arr[0][0] + "  ");
System.out.println("arr[0][1] = " + arr[0][1] + "  ");
System.out.println("arr[0][2] = " + arr[0][2] + "  ");
System.out.println("arr[1][0] = " + arr[1][0] + "  ");
System.out.println("arr[1][1] = " + arr[1][1] + "  ");
System.out.println("arr[1][2] = " + arr[1][2] + "  ");

 

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

arr[0][0] = 1;
arr[0][1] = 2;
arr[0][2] = 3;
arr[1][0] = 4;
arr[1][1] = 5;
arr[1][2] = 6;

int num1 = arr.length;
int num2 = arr[0].length;
int num3 = arr[1].length;
System.out.println(num1); // 2
System.out.println(num2); // 3
System.out.println(num3);	 // 3

for(int i = 0 ; i < 2; i++) {
    for(int k = 0; k < 3; k++) {
        System.out.println("arr[" + i + "][" + k + "] : " + arr[i][k]);
    }
}

 

 

-변수명[][]에서 지정한 각각의 인덱스의 값을 for문을 이용해서 출력하기

int[][] arr = {
        {30000,2990,8030},
        {5600,1890,3550},
        {5000,6800,3900}
};

for (int row = 0; row < arr.length; row++) {
    for(int col = 0; col < arr[row].length; col++)  {
        System.out.println("arr[" + row + "][" + col + "] : " + arr[row][col]);
    }
}

 

 

String[] strArray = new String[3];
strArray[0] = "홍길동";
strArray[1] = "홍길동";
strArray[2] = new String("홍길동");

System.out.println(strArray[0] == strArray[1]);
System.out.println(strArray[1] == strArray[2]);
System.out.println();
System.out.println(strArray[0].equals(strArray[1]));
System.out.println(strArray[0].equals(strArray[2]));

 

 

-아이디와 비밀번호 값을 받아서 일치하면 로그인이 성공, 일치하지 않으면 로그인이 실패하는 예제

String id = "abc";
String pw = "a123";
boolean login = false;

String idArray[] = {"abc", "main", "solo", "str", "mail"};
String pwArray[] = {"a123", "b123", "c123", "d123", "e123"};

for (int i = 0; i < idArray.length; i++) {
    if (id.equals(idArray[i]) && pw.equals(pwArray[i])) {
        login = true;
    } 
}
if (login) {
    System.out.println("로그인 되었습니다.");
} else {
    System.out.println("아이디 또는 비밀번호를 확인하세요.");
}
Scanner sc = new Scanner(System.in);

System.out.println("id를 입력하세요. >");
String id = sc.nextLine();
System.out.println("pw를 입력하세요. >");
String pw = sc.nextLine();
String idArray[] = {"abc" , "mouse", "keyboard", "monitor", "laptop"};
String pwArray[] = {"a123" , "abcd1" , "abcd2", "abcd3", "abcd4"};
boolean login = false;

for (int i = 0; i < idArray.length; i++) {

        if (id.equals(idArray[i])) {
            if (pw.equals(pwArray[i])) {
                login = true;
            } 
        }
    }

if (login) {
    System.out.println("로그인 되었습니다.");
} else {
    System.out.println("아이디 또는 비밀번호를 확인해주세요.");
}
반응형

'java(2)↗' 카테고리의 다른 글

java 클래스(2)  (0) 2024.04.22
java 클래스  (0) 2024.04.19
java 제어문(if, switch, for, while)  (0) 2024.04.16
java 연산자  (0) 2024.04.15
java특  (2) 2024.04.12