본문 바로가기
Java/이것이 자바다

기본 API 클래스 (2)

by k-mozzi 2023. 4. 14.
반응형
Preface

 

각 클래스에서 제공하는 메소드의 양이 정말 많지만, 대부분의 메소드는 지금까지 이런저런 코드를 작성하며 한 번 쯤 보고 사용해 봤던 것들이라 쉽게 이해할 수 있었다.

 

또, 메소드들의 이름이 직관적이라 어떤 동작을 하는 메소드인지 헷갈릴 걱정은 하지 않아도 될 것 같다.

 

다만 필요할 때 적절한 메소드를 사용하려면 적어도 자주 사용되는 것들의 이름은 확실히 암기해야 할 것 같다.

 

본문에 정규 표현식에 관한 내용도 있는데, 이 부분은 필요할 때 다시 찾아 공부할 생각이다.

 

 

 

아 그리고 박싱과 언박싱의 개념이 확 와닿지 않아 gpt에게 몇 가지 질문을 했다.

Q1: boxing과 unboxing은 언제 왜 일어나는거야?

A1: boxing과 unboxing은 기본 데이터 타입과 래퍼 클래스 객체 간의 자동 변환을 말합니다.
boxing은 기본 데이터 타입을 해당하는 래퍼 클래스의 객체로 자동으로 변환하는 것을 의미합니다.
예를 들어, int 타입 변수를 Integer 객체로 할당하면 자동으로 boxing이 발생합니다.
int i = 10;
Integer integer = i; // boxing 발생​

unboxing은 래퍼 클래스 객체를 해당하는 기본 데이터 타입으로 자동으로 변환하는 것을 의미합니다. 예를 들어, Integer 객체를 int 타입 변수에 할당하면 자동으로 unboxing이 발생합니다.
Integer integer = new Integer(10);
int i = integer; // unboxing 발생​

boxing과 unboxing은 일반적으로 제네릭과 관련된 코드에서 발생합니다. 제네릭은 컴파일 시점에 타입 안정성을 보장하기 위해 사용되지만, 기본 데이터 타입은 사용할 수 없기 때문에 boxing과 unboxing이 필요합니다.
List<Integer> list = new ArrayList<>();
list.add(10); // boxing 발생
int i = list.get(0); // unboxing 발생​

또한, boxing과 unboxing은 자바에서의 연산에서도 발생할 수 있습니다. 예를 들어, 기본 데이터 타입과 래퍼 클래스 객체를 함께 연산할 때 자동으로 boxing과 unboxing이 발생합니다.
int i = 10;
Integer integer = 20;
int result = i + integer; // unboxing 후 연산이 수행됨​

boxing과 unboxing은 코드의 편의성을 높이기 위한 기능이지만, 불필요한 boxing과 unboxing은 성능 저하를 가져올 수 있으므로 주의해서 사용해야 합니다.




Q2: 포장 객체에서 포장하고 있는 기본 타입 값은 외부에서 변경할 수 없다고 하는데, 여기서 외부란 어떤 범위를 의미하는 거야?

A2: 포장 객체에서 포장하고 있는 기본 타입 값은 외부에서 변경할 수 없습니다. 여기서 외부는 해당 포장 객체의 참조를 가진 코드 영역에서 변경할 수 없다는 것을 의미합니다. 즉, 포장 객체를 생성한 코드 영역 내에서는 해당 포장 객체가 가리키는 기본 타입 값에 대한 변경이 가능하지만, 다른 코드 영역에서는 해당 값을 변경할 수 없습니다. 이것이 가능하다면, 포장 객체를 사용하는 이점이 없어지고 기본 타입 변수와 마찬가지로 동작할 것입니다.

 

6. String 클래스

 

 

- 소스상에서 문자열 리터럴은 String 객체로 자동 생성되지만, String 클래스의 다양한 생성자를 이용해 직접 String 객체를 생성할 수도 있다.

// 배열 전체를 String 객체로 생성
String str = new String(byte[] bytes);
// 지정한 문자셋으로 디코딩
String str = new String(byte[] bytes, String charsetName);

// 배열의 offset 인덱스 위치부터 length만큼 String 객체로 생성
String str = new String(byte[] bytes, int offset, int length);
// 지정한 문자셋으로 디코딩
String str = new String(byte[] bytes, int offset, int length, String charsetName);
package ch11;

public class ByteToStringExample {

	public static void main(String[] args) {

		byte[] bytes = { 72, 101, 108, 108, 111, 32, 74, 97, 118, 97 };

		String str1 = new String(bytes);
		System.out.println(str1);
		String str2 = new String(bytes, 6, 4);	// 자바에서의 슬라이싱 방법인듯?: 인덱스 6번부터 4개 출력
		System.out.println(str2);
	}

}

 

 

- System.in.read( ) 메소드: 키보드에서 입력한 내용을 매개값으로 주어진 바이트 배열에 저장하고 읽은 바이트 수를 리턴한다.

package ch11;

import java.io.IOException;

public class KeyboardToStringExample {

	public static void main(String[] args) throws IOException {

		byte[] bytes = new byte[100];

		System.out.print("input: ");
		int readByteNo = System.in.read(bytes);

		String str = new String(bytes, 0, readByteNo - 1);
		System.out.println(str);
	}

}

 

 

- String 메소드

리턴 타입 메소드명(매개 변수) 설명
char charAt(int index) 주어진 인덱스의 문자 리턴
boolean equals(Object anObject) 두 문자열을 비교
byte[ ] getBytes( ) 시스템의 기본 문자셋으로 인코딩된 byte 배열을 리턴
byte[ ] getBytes(Charset charset) 주어진 문자셋으로 인코딩한 byte 배열을 리턴
int indexOf(String str) 문자열 내에서 주어진 문자열의 위치를 리턴: 주어진 문자열이 포함되어 있지 않으면 -1을 리턴
int length( ) 총 문자의 수를 리턴
String replace(CharSequence target, CharSequence replacement) target 부분을 replacement로 대치한 새로운 문자열을 리턴
String substring(int beginindex) beginindex 위치에서 끝까지 잘라낸 새로운 문자열을 리턴
String substring(int beginindex, int endindex) beginindex 위치에서 endindex 전까지 잘라낸 새로운 문자열을 리턴: 마지막 인덱스 제외
String toLowerCase( ) 알파벳 소문자로 변경한 새로운 문자열을 리턴
String toUpperCase( ) 알파벳 대문자로 변경한 새로운 문자열을 리턴
String trim( ) 앞뒤 공백을 제거한 새로운 문자열을 리턴: 중간의 공백은 제거하지 않는다.
String valueOf(int i)
valueOf(double d)
기본 타입값을 문자열로 리턴

 

 

- 기본 타입 변수의 값을 비교할 땐 "==" 연산자를 사용하지만, 문자열을 비교할 땐 "==" 연산자를 사용하지 않는다.

1) "==" 연산자는 각 변수에 저장된 번지를 비교하기 때문이다.

2) 자바는 문자열 리터럴이 동일하다면 동일한 String 객체를 참조한다.

3) String 객체의 문자열만 비교하고 싶다면 equals( ) 메소드를 사용해야 한다.

 

 

- getBytes(Charset charset) 메소드는 UnsupportedEncodingException 예외 처리가 필요하다.

 

 

- 바이트 배열을 다시 문자열로 변환(디코딩)할 땐 인코딩된 바이트 배열의 문자셋 종류에 따라 디코딩 방법이 다르다.

1) 시스템의 기본 문자셋을 이용한 경우: String(byte[ ] bytes);

2) 시스템의 기본 문자셋과 다른 문자셋을 이용한 경우: String str = new String(byte[ ] bytes, String charsetName);

 

 

- String 객체의 문자열은 변경이 불가한 특성을 지닌다.

→ 변경하거나 수정한 문자열은 기존 문자열의 수정본이 아니라 완전히 새로운 문자열이다.

 

 

- equalsIgnoreCase( ) 메소드: 알파벳의 대소문자 구문 없이 문자열이 동일한지 판한한다.

package ch11;

public class EqualsIgnoreExample {

	public static void main(String[] args) {

		String s1 = "QweRt";
		String s2 = "qWErT";

		System.out.println(s1.equals(s2));
		System.out.println(s1.equalsIgnoreCase(s2));
	}

}

 


 

7. StringTokenizer 클래스

 

 

- 문자열이 특정 구분자(delimiter)로 연결된 경우, 구분자를 기준으로 문자열을 분리할 수 있다.

1) split( ): 정규 표현식으로 구분

2) StringTokenizer: 문자로 구분

 

 

- split( ) 메소드 호출 예시

String[] result = "문자열".split("정규표현식");

String[] names = text.split("&|,|-");
// 파이프 기호(|)로 연결하여 여러 종류의 구분자를 동시에 구분할 수 있다.

 

 

- StringTokenizer 클래스는 문자열이 한 종류의 구분자로 연결된 경우에 사용한다.

StringTokenizer st = new StringTokenizer("문자열", "구분자");
// 구분자를 생략하면 공백이 기본 구분자가 된다.

 

 

- StringTokenizer의 메소드

리턴 타입 메소드 설명
int countTokens( ) 꺼내지 않고 남아 있는 토큰의 수
boolean hasMoreTokens( ) 남이 있는 토큰이 있는지 여부
String nextToken( ) 토큰을 하나씩 꺼내옴

 


 

8. StringBuffer, StringBuilder 클래스

 

 

- 문자열을 결합하는 "+" 연산자를 사용할수록 String 객체의 수가 늘어나 프로그램 성능이 저하된다.

→ String은 내부의 문자열을 수정할 수 없어 새로운 문자열을 생성해 리턴하기 때문이다.

 

 

- 문자열 변경 작업이 많을 경우엔 java.lang 패키지의 StringBuffer 혹은 StringBuilder 클래스를 사용하는 것이 좋다.

1) 두 클래스 모두 내부 버퍼에 문자열을 저장해두고, 그 안에서 추가, 수정, 삭제 작업을 할 수 있다.

2) StringBuffer: 멀티 스레드 환경에서 사용할 수 있도록 동기화가 적용되어 있어 스레드에 안전하다.

3) StringBuilder: 단일 스레드 환경에서만 사용할 수 있다.

 

 

- StringBuilder 클래스에서 사용할 수 있는 생성자

1) 기본 생성자인 StringBuilder( ): 16개의 문자를 저장할 수 있는 초기 버퍼를 생성한다.

2) StringBuilder(int capacity): capacity로 주어진 개수만큼 문자를 저장할 수 있는 초기 버퍼를 생성한다.

→ StringBuilder는 버퍼가 부족할 경우 자동으로 버퍼 크기를 늘리므로 초기 버퍼의 크기가 중요하지 않다.

3) StringBuilder(String str): str로 주어진 매개값을 버퍼의 초기값으로 저장한다.

 

 

- StringBuilder의 메소드

메소드 설명
append(...) 문자열 끝에 주어진 매개값을 추가: "." 연산자로 여러 개를 이어서 사용할 수 있다.
insert(int offset, ...) 문자열 중간에 주어진 매개값을 추가
delete(int start, int end) 문자열의 일부분을 삭제
deleteCharAt(int index) 문자열에서 주어진 index의 문자를 삭제
replace(int start, int end, String str) 문자열의 일부분을 다른 문자열로 대치
reverse( ) 문자열의 순서를 뒤바꿈
setCharAt(int index, char ch) 문자열에서 주어진 index의 문자를 다른 문자로 대치

 


 

9. 정규 표현식과 Pattern 클래스

 

 

- 정규 표현식을 작성하는 방법: API doc에서 java.util.regex.Pattern 클래스를 찾아 Summary of regular-expression constructs를 참조하면 된다.

 

 

- 정규 표현식과 관련된 기본적인 기호

기호 설명
[ ] 한 개의 문자 [abc] a, b, c 중 하나의 문자
[^abc] a, b, c 이외의 하나의 문자
[a-zA-Z] a~z, A~Z 중 하나의 문자
\d 한 개의 숫자, [0-9]와 동일
\s 공백
\w 한 개의 알파벳 또는 한 개의 숫자, [a-zA-Z_0-9]와 동일
? 없음 또는 한 개
* 없음 또는 한 개 이상
+ 한 개 이상
{n} 정확히 n개
{n,} 최소한 n개
{n, m} n개에서부터 m개까지
( ) 그룹핑

 

 

- java.util.regex.Pattern 클래스의 matches( ) 메소드: 문자열을 정규 표현식으로 검증하는 기능

boolean result = Pattern.matches("정규식", "검증할 문자열");
// 첫 번째 매개값은 정규표현식, 두 번재 매개값은 검증할 문자열이다.

 


 

10. Arrays 클래스

 

 

- Arrays 클래스는 배열 조작 기능(배열 복사, 항목 정렬, 항목 검색 등)을 가지고 있다.

→ 모든 메소드는 정적이므로 Arrays 클래스로 바로 사용할 수 있다.

 

 

- System.arraycopy( ) 메소드: 배열을 단순히 복사한다.

System.arraycopy(원본배열, 원본시작인덱스, 타겟배열, 타겟시작인덱스, 복사개수);
// 5개의 매개값이 필요하다.
package ch11;

import java.util.Arrays;

public class ArrayCopyExample {

	public static void main(String[] args) {

		char[] arr1 = { 'J', 'A', 'V', 'A' };

		char[] arr2 = Arrays.copyOf(arr1, arr1.length);
		System.out.println(Arrays.toString(arr2));

		char[] arr3 = Arrays.copyOfRange(arr1, 1, 3);
		System.out.println(Arrays.toString(arr3));

		char[] arr4 = new char[arr1.length];
		System.arraycopy(arr1, 0, arr4, 0, arr1.length);
		for (int i = 0; i < arr4.length; i++) {
			System.out.println("arr4[" + i + "]=" + arr4[i]);
		}
	}

}

 

 

- Arrays 클래스의 메소드

리턴 타입 메소드 이름 설명
int binarySearch(배열, 찾는값) 전체 배열 항목에서 찾는 값이 있는 인덱스 리턴
타겟 배열: 복사한 배열 copyOf(원본배열, 복사할길이: 인덱스 아니고 단순히 복사할 값의 개수이다.) 원본 배열의 0번 인덱스에서 복사할 길이만큼 복사한 배열 리턴, 복사할 길이는 원본 배열의 길이보다 커도 되며, 타겟 배열의 길이가 된다.
타켓 배열 copyOfRange(원본배열, 시작인덱스, 끝인덱스: 마지막 인덱스 제외) 원본 배열의 시작 인덱스에서 끝 인덱스까지 복사한 배열 리턴
boolean deepEquals(배열, 배열) 두 배열의 깊은 비교(중첩 배열의 항목까지 비교)
boolean equals(배열, 배열) 두 배열의 얕은 비교(중첩 배열의 항목은 비교하지 않음)
void fill(배열, 값) 전체 배열 항목에 동일한 값을 저장
void fill(배열, 시작인덱스, 끝인덱스, 값) 시작 인덱스부터 끝 인덱스까지의 항목에만 동일한 값을 저장
void sort(배열) 배열의 전체 항목을 오름차순으로 정렬
String toString(배열) "[값1, 값2, ...]"와 같은 문자열 리턴

 

 

- 기본 타입 또는 String 배열은 Arrays.sort( ) 메소드의 매개값으로 지정해주면 자동으로 오름차순 정렬이 된다.

→ but, 사용자 정의 클래스 타입은 클래스가 Comparable 인터페이스를 구현하고 있어야 정렬이 된다.

package ch11;

import java.util.Arrays;

class Member2 implements Comparable<Member2> {
	String name;

	Member2(String name) {
		this.name = name;
	}

	@Override
	public int compareTo(Member2 o) {
		return name.compareTo(o.name);
	}
}

public class SortExample {

	public static void main(String[] args) {

		int[] scores = { 99, 97, 98 };
		Arrays.sort(scores);
		for (int i = 0; i < scores.length; i++) {
			System.out.println("scores[" + i + "]=" + scores[i]);
		}
		System.out.println();

		String[] names = { "c", "a", "b" };
		Arrays.sort(names);
		for (int i = 0; i < names.length; i++) {
			System.out.println("names[" + i + "]=" + names[i]);
		}
		System.out.println();

		Member2 m1 = new Member2("b");
		Member2 m2 = new Member2("a");
		Member2 m3 = new Member2("c");
		Member2[] members = { m1, m2, m3 };
		Arrays.sort(members);
		for (int i = 0; i < members.length; i++) {
			System.out.println("members[" + i + "].name=" + members[i].name);
		}
	}

}

 

 

- compareTo( ) 메소드의 리턴값

1) 오름차순일 때: 자신이 매개값보다 낮을 경우 음수, 같은 경우 0, 높을 경우 양수 리턴

2) 내림차순일 때: 자신이 매개값보다 낮을 경우 양수, 같은 경우 0, 높을 경우 음수 리턴

 

 

- 배열 검색: 배열 항목에서 특정 값이 위치한 인덱스를 얻는 것

→ Arrays.sort( ) 메소드로 항목들을 오름차순 정렬한 후 Arrays.binarySearch( ) 메소드로 항목을 찾아야 한다.

 


 

11. Wrapper(포장) 클래스

 

 

- 포장 객체: 기본 타입의 값을 갖는 객체

→ 포장하고 있는 기본 타입 값은 외부에서 변경할 수 없다.

 

 

- 박싱(Boxing): 기본 타입의 값을 포장 객체로 만드는 과정

 

 

- 언박싱(Unboxing): 포장 객체에서 기본 타입의 값을 얻어내는 과정

1) 포장 클래스의 생성자 매개값으로 기본 타입의 값 또는 문자열을 넘겨주면 된다.

Integer obj = new Integer(1000);

2) 각 포장 클래스마다 가지고 있는 정적 valueOf( ) 메소드를 사용할 수도 있다.

Integer obj = Integer.valueOf(1000);

 

 

- 자동 박싱: 포장 클래스 탕입에 기본값이 대입될 경우 발생

Integer obj = 100;

 

 

- 자동 언박싱: 기본 타입에 포장 객체가 대입될 경우 발생

Integer obj = new Integer(200);
int value1 = obj;
int value2 = obj + 100;

// 컬렉션 객체에 int 값을 저장하면 자동 박싱이 일어나 Integer 객체가 저장된다.

 

 

- 문자열을 기본 타입 값으로 변환

기본 타입의 값을 이용
byte num = Byte.parseByte("10");
short num = Short.parseShort("100");
int num = Integer.parseInt("1000");
long num = Long.parseLong("10000");
float num = Float.parseFloat("2.5F");
double num = Double.parseDouble("3.5");
boolean num = Boolean.parseBoolean("true");

 

 

- 포장 객체는 내부의 값을 비교할 때 "==" 연산자와 "!=" 연산자를 사용할 수 없다.

1) 내부 값의 비교가 아닌 포장 객체의 참조를 비교하기 때문이다.

2) but, boolean/char/byte/short/int는 박싱된 채로 값을 비교할 수 있다. (크기 제한 있음)

3) 그래도 되도록이면 equals( ) 메소드로 내부 값을 비교하는 것이 좋다.

 

728x90
반응형

댓글