본문 바로가기
프로그래밍 언어/자바

3. 다시 공부하는 자바 - 객체 지향 프로그래밍 1 (이것이 자바다)

by amobu0 2024. 6. 13.

이것이 자바다 라는 책을 보고 정리한 글이다.

https://m.hanbit.co.kr/store/books/book_view.html?p_code=B4861113361

 

이것이 자바다(개정판)

2015년 초판이 출간된 이후부터 지금까지 기본 개념에 충실한 설명으로 독자들에게 큰 사랑을 받아온 『이것이 자바다』의 개정판. 기존 Java 8 버전에 최신 Java 17 LTS 버전까지 아우르는 내용으로

m.hanbit.co.kr

 

Part 2 객체 지향 프로그래밍


데이터 타입 분류

자바의 데이터 타입은 크게 기본 타입(Primitive type)과  참조 타입(Reference type)으로 분류된다. 이전 글에서는 기본 타입을 알아보았으니, 지금은 참조 타입에 대해 알아보자 참조라입이란 객체(Object)의 번지를 참조하는 타입으로 배열, 열거, 클래스, 인터페이스 타입이 있다.

Object(객체)란? 객체는 데이터와 메소드로 구성된 덩어리이다.
객체 = 데이터(필드) + 메소드

 

기본 타입으로 선언된 변수와 참조 타입으로 선언된 변수의 차이점은 저장되는 값이다. 기본 타입으로 선언된 변수는 값 자체를 저장하고, 참조 타입으로 선언된 변수는 객체가 생성된 메모리 번지를 저장한다. 

 

변수들은 모두 스택(stack)이라는 메모리 영역에서 생성되고 제거된다. 기본 타입 변수는 직접 값을 저장하고 있지만, 참조 타입 변수는 힙(heap) 메모리 영역의 번지를 저장하고 객체를 참조한다.


null과 NullPointerException

참조 타입 변수는 아직 번지를 저장하고 있지 않다는 뜻으로 null(널) 값을 가질 수 있다. null도 초기값으로 사용할 수 있기 때문에 null로 초기화된 참조 변수는 스택 영억에 생성된다.

자바는 프로그램 실행 도중에 발생하는 오류를 예외(Exception)라고 부른다.

 

참조 변수를 사용하면서 가장 많이 발생하는 예외 중 하나는 NullPointerException이다. 변수가 null 값인 상태에서 객체의 데이터나 메소드를 사용하려 할 때 발생하는 예외이다. NullPointerException이 발생하면 예외가 발생한 곳에서 null인 상태의 참조 변수가 사용되고 있음을 알고, 이것을 해결하려면 참조 변수가 객체를 정확히 참조하도록 번지를 대입해야 한다.


문자열(String) 타입

자바의 문자열은 String 객체로 생성된다. 다음은 두 개의 String 변수 name과 job를 선언하고 문자열 리터럴을 대입한 것이다. name 변수와 job 변수에 문자열 리터럴이 대입되면 문자열은 String 객체로 생성되고, 객체의 번지가 각각 대입된다.

String name; 	     //String 타입 변수 name 선언
name = "Amobu0";     //name 변수에 문자열 대입
String job = "개발자"; //String 타입 변수 job을 선언하고 문자열 대입

문자열 비교(equals)

자바는 문자열 리터럴이 동일하다면 String 객체를 공유하도록 설계되어 있다. String 변수에 문자열 리터럴을 대입하는 것이 일반적이다. job1과 job2는 동일한 String 객체의 번지가 저장된다.

 

new 연산자로 직접 String 객체를 생성하고 대입할 수도 있다. new 연산자를 새로운 객체를 만드는 연산자로 객체 생성 연산자라고 한다. name1과 name2 변수는 서로 다른 String 객체의 번지를 가진다.

동일한 String 객체든 다른 String 객체든 상관없이 내부 문자열만을 비교할 경우에는 String 객체의 equals() 메소드를 사용한다.

//job1과 job2는 같은 번지를 가진다.
String job1 = "개발자";
String job2 = "개발자";

//name1과 name2는 다른 번지를 가진다.
String name1 = new String("Amobu0");
String name2 = new String("Amobu0");

boolean a = job1.equals(job2); //같은 문자열인지 검사
boolean b = name1.equals(name2); //같은 문자열인지 검사

boolean c = job1 == job2; //같은 참조값인지 검사
boolean d = name1 == name2; //같은 참조값인지 검사

System.out.println("a = " + a); //true
System.out.println("b = " + b); //true

System.out.println("c = " + c); //true
System.out.println("d = " + d); //false

문자 추출

문자열에서 특정 위치의 문자를 얻고 싶다면 charAt() 메소드를 이용할 수 있다. charAt()메소드는 매개값으로 주어진 인덱스의 문자를 리턴한다. 여기서 인덱스란 0에서부터 '문자열의 길이-1'까지의 번호를 말한다.

String str = "Amobu0 개발자";
char charValue = str.charAt(3); //b

문자열 길이

문자열에서 문자의 개수를 얻고 싶다면 length() 메소드를 사용한다.

String str = "Amobu0 개발자";
int length = str.length() //10

문자열 대체

문자열에서 특정 문자열을 다른 문자열로 대체하고 싶다면 replace() 메소드를 사용한다. replace()메소드는 기존 문자열은 그대로 두고, 대체한 새로운 문자열을 리턴한다.

String oldStr = "Amobu0 개발자";
String newStr = oldStr.replace("개발자", "developer"); //Amobu0 developer

 

String 객체의 문자열은 변경이 불가한 특성을 갖기 때문에 replace() 메소드가 리턴하는 문자열은 원래 문자열의 수정본이 아니라 완전히 새로운 문자열이다. 따라서 oldStr 변수는 "Amobu0 개발자" 문자열을 참조하고, newStr 변수는 새로 생성된 "Amobu0 developer" 문자열을 참조한다.


문자열 잘라내기

문자열에서 특정 위치의 문자열을 잘라내어 가져오고 싶다면 subString() 메소드를 사용한다.

메소드 설명
substring(int beginIndex) beginIndex에서 끝까지 잘라내기
substring(int beginIndex, int endIndex) beginIndex에서 endIndex 앞까지 잘라내기

 

String num = "012345-1234567";
String value1 = num.substring(0, 6); //012345
String value2 = num.substring(7); //1234567

문자열 찾기

문자열에서 특정 문자열의 위치를 찾고자 할 때는 indexOf() 메소드를 사용한다. indexOf() 메소드는 주어진 문자열이 시작되는 인덱스를 리턴한다. index 변수에는 7이 저장되는데, "xxxxxx-1234567"에서 "1234567"문자열의 인덱스가 7번이기 때문이다.

 

만약 문자열이 포함되어 있지 않으면 메소드는 -1을 리턴한다. 주어진 문자열이 단순히 포함되어 있는지만 조사한다면 contains() 메소드를 사용하면 편리하다. 원하는 문자열이 포함되어 있으면 contains() 메소드는 true를 리턴하고, 그렇지 않으면 false를 리턴한다.

String num = "XXXXXX-1234567";
int index1 = num.indexOf("1234567"); //7
int index2 = num.indexOf("ㄱ") //-1
boolean result = num.contains("1") //true

문자열 분리

문자열이 구분자를 사용하여 여러 개의 문자열로 구성되어 있을 경우, 이를 따로 분리해서 얻고 싶다면 split() 메소드를 사용한다. sports는 쉼표로 구분된 문자열을 가지고 있다. split() 메소드를 호출할 때 쉼표를 제공하면 분리된 문자열로 구성된 배열(array)을 얻을 수 있다.

String sports = "축구, 배구, 야구, 탁구, 당구";
String[] sport = sports.split(","); //"축구" "배구" "야구" "탁구" "당구"

배열(Array) 타입

변수는 하나의 값만 저장할 수 있다. 그래서 많은 양의 값을 다루는 좀 더 효율적인 방법이 필요한데 이것이 배열이다. 배열은 연속된 공간에 값을 나열시키고, 각 값에 인덱스를 부여해 놓은 자료구조이다. 인덱스 대괄호 [ ]와 함께 사용하여 각 항목의 값을 읽거나 저장하는데 사용된다.

 

예를 들어 socre[0]은 100, socre[1]은 87, socre[2]은 91의 값을 가진다면, 이렇게 성적을 배열하면 평균 값은 배열의 인덱스를 이용해서 for 문으로 쉽게 구할 수 있다.

int[] scores = {100, 87, 91};

int sum = 0;
for (int i = 0; i < 3; i++) {
    sum += scores[i];
}
int avg = sum/3;

 

배열은 다음과 같은 특징을 가지고 있다.

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

 

int 배열은 int타입의 값만 관리하고, String 배열은 문자열만 관리한다. 배열은 생성과 동시에 길이가 결정된다. 또한 한 번 결정된 배열의 길이는 늘리거나 줄일 수 없다.


배열 변수 선언

배열 변수의 선언은 두 가지 형태로 작성할 수 있지만, 관례적으로 첫 번째 방법을 주로 사용한다.

선언 방법 예시
1. 타입[] 변수; int[] intArray;
double[] doubleArray;
2. 타입 변수[]; int intArray[]; 
double doubleArray[];

 

배열 변수도 참조 변수이다. 배열도 객체이므로 힙 영억에 생성되고 배열 변수는 힙 영역의 배열 참조값(주소)을 저장한다. 참조할 배열이 없다면 배열 변수도 null로 초기화할 수 있다. 만약 배열 변수가 null 값을 가진 생태에서 변수[인덱스]로 값을 읽거나 저장하게 되면 NullPointerException이 발생한다.

타입[] 변수 = null;

열거(Enum) 타입

데이터 중에는 몇 가지로 한정된 값을 갖는 경우가 있다. 예를 들어 월은 12개의 값을, 요일은 7개의 값을 갖는데, 이와 같이 한정된 값을 갖는 타입을 열거 타입이라고 한다. 열거 타입을 사용하기 위해서는 열거 타입 이름으로 소스 파일(.java)을 생성하고 한정된 값을 코드로 정의해야 한다. 열거 상수는 열거 타입으로 사용할 수 있는 한정된 값을 말한다. 관례적으로 알파벳으로 정의하며, 모두 대문자로 작성한다.

좌: enum 타입 소스파일 / 우: enum 타입 사용 예시