[자바의 정석 기초편] Object, String 클래스

JEREGIM·2023년 2월 15일
0

자바의 정석 기초편

목록 보기
10/23

📌Object 클래스

모든 클래스의 최고 조상. 오직 11개의 메서드만 가지고 있다.

  • notify(), wait() 메서드는 쓰레드와 관련된 메서드

  • public Class getClass() : 예를 들어 hello.java 파일을 컴파일하면 hello.class 파일이 만들어진다. 이 class 파일이 메모리에 올라갈 때 hello의 Class 객체가 자동으로 생성된다. 이 객체에는 클래스에 대한 정보(iv, 생성자, 조상, 메서드 등)가 담겨져 있다. 즉, 설계도 객체라고 할 수 있다. 이 설계도 객체를 통해서 객체를 생성하거나 객체의 정보를 얻을 수 있고 이를 Reflection API 라고 한다.

  • protected Ojbect clone(), protected void finalize() : 두 메서드는 사용할 때 오버라이딩해서 public으로 변경 후 사용

equals(Object obj)

객체 자신(this)과 주어진 객체(obj)를 비교한다. 같으면 true, 다르면 false
Object 클래스의 equals()는 객체의 주소를 비교(참조변수 값 비교)

class Ex9_1 {
	public static void main(String[] args) {
		Value v1 = new Value(10);
		Value v2 = new Value(10);

		if (v1.equals(v2))
			System.out.println("v1과 v2는 같습니다.");
		else
			System.out.println("v1과 v2는 다릅니다.");
	}
}

class Value {
	int value;

	Value(int value) {
		this.value = value;
	}
}

결과
v1과 v2는 다릅니다.

  • 오버라이딩 하지 않은 equals()는 객체의 주소를 비교하기 대문에 v1의 객체와 v2의 객체는 주소가 달라서 v1과 v2가 다르다고 나온다.
class Ex9_1 {
	public static void main(String[] args) {
		Value v1 = new Value(10);
		Value v2 = new Value(10);

		if (v1.equals(v2))
			System.out.println("v1과 v2는 같습니다.");
		else
			System.out.println("v1과 v2는 다릅니다.");
	}
}

class Value {
	int value;

	Value(int value) {
		this.value = value;
	}

	public boolean equals(Object obj){
		if(!(obj instanceof Value)) 
        	return false;
		
		Value v = (Value) obj;
		return this.value == v.value;
	}
}

결과
v1과 v2는 같습니다.

  • equals()를 두 객체의 주소가 아닌 value 값을 비교하기 위해 오버라이딩 해준다.

  • if(!(obj instanceof Value)) return false; : 형변환하기 전에 꼭 instanceof 연산자로 형변환이 가능한지 확인해줘야 한다.

  • Value v = (Value) obj; : Object 클래스에는 value 변수가 없기 때문에 형변환 후 value 변수를 사용한다.

hashCode()

객체의 해시코드(hash Code)를 반환하는 메서드

Object 클래스의 hashCode()는 객체의 주소를 int로 변환해서 반환, 객체의 지문이라고도 한다.

public class Object {
...
	public native int hashCode();
}
  • native : 네이티브 메서드, OS의 메서드이다.(C언어) 다른 언어로 이미 만들어진 메서드이기 때문에 구현부(내용)가 없다.

equals()의 결과가 true인 두 객체의 해시코드는 같아야 하기 때문에 equals()를 오버라이딩하면, hashCode()도 오버라이딩해야 한다.

  • equals()가 원래는 두 객체의 주소를 비교하지만 보통 두 객체의 iv 값을 비교하기 위해 오버라이딩한다. 이럴 때, hashCode()도 두 객체의 iv 값의 해시코드가 같아야하기 때문에 오버라이딩해줘야 한다.

System.identityHashCode(Object obj)는 Object 클래스의 원래 hashCode()와 동일

  • hashCode()를 오버라이딩 했을 경우, 원래 객체마다 다른 해시코드를 반환하는 기능이 필요할 때 사용한다.

64bit JVM을 사용할 경우 주소 값이 겹치는 경우가 발생할수도 있다.

toString()

객체를 문자열(String)으로 변환하기 위한 메서드

public class Object {
...
	public String toString() {
		return getClass().getName() + "@" + Integer.toHexString(hashCode());
	}
}
  • Card@809a0863 toString()을 오버라이딩하지 않으면 이런 값을 출력한다.

  • 보통 iv 값을 문자열로 출력하기 위해서 오버라이딩을 하고 사용한다.

Object 클래스 예제

import java.util.Objects;

public class ObjectTest {
    public static void main(String[] args) {
        Card c1 = new Card();
        Card c2 = new Card();

        System.out.println(c1); // c1.toString()
        System.out.println(c2); // c2.toString()
        System.out.println(c1.equals(c2));
        System.out.println(c1.hashCode());
        System.out.println(c2.hashCode());
    }
}

class Card {
    String shape;
    int number;

    Card() {
        this("Heart", 8);
    }

    Card(String shape, int number) {
        this.shape = shape;
        this.number = number;
    }

    public String toString() {
        return "shape : " + shape + ", number : " + number;
    }

    public boolean equals(Object obj) {
        if(!(obj instanceof Card))
            return false;

        Card c = (Card) obj;
        return this.shape.equals(c.shape) && this.number == c.number;
    }

    public int hashCode() {
        return Objects.hash(shape, number);
    }
}

결과
shape : Heart, number : 8
shape : Heart, number : 8
true
-2137388957
-2137388957

  • public int hashCode() { return Objects.hash(shape, number); } : hashCode() 오버라이딩 하는 방법

📌String 클래스

문자열을 다루기 위한 클래스. 데이터(char[]) + 메서드(문자열 관련)

내용을 변경할 수 없는 불변(immutable) 클래스

String a = "a";
String b = "b";
a = a + b; // a = "ab"

  • 0x100 번지의 값이 "ab"로 바뀌는게 아니라 새로운 문자열 객체가 만들어진다.

덧셈 연산자(+)를 이용한 문자열 결합은 성능이 떨어진다. 문자열의 결합이나 변경이 잦다면, 내용 변경이 가능한 StringBuffer를 사용해야 한다.

문자열의 비교

String str1 = "abc"; // 문자열 리터럴 "abc"의 주소가 str1에 저장됨
String str2 = "abc"; // 문자열 리터럴 "abc"의 주소가 str2에 저장됨
String str3 = new String("abc"); // 새로운 String 인스턴스를 생성
String str4 = new String("abc"); // 새로운 String 인스턴스를 생성

  • new 연산자를 이용하면 문자열의 내용이 같아도 항상 새로운 객체가 생성된다.

문자열 리터럴

문자열 리터럴은 프로그램 실행 시 자동으로 생성된다.(constant pool에 저장)

같은 내용의 문자열 리터럴은 하나만 만들어진다.

String s1 = "AAA";
String s2 = "AAA";
String s3 = "AAA";

빈 문자열("", empty string)

내용이 없는 문자열. 길이가 0인 char형 배열을 저장하는 문자열
String str = "";

길이가 0인 배열을 생성하는 것은 어느 타입이나 가능
char[] chArr = new char[0]; : 길이가 0인 char배열
int[] iArr = {}; : 길이가 0인 int배열

문자(char)와 문자열(String)의 초기화
String s = ""; : 빈 문자열로 초기화
char c =' '; : 공백으로 초기화

String 클래스의 생성자와 메서드

String(char[] value) 생성자

: 주어진 문자열(value)을 갖는 String 인스턴스를 생성한다.

char[] c = {'H', 'e', 'l', 'l', 'o'};
String s = new String(c);

s = "Hello"

  • char[] 배열을 String으로 바꿀 때 사용하는 생성자
  • String을 char[] 배열로 바꾸는 방법 - toCharArray() 메서드 사용

String(StringBuffer buf) 생성자

: StringBuffer 인스턴스가 갖고 있는 문자열과 같은 내용의 String 인스턴스를 생성한다.

StringBuffer sb = new StringBuffer("Hello");
String s = new String(sb);

s = "Hello"

  • StringBuffer를 String으로 바꿀 때 사용하는 생성자

char charAt(int index)

: 지정된 위치(index)에 있는 문자 1개를 반환한다.(index는 0부터 시작)

String s = "Hello";
char c = s.charAt(1);

c = 'e'

index01234
문자Hello

int compareTo(String str)

: 문자열(str)을 사전 순서로 바교한다. 같으면 0, 왼쪽이 작으면 -1, 오른쪽이 작으면 1

int i = "aaa".compareTo("aaa");
int i2 = "aaa".compareTo("bbb");
int i3 = "bbb".compareTo("aaa");

i = 0
i2 = -1
i3 = 1

  • 정렬할 때 사용

String concat(String str)

: 문자열(str)을 뒤에 덧붙인다.

String s = "Hello";
String s2.s.concat(" World");

s2 = "Hello World"

boolean contains(CharSequence s)

: 지정된 문자열(s)이 포함되었는지 검사한다.

String s = "abcdefg";
boolean b = s.contains("bc");

b = true

  • 문자열 배열을 다루는 클래스들(CharBuffer, Segment, String, StringBuffer, StringBuilder 등)은 서로 공통 조상이 없다. 그래서 CharSequence 라는 인터페이스를 만들고 이것을 다 구현하게 만듦으로써 CharSequence를 매개변수로 두게 되면 이 인터페이스를 구현한 클래스들을 전부 매개변수로 사용할 수 있게 된다.

boolean endsWith(String suffix)

: 지정된 문자열(suffix)로 끝나는지 검사한다.

String file = "Hello.txt";
boolean b = file.endsWith("txt");

b = true

boolean startsWith(String prefix)

: 지정된 문자열(suffix)로 시작하는지 검사한다.

String s = "java.lang.Object";
boolean b1 = s.startsWith("java");
boolean b2 = s.startsWith("lang");

b1 = true
b2 = false

equalsIgnoreCase(String str)

: 문자열과 String 인스턴스의 문자열을 대소문자 구분 없이 비교한다.

String s = "Hello";
boolean b = s.equalsIgnoreCase("HELLO");

b = true

int indexOf(int ch)

: 주어진 문자(ch)가 문자열에 존재하는지 확인하여 위치(index)를 알려준다. 못 찾으면 -1을 반환

String s = "Hello";
int idx1 = s.indexOf('o');
int idx2 = s.indexOf('q');

idx1 = 4
idx2 = -1

int indexOf(int ch, int pos)

: 주어진 문자(ch)가 문자열에 존재하는지 지정된 위치(pos)부터 확인하여 위치(index)를 알려준다. 못 찾으면 -1을 반환

String s = "Hello";
int idx1 = s.indexOf('e', 0);
int idx2 = s.indexOf('e', 2);

idx1 = 1
idx2 = -1

index01234
문자Hello

int indexOf(String str)

: 주어진 문자열(str)이 존재하는지 확인하여 그 위치(index)를 알려준다. 못 찾으면 -1을 반환

String s = "ABCDEFG";
int idx = s.indexOf("CD");

idx = 2

  • 문자열의 시작 인덱스를 반환한다.

int lastIndexOf(int ch)

: 지정된 문자(ch)를 문자열의 오른쪽 끝에서부터 찾아서 위치(index)를 알려준다. 못 찾으면 -1을 반환

String s = "java.lang.Object";
int idx1 = s.lasIndexOf('.');
int idx2 = s.indexOf('.');

idx1 = 9
idx2 = 4

index0123456789101112131415
문자java.lang.Object

int lastIndexOf(String str)

: 지정된 문자열을 인스턴스의 문자열 오른쪽 끝에서부터 찾아서 위치(index)를 알려준다. 못 찾으면 -1을 반환

String s = "java.lang.java";
int idx1 = s.lasIndexOf("java");
int idx2 = s.indexOf("java");

idx1 = 10
idx2 = 0

index012345678910111213
문자java.lang.java
  • 문자열의 시작 인덱스를 반환한다.

int length()

: 문자열의 길이를 알려준다.

String s = "Hello";
int l = s.length();

l = 5

String[] split(String regex)

: 문자열을 지정된 분리자(regex)로 나누어 문자열 배열에 담아 반환한다.

String animals = "dog,cat,bear";
String[] arr = animals.split(",");

arr[0] = "dog"
arr[1] = "cat"
arr[2] = "bear"

String[] split(String regex, int limit)

: 문자열을 지정된 분리자(regex)로 나누어 문자열 배열에 담아 반환한다. 단, 문자열 전체를 지정된 수(limit)로 자른다.

String animals = "dog,cat,bear";
String[] arr = animals.split(",", 2);

arr[0] = "dog"
arr[1] = "cat,bear"

String substring(int begin, int end)

: 주어진 시작 위치(begin)부터 끝 위치(end) 범위에 포함된 문자열을 얻는다. 이 때, 시작 위치(begin)는 포함되지만 끝 위치(end)는 포함되지 않는다.

String s = "java.lang.Object";
String sub1 = s.substring(10);
String sub2 = s.substring(5, 9);

sub1 = Object
sub2 = lang

index0123456789101112131415
문자java.lang.Object

String toLowerCase()

: 모든 문자열을 소문자로 변환하여 반환한다.

String s = "Hello";
String lower = s.toLowerCase();

lower = "hello"

String toUpperCase()

: 모든 문자열을 대문자로 변환하여 반환한다.

String s = "Hello";
String upper = s.toUpperCase();

upper = "HELLO"

String trim()

: 문자열의 왼쪽 끝과 오른쪽 끝에 있는 공백을 없애준다. 이 때, 문자열 중간에 있는 공백은 제거되지 않는다.

String s = "  Hello World   ";
String trim = s.trim();

trim = "Hello World"

static String valueOf(boolean b or char c or int i or double d or Object obj)

: 지정된 값(기본형, 참조형 변수)을 문자열로 반환한다. 단, 참조변수는 toString()을 호출한 결과를 반환한다.

String b = String.valueOf(true);
String c = String.valueOf('a');
String i = String.valueOf(100);
String d = String.valueOf(100.0);

java.util.Date dd = new java.util.Date();
String date = String.valueOf(dd);

b = "true"
c = "a"
i = "100"
d = "100.0"
date = "Sun Feb 19 22:42:00 KST 2023"

  • true + "" 을 해도 문자열 "true"로 변환되지만 valueOf가 더 성능이 좋다.

String join(CharSequence delimiter, CharSequence... elements)

: 여러 문자열 사이에 구분자를 넣어 결합한다.

String animals = "dog,cat,bear";
String[] arr = animals.split(","); // animals 문자열을 ',' 구분자로 나눠서 배열에 저장ㅇ
String str = String.join("-", arr); // 배열의 문자열을 '-'로 구분해서 결합

System.out.println(str);

dog-cat-bear

문자열과 기본형 간의 변환

숫자를 문자열로 바꾸는 방법

int num = 100;
String s1 = num + ""; // 편리하다.
String s2 = String.valueOf(num); // 속도가 더 빠르다.

문자열을 숫자로 바꾸는 방법

int i = Integer.parseInt("100"); // 예전 방법
int i2 = Integer.valueOf("100); // 기본형 전부 valueOf로 사용할 수 있다.
Integer i2 = Integer.valueOf("100); // 원래는 반환 타입이 Integer 이다.
  • Boolean.valueOf, Short.valueOf, Double.valueOf 등 기본형 모두 valueOf 사용 가능

  • Integer.valueOf를 쓰게 되면 반환 타입은 Integer 참조형 타입이다.

  • 그러나 기본형 타입인 int를 써도 된다. 이유는 오토 박싱을 통해 Integer 타입을 자동으로 int 타입으로 바꿔주기 때문이다.


0개의 댓글