자바의 데이터 타입은 2종류
1. 기본타입: 값 자체를 저장
2. 참조타입: 객체가 생성된 메모리 번지를 저장
참조타입
객체의 번지(주소값)를 참조하는 타입
-> 타입 종류: 배열, 열거, 클래스, 인터페이스
변수들은 모두 스택(stack) 이라는 메모리 영역에 생성된다.
기본타입은 값을 직접 저장하지만, 참조 타입 변수(예를 들어 String)는 힙 메모리 영역의 String 객체 주소를 저장하고 이 주소를 통해 String 객체를 참조한다.
=> 스택 영역: 기본타입의 값 저장, 참조타입의 주소값 저장
=> 힙 영역: 참조타입의 주소가 가리키는 실제 값 저장
사진출처: https://steady-coding.tistory.com/305
java 명령어로 JVM이 구동되면 JVM은 운영체제에서 할당받은 메모리영역을 구분해서 사용한다.
아래는 JVM의 메모리 구조이다. 중요하므로 잘 볼것
바이트코드 파일 내용이 저장되는 영역.
클래스 별로 상수, 정적 필드, 메소드 코드, 생성자 코드 등이 저장된다.
객체가 생성되는 영역.
객체의 번지는 메소드 영역과 스택 영역의 상수와 변수에서 참조할수 있음
(스택 영역에서 힙 영역의 주소값을 가지고 있음)
메소드 호출할때마다 생성되는 프레임이 저장되는 영역.
메소드 호출이 끝나면 프레임은 자동 제거.
프레임 내부에는 로컬 변수 스택이 있다.
이 스택 영역에서 기본타입 변수와 참조타입 변수가 생성/제거 된다.
==, != 연산자는 변수의 값이 같은지, 아닌지 조사한다.
참조타입 변수의 값은 객체의 주소값이므로 참조타입 변수의 ==, != 연산자는 주소값을 비교하는것이 된다.
주소값이 같으면 동일 객체를 참조하는 것이고,
다르면 다른 객체를 참조하는 것이다.
package ch05.sec03;
public class ReferenceVariableCompareExample {
public static void main(String[] args) {
int[] arr1;
int[] arr2;
int[] arr3;
arr1 = new int[] {1,2,3};
arr2 = new int[] {1,2,3};
arr3 = arr2;
System.out.println(arr1 == arr2); //false
System.out.println(arr2 == arr3); //true
}
}
참조타입 변수는 null값을 가질수 있다. (아직 주소를 저장하지 않고 있다는 뜻)
null을 초기값으로 사용할수 있기때문에 null로 초기화된 참조변수는 스택영역에 생성된다.
package ch05.sec03;
public class ReferenceVariableCompareExample {
public static void main(String[] args) {
int[] arr1;
int[] arr2;
int[] arr3;
arr1 = new int[] {1,2,3};
arr2 = new int[] {1,2,3};
arr3 = arr2;
System.out.println(arr1 == arr2); //false
System.out.println(arr2 == arr3); //true
}
}
참조타입 변수가 null값인지 확인하려면 !=, == 연산자 사용하면 된다.
예외(exception): 프로그램 실행 도중 발생하는 오류
NullPointerException: 변수가 null인 상태에서 객체의 데이터나 메소드를 사용하려 할때 발생, 참조변수 사용하면서 많이 발생한다.
package ch05.sec04;
public class NullPointerExceptionExample {
public static void main(String[] args) {
int[] intArray = null;
// intArray[0] = 10;//NullPointerException
String str = null;
// System.out.println(str.length()); //NullPointerException
}
}
일부러 null을 대입하는 경우
객체를 사용하려면 참조변수를 이용해야하는데, 참조변수에 null을 대입하면 주소값을 잃게 되므로 더이상 객체를 사용할 수 없다.
즉, 스택 영역에 있던 주소가 null이 되면서, 힙 영역에 있던 객체는 위치정보를 모르는 사용불가 객체가 된다.
자바는 가비지콜렉터를 실행시켜 이런 쓰레기 객체를 자동 제거한다.
자바는 코드로 객체를 삭제하는 방법이 없기때문에, 객체를 제거하려면 객체의 모든 참조를 없애면 된다. => 중요함!!!!
package ch05.sec04;
public class GarbageObjectExample {
public static void main(String[] args) {
String hobby = "수영";
hobby = null; //"수영"에 해당하는 String객체를 쓰레기객체로 만듦
String kind1 = "자동차";
String kind2 = kind1;
kind1 = null; //kind2가 여전히 참조하고 있어서 "자동차"에 해당하는 String 객체가 쓰레기가 되지 않음
System.out.println("kind2 : " + kind2); //kind2 : 자동차
}
}
어느 하나라도 참조하고 있다면 삭제 되지 않음
자바 문자열은 String객체로 생성.
변수에 문자열 리터럴이 대입되면 문자열은 String객체로 생성되고, 객체의 주소가 각각 대입된다.
- 리터럴이란?
변하지 않는 데이터 그 자체
원시타입, String 두가지 리터럴 종류가 있다.
자바는 문자열 리터럴이 동일하면 String객체를 공유한다.
name1과 name2 변수에 "홍길동"을 대입할경우, name1과 name2 변수에는 동일한 String객체의 주소가 저장된다.
String name1 = "홍길동";
String name2 = "홍길동";
//name1과 name2는 같은 객체를 참조하고있다. (같은 주소)
String 변수에 문자열 리터럴을 대입하는게 일반적이지만,
new 연산자로 직접 String 객체를 생성/대입할 수도 있다.
String name1 = new String("홍길동");
String name2 = new String("홍길동");
//name1과 name2는 서로 다른 String 객체를 참조하고 있다. (다른 주소)
equal()
동일한 String객체든, 다른 String객체든 상관없이 내부 문자열만 비교할때 사용하는 메소드(대소문자 구분)
boolean result = str1.equal(str2); //문자열이 같은지 검사 (str1이 원본, str2가 비교문자열)
boolean result != str1.equal(str2); //문자열이 다른지 검사
예시
package ch05.sec05;
public class EqualsExample {
public static void main(String[] args) {
String strVal1 = "홍길동";
String strVal2 = "홍길동";
if(strVal1 == strVal2) {
System.out.println("strVal1, strVal2 는 같은 String 객체 참조");
} else {
System.out.println("strVal1, strVal2 는 다른 String 객체 참조");
}
if(strVal1.equals(strVal2)) {
System.out.println("strVal1, strVal2 는 같은 문자열임");
}
System.out.println("--------------------------------------");
String strVal3 = new String("김개똥");
String strVal4 = new String("김개똥");
if(strVal3 == strVal4) {
System.out.println("strVal3, strVal4 는 참조가 같음");
} else {
System.out.println("strVal3, strVal4 는 참조가 다름");
}
if(strVal3.equals(strVal4)) {
System.out.println("strVal3, strVal4 는 같은 문자열임");
}
}
}
// strVal1, strVal2 는 같은 String 객체 참조
// strVal1, strVal2 는 같은 문자열임
// --------------------------------------
// strVal3, strVal4 는 참조가 다름
// strVal3, strVal4 는 같은 문자열임
String 변수에 빈문자열("")을 대입하면 빈문자열도 String객체로 생성된다. 변수가 빈문자열을 참조하는지 확인하려면 equals() 메소드
를 사용해야한다.
package ch05.sec05;
public class EmptyStringExample {
public static void main(String[] args) {
String hobby = "";
if(hobby.equals("")) { //true
System.out.println("hobby 변수가 참조하는 String 객체는 빈문자열");
}
}
}
charAt() 메소드
문자열에서 특정 위치의 문자를 얻고자할때 사용
매개값으로 주어진 인덱스의 문자를 리턴한다.
- 인덱스: 0부터 문자열의 길이-1 까지
//주민번호에서 성별에 해당하는 7번째 문자를 읽고 남자인지 여자인지 출력
package ch05.sec05;
public class CharAtExample {
public static void main(String[] args) {
String ssn = "9506241230123";
char sex = ssn.charAt(6);
switch (sex) {
case '1':
case '3':
System.out.println("남자입니다.");
break;
case '2':
case '4':
System.out.println("여자입니다.");
break;
}
//결과: 남자입니다.
}
}
length() 메소드
문자열에서 문자의 개수를 얻고자 할때 사용
이때 띄어쓰기(공백)도 문자 개수 하나를 차지한다.
문자열.length();
package ch05.sec05;
public class LengthExample {
public static void main(String[] args) {
String ssn = "9506241230123";
int length = ssn.length();
if(length == 13) {
System.out.println("주민번호 13자리가 맞음");
} else {
System.out.println("주민번호 13자리가 아님");
}
//결과: 주민번호 13자리가 맞음
}
}
replace() 메소드
문자열에서 특정 문자열을 다른 문자열로 대체하고자 할때 사용
기존 문자열은 그대로 두고,대체한 새로운 문자열
을 리턴한다.
String oldStr = "자바 프로그래밍";
String newStr = oldStr.replace("자바","JAVA");
String객체의 문자열은 변경이 불가한 특성을 갖기때문에 replace()메소드가 리턴하는 문자열은 원래 문자열을 수정한게 아니라 대체하는 새로운 문자열이다. 따라서 oldStr과 newStr은 서로 다른 문자열을 참조하고있다.
package ch05.sec05;
public class ReplaceExample {
public static void main(String[] args) {
String oldStr = "자바 문자열은 불변입니다. 자바 문자열은 String 입니다.";
String newStr = oldStr.replace("자바", "JAVA");
System.out.println(oldStr);
System.out.println(newStr);
// 자바 문자열은 불변입니다. 자바 문자열은 String 입니다.
// JAVA 문자열은 불변입니다. JAVA 문자열은 String 입니다.
}
}
substring() 메소드
문자열에서 특정 위치의 문자열을 잘라내기 하여 가져오고 싶을때 사용
substring(int 시작인덱스)
: 시작인덱스부터 끝까지 잘라내기
substring(int 시작인덱스, int 끝인덱스)
: 시작인덱스부터 끝인덱스까지 잘라내기
package ch05.sec05;
public class SubStringExample {
public static void main(String[] args) {
String ssn = "880815-1234567";
String firstNum = ssn.substring(0, 6);
System.out.println(firstNum); //880815
String secondNum = ssn.substring(7);
System.out.println(secondNum); //1234567
}
}
indexOf() 메소드
문자열에서 특정 문자열의 위치를 찾고자 할 때 사용
주어진문자열이 시작되는 index
를 리턴한다.
주어진 문자열이 포함되지 않은경우-1
을 리턴
문자열.indexOf('시작 인덱스를 찾고자하는 문자열');
contains() 메소드
주어진 문자열이 단순히 포함 되어있는지만 확인하고자 할때 사용
원하는 문자열이 포함되어있으면true
를 리턴, 포함되지 않았으면false
를 리턴
문자열.contains("포함되어있는지 확인할 문자열");
package ch05.sec05;
public class IndexOfContainsExample {
public static void main(String[] args) {
String subject = "자바 프로그래밍";
int location = subject.indexOf("프로그래밍");
System.out.println(location); //3
String substring = subject.substring(location);
System.out.println(substring); //프로그래밍
location = subject.indexOf("자바");
if(location != -1) {
System.out.println("자바와 관련된 책이군"); //자바와 관련된 책이군
} else {
System.out.println("자바 책이 아니군");
}
boolean result = subject.contains("자바");
if(result) {
System.out.println("제목에 '자바'가 포함된 책이군"); //제목에 '자바'가 포함된 책이군
} else {
System.out.println("제목에 '자바'가 없는 책이군");
}
}
}
split() 메소드
문자열이 구분자를 사용하여 여러개의 문자열로 구성되어 있을경우, 이를 따로 분리해서 얻고자 할때 사용Sring board = "번호,제목,내용,글쓴이"; String[] arr = board.split(","); //arr[0] = "번호"; //arr[1] = "제목"; //arr[2] = "내용"; //arr[3] = "글쓴이";
package ch05.sec05;
public class SplitExample {
public static void main(String[] args) {
String board = "1,자바 학습,참조 타입 String을 학습합니다.,홍길동";
//문자열 분리
String[] tokens = board.split(",");
//인덱스별로 읽기
System.out.println("번호 : " + tokens[0]);
System.out.println("제목 : " + tokens[1]);
System.out.println("내용 : " + tokens[2]);
System.out.println("성명 : " + tokens[3]);
System.out.println();
//for문을 이용한 읽기
for(int i=0; i<tokens.length; i++) {
System.out.println(tokens[i]);
}
// 번호 : 1
// 제목 : 자바 학습
// 내용 : 참조 타입 String을 학습합니다.
// 성명 : 홍길동
//
// 1
// 자바 학습
// 참조 타입 String을 학습합니다.
// 홍길동
}
}
출처: 이것이 자바다 (개정판) : JAVA 프로그래밍의 기본서 - 신용권, 임경균 저
좋은 정보 감사합니다~ 좋은하루보내세요^^