[Java] 김영한의 실전 자바 - 중급편 섹션3,4 String ,래퍼,Class 클래스
○ String 클래스
🟢 String 클래스 구조
public final class String {
//문자열 보관
private final char[] value;// 자바 9 이전
private final byte[] value;// 자바 9 이후
//여러 메서드
public String concat(String str) {...}
public int length() {...}
...
자바에서 문자 하나를 표현하는 char 는 2byte 를 차지한다. 단순 영어, 숫자로만 표현된 경우 1byte 를 사용하고, 그렇지 않은 나머지의 경우 2byte 인 UTF-16 인코딩을 사용한다. 따라서 메모리를 더 효율적으로 사용할 수 있게 변경되었다.
🟢 String 기능(메서드)
- length() : 문자열의 길이를 반환한다.
- charAt(int index) : 특정 인덱스의 문자를 반환한다.
- substring(int beginIndex, int endIndex) : 문자열의 부분 문자열을 반환한다.
- indexOf(String str) : 특정 문자열이 시작되는 인덱스를 반환한다.
- toLowerCase() , toUpperCase() : 문자열을 소문자 또는 대문자로 변환한다.
- trim() : 문자열 양 끝의 공백을 제거한다. concat(String str) : 문자열을 더한다.
🟢 String 비교
String 클래스 비교할 때는 == 비교가 아니라 항상 equals() 비교를 해야한다.
- 동일성(Identity): == 연산자를 사용해서 두 객체의 참조가 동일한 객체를 가리키고 있는지 확인
- 동등성(Equality): equals() 메서드를 사용하여 두 객체가 논리적으로 같은지 확인
public class StringEqualsMain1 {
public static void main(String[] args) {
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println("new String() == 비교: " + (str1 == str2));
System.out.println("new String() equals 비교: " + (str1.equals(str2)));
String str3 = "hello";
String str4 = "hello";
System.out.println("리터럴 == 비교: " + (str3 == str4));
System.out.println("리터럴 equals 비교: " + (str3.equals(str4)));
}
}
new String() == 비교: false
new String() equals 비교: true
리터럴 == 비교: true
리터럴 equals 비교: true
🟢 문자열 리터럴, 문자열 풀
- String str3 = "hello" 같이 문자열 리터럴을 사용하는 경우 자바는 메모리 효율성과 성능 최적화를 위해 문자열 풀을 사용한다.
- 자바가 실행되는 시점에 클래스에 문자열 리터럴이 있으면 문자열 풀에 String 인스턴스를 미리 만들어둔다. 이때 같은 문자열이 있으면 만들지 않는다.
- 따라서 위 예제처 문자열 리터럴을 사용하는 경우 같은 참조값을 가지므로 == 비교에 성공한다.
- !!! 문자열 비교는 항상 equals() 를 사용해서 동등성 비교를 해야 한다.
참고로 문자열 풀은 힙 영역을 사용한다. 그리고 문자열 풀에서 문자를 찾을 때는 해시 알고리즘을 사용하기 때문 에 매우 빠른 속도로 원하는 String 인스턴스를 찾을 수 있다. 해시 알고리즘은 뒤에서 설명한다.
🟢 String 클래스 - 불변 객체
String 은 불변 객체이다. 따라서 생성 이후에 절대로 내부의 문자열 값을 변경할 수 없다.
🟢 String 클래스 - 주요 메서드1
문자열 정보 조회
- length() : 문자열의 길이를 반환한다.
- isEmpty() : 문자열이 비어 있는지 확인한다. (길이가 0)
- isBlank() : 문자열이 비어 있는지 확인한다. (길이가 0이거나 공백(Whitespace)만 있는 경우), 자바 11
- charAt(int index) : 지정된 인덱스에 있는 문자를 반환한다.
문자열 비교
- equals(Object anObject) : 두 문자열이 동일한지 비교한다.
- equalsIgnoreCase(String anotherString) : 두 문자열을 대소문자 구분 없이 비교한다.
- compareTo(String anotherString) : 두 문자열을 사전 순으로 비교한다.
- compareToIgnoreCase(String str) : 두 문자열을 대소문자 구분 없이 사전적으로 비교한다.
- startsWith(String prefix) : 문자열이 특정 접두사로 시작하는지 확인한다.
- endsWith(String suffix) : 문자열이 특정 접미사로 끝나는지 확인한다.
문자열 검색
- contains(CharSequence s) : 문자열이 특정 문자열을 포함하고 있는지 확인한다.
- indexOf(String ch) / indexOf(String ch, int fromIndex) : 문자열이 처음 등장하는 위치를 반환한다.
- lastIndexOf(String ch) : 문자열이 마지막으로 등장하는 위치를 반환한다.
문자열 조작 및 변환
- substring(int beginIndex) / substring(int beginIndex, int endIndex) : 문자열의 부분 문자열을 반환한다.
- concat(String str) : 문자열의 끝에 다른 문자열을 붙인다.
- replace(CharSequence target, CharSequence replacement) : 특정 문자열을 새 문자열로 대체 한다.
- replaceAll(String regex, String replacement) : 문자열에서 정규 표현식과 일치하는 부분을 새 문자열로 대체한다. replaceFirst(String regex, String replacement) : 문자열에서 정규 표현식과 일치하는 첫 번째 부분을 새 문자열로 대체한다.
- toLowerCase() / toUpperCase() : 문자열을 소문자나 대문자로 변환한다.
- trim() : 문자열 양쪽 끝의 공백을 제거한다. 단순 Whitespace 만 제거할 수 있다.
- strip() : Whitespace 와 유니코드 공백을 포함해서 제거한다. 자바 11
문자열 분할 및 조합
- split(String regex) : 문자열을 정규 표현식을 기준으로 분할한다.
- join(CharSequence delimiter, CharSequence... elements) : 주어진 구분자로 여러 문자열을 결합한다.
기타 유틸리티
- valueOf(Object obj) : 다양한 타입을 문자열로 변환한다.
- toCharArray(): 문자열을 문자 배열로 변환한다.
- format(String format, Object... args) : 형식 문자열과 인자를 사용하여 새로운 문자열을 생성한다.
- matches(String regex) : 문자열이 주어진 정규 표현식과 일치하는지 확인한다.
🪄참고: CharSequence 는 String , StringBuilder 의 상위 타입.문자열을 처리하는 다양한 객체를 받을 수 있다.
🟢 StringBuilder - 가변 String
불변인 String 의 내부 값은 변경할 수 없다. 따라서 변경된 값을 기반으로 새로운 String 객체를 생성한다.
StringBuilder 는 가변 String이다.StringBuilder 는 사이드이펙트를 주의하자.
보통 문자열을 변경하는 동안만 사용하다가 문자열 변경이 끝나면 안전한(불변) String 으로변환하는 것이 좋다.
☀️ StringBuilder 직접 사용하는 것이 더 좋은 경우
- 반복문에서 반복해서 문자를 연결할 때
- 조건문을 통해 동적으로 문자열을 조합할 때
- 복잡한 문자열의 특정 부분을 변경해야 할 때
- 매우 긴 대용량 문자열을 다룰 때
public final class StringBuilder {
char[] value;// 자바 9 이전
byte[] value;// 자바 9 이후
//여러 메서드
public StringBuilder append(String str) {...}
public int length() {...}
...
}
public static void main(String[] args) {
StringBuilder sb = new StringBuilder(); // StringBuilder 객체 생성
sb.append("A"); // 여러 문자열 추가
sb.append("B");
sb.append("C");
sb.append("D");
System.out.println("sb = " + sb);
sb.insert(4, "Java"); //해당인덱스위치에 문자열삽입
System.out.println("insert = " + sb);
sb.delete(4, 8);
System.out.println("delete = " + sb); //삭제
sb.reverse();
System.out.println("reverse = " + sb); // 뒤집기
//StringBuilder -> String
String string = sb.toString(); // String생성
System.out.println("string = " + string);
}
sb = ABCD
insert = ABCDJava
delete = ABCD
reverse = DCBA
string = DCBA
🟢 String 최적화
자바 컴파일러는 아래와 같이 문자열 리터 최적화를 시행. (다만 문자열을 루프안에서 문자열을 더하는 경우는 최적화X)
String result = str1 + str2;
String result = new StringBuilder().append(str1).append(str2).toString();
🟢 메서드 체이닝
아래와 같이 반환된 참조값을 바로 메소드 호출에 사용할 수 있다.
public class ValueAdder {
private int value;
public ValueAdder add(int addValue) {
value += addValue;
return this; // 자기 자신의 참조값을 반환
}
public int getValue() {
return value;
}
}
public static void main(String[] args) {
ValueAdder adder = new ValueAdder();
int result = adder.add(1).add(2).add(3).getValue();
System.out.println("result = " + result);
}
○ 래퍼, Class 클래스
🟢 기본형의 한계
- 객체가 아니라 참조X,제네릭사용X,메서드제공X
- null 값을 가질 수 없다.
예를들어, int가 아니라 아래와 같이 MyInteger를 설계하면 는 객체이므로 자신이 가진 메서드를 편리하게 호출할 수 있다.
또한 값이 없다는 null을 사용할 수 있다.
public class MyInteger {
private final int value;
public MyInteger(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public int compareTo(int target) {
if (value < target) {
return -1;
} else if (value > target) {
return 1;
} else {
return 0;
}
}
@Override
public String toString() {
return String.valueOf(value); //숫자를 문자로 변경
}
}
🟢 래퍼 클래스
- 박싱은 Integer.valueOf()를 사용. 여기에는 미리값을 만들고 재사용하는 성능 최적화 기능이 있다.
- 언박싱은 intValue()를 사용한다.
Integer newInteger = new Integer(10); //미래에 삭제 예정, 대신에 valueOf() 사용
Integer integerObj = Integer.valueOf(10); //-128 ~ 127 자주 사용하는 숫자 값 재사용, 불변
Long longObj = Long.valueOf(100);
Double doubleObj = Double.valueOf(10.5);
System.out.println("newInteger = " + newInteger);
System.out.println("integerObj = " + integerObj);
System.out.println("longObj = " + longObj);
System.out.println("doubleObj = " + doubleObj);
System.out.println("내부 값 읽기");
int intValue = integerObj.intValue();
System.out.println("intValue = " + intValue);
long longValue = longObj.longValue();
System.out.println("longObj = " + longValue);
System.out.println("비교");
System.out.println("==: " + (newInteger == integerObj));
System.out.println("equals: " + newInteger.equals(integerObj));
newInteger = 10
integerObj = 10
longObj = 100
doubleObj = 10.5
내부 값 읽기
intValue = 10
longObj = 100
비교
==: false
equals: true
🟢 오토 박싱 - Autoboxing
// Primitive -> Wrapper
int value = 7;
Integer boxedValue = value; // 오토 박싱(Auto-boxing)
// Wrapper -> Primitive
int unboxedValue = boxedValue; // 오토 언박싱(Auto-Unboxing)
🟢 래퍼 클래스 - 주요메서드
Integer i1 = Integer.valueOf(10);//숫자, 래퍼 객체 반환
Integer i2 = Integer.valueOf("10");//문자열, 래퍼 객체 반환
int intValue = Integer.parseInt("10");//문자열 전용, 기본형 반환
//비교; 내값이 크면1,같으면0,내값이 작으면-1
int compareResult = i1.compareTo(20);
🟢 parseInt() vs valueOf()
- valueOf("10") 는 래퍼 타입을 반환한다.
- parseInt("10") 는 기본형을 반환한다.
🟢 Class 클래스
- 타입 정보 얻기: 클래스의 이름, 슈퍼클래스, 인터페이스, 접근 제한자 등과 같은 정보를 조회할 수 있다.
- 리플렉션: 클래스에 정의된 메서드, 필드, 생성자 등을 조회하고, 이들을 통해 객체 인스턴스를 생성하거나 메서드 를 호출하는 등의 작업을 할 수 있다.
- 동적 로딩과 생성: Class.forName() 메서드를 사용하여 클래스를 동적으로 로드하고, newInstance() 메서드를 통해 새로운 인스턴스를 생성할 수 있다.
- 애노테이션 처리: 클래스에 적용된 애노테이션(annotation)을 조회하고 처리하는 기능을 제공한다.
🟢 Class 클래스 주요 기능
- getDeclaredFields(): 클래스의 모든 필드를 조회한다.
- getDeclaredMethods(): 클래스의 모든 메서드를 조회한다.
- getSuperclass(): 클래스의 부모 클래스를 조회한다.
- getInterfaces(): 클래스의 인터페이스들을 조회한다
//Class 조회
Class clazz = String.class; // 1.클래스에서 조회
//Class clazz = new String().getClass();// 2.인스턴스에서 조회
//Class clazz = Class.forName("java.lang.String"); // 3.문자열로 조회
// 모든 필드 출력
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println("Field: " + field.getType() + " " + field.getName());
}
// 모든 메서드 출력
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println("Method: " + method);
}
// 상위 클래스 정보 출력
System.out.println("Superclass: " + clazz.getSuperclass().getName());
// 인터페이스 정보 출력
Class[] interfaces = clazz.getInterfaces();
for (Class i : interfaces) {
System.out.println("Interface: " + i.getName());
}
Field: class [B value
...
Method: public boolean java.lang.String.equals(java.lang.Object)
Method: public int java.lang.String.length()
...
Superclass: java.lang.Object
Interface: java.io.Serializable
Interface: java.lang.Comparable ...
🟢 클래스 생성
package lang.clazz;
public class Hello {
public String hello() {
return "hello!";
}
}
package lang.clazz;
public class ClassCreateMain {
public static void main(String[] args) throws Exception {
//Class helloClass = Hello.class;
Class helloClass = Class.forName("lang.clazz.Hello");
// 생성자를 선택, 생성자 기반 인스턴스 생성
Hello hello = (Hello) helloClass.getDeclaredConstructor().newInstance();
String result = hello.hello();
System.out.println("result = " + result);
}
}
result = hello!
🪄 Class 를 사용하면 클래스의 메타 정보를 기반으로 클래스에 정의된 메서드, 필드, 생성자 등을 조회하고, 이들을 통해 객체 인스턴스를 생성하거나 메서드를 호출하는 작업을 할 수 있다. 이런 작업을 리플렉션이라 한다.
🟢 System 클래스
public class SystemMain {
public static void main(String[] args) {
// 현재 시간(밀리초)를 가져온다.
long currentTimeMillis = System.currentTimeMillis();
System.out.println("currentTimeMillis: " + currentTimeMillis);
// 현재 시간(나노초)를 가져온다.
long currentTimeNano = System.nanoTime();
System.out.println("currentTimeNano: " + currentTimeNano);
// 환경 변수를 읽는다.
System.out.println("getenv = " + System.getenv());
// 시스템 속성을 읽는다.
System.out.println("properties = " + System.getProperties());
System.out.println("Java version: " + System.getProperty("java.version"));
// 배열을 고속으로 복사한다.
char[] originalArray = new char[]{'h', 'e', 'l', 'l', 'o'};
char[] copiedArray = new char[5];
System.arraycopy(originalArray, 0, copiedArray, 0, originalArray.length);
// 배열 출력
System.out.println("copiedArray = " + copiedArray);
System.out.println("Arrays.toString = " + Arrays.toString(copiedArray));
//프로그램 종료
System.exit(0);
}
}
currentTimeMillis: 1703570732276
currentTimeNano: 286372106104583
getenv = {IDEA_INITIAL_DIRECTORY=/, COMMAND_MODE=unix2003, LC_CTYPE=ko_KR.UTF-8, SHELL=/bin/zsh, HOME=/Users/yh, PATH=/opt/homebrew/bin:/usr/local/bin: ...} // OS가 사용하는 시스템 환경
properties = {java.specification.version=21, java.version=21.0.1, sun.jnu.encoding=UTF-8, os.name=Mac OS X, file.encoding=UTF-8 ...} //자바가 사용하는 시스템 환경
Java version: 21.0.1
copiedArray = [C@77459877
Arrays.toString = [h, e, l, l, o]
🟢 Math, Random 클래스
// 기본 연산 메서드
System.out.println("max(10, 20): " + Math.max(10, 20)); //최대값 20
System.out.println("min(10, 20): " + Math.min(10, 20)); //최소값 10
System.out.println("abs(-10): " + Math.abs(-10)); //절대값 10
// 반올림 및 정밀도 메서드
System.out.println("ceil(2.1): " + Math.ceil(2.1)); //올림 3.0
System.out.println("floor(2.7): " + Math.floor(2.7)); //내림 2.0
System.out.println("round(2.5): " + Math.round(2.5)); //반올림 3
// 기타 유용한 메서드
System.out.println("sqrt(4): " + Math.sqrt(4)); //제곱근 2.0
System.out.println("random(): " + Math.random()); //0.0 ~ 1.0 사이의 double 값
import java.util.Random;
public class RandomMain {
public static void main(String[] args) {
// 생성자를 비워두면 내부에서 씨드값을 생성.반복 실행해도 결과가 항상 달라짐
Random random = new Random();
//Random random = new Random(1); //seed가 같으면 Random의 결과가 같다.
int randomInt = random.nextInt();
System.out.println("randomInt: " + randomInt); //-1316070581
double randomDouble = random.nextDouble(); //0.0d ~ 1.0d
System.out.println("randomDouble: " + randomDouble); //0.37735342193577215
boolean randomBoolean = random.nextBoolean();
System.out.println("randomBoolean: " + randomBoolean); //false
// 범위 조회
int randomRange1 = random.nextInt(10); //0 ~ 9까지 출력
System.out.println("0 ~ 9: " + randomRange1);
int randomRange2 = random.nextInt(10) + 1; //1 ~ 10까지 출력
System.out.println("1 ~ 10: " + randomRange2);
}
}
'Java' 카테고리의 다른 글
[Java] 김영한의 실전 자바 - 중급편 섹션8 중첩 클래스,내부 클래스2 (0) | 2024.05.20 |
---|---|
[Java] 김영한의 실전 자바 - 중급편 섹션5 열거형 - ENUM (0) | 2024.05.09 |
[Java] 김영한의 실전 자바 - 중급편 섹션2 불변 객체 (0) | 2024.05.05 |
[Java] 김영한의 실전 자바 - 중급편 섹션1 Object 클래스 (0) | 2024.05.05 |
[Java의 정석] chapter09 java.lang패키지와 유용한 클래스 - 요약정리 (0) | 2024.05.05 |