JAVA : 문자열, 배열

soap·2025년 4월 4일

Java : 기초

목록 보기
1/11
post-thumbnail

🍋 문자열 : immutable 불변

1. 문자열 비교

: 문자열 리터럴(값)이 동일하다면 String 객체를 공유하게 되어 있다.

String s1 = "hello";
String s2 = "hello";

System.out.println(s1 == s2); // true (리터럴 풀에서 공유됨)

1) 주소비교 ( == )

2) 값 비교

비교기준(String).equals(String s) : boolean


2. 문자열 추출

.substring(int beginIndex) : String

.substring(int beginIndex, int endIndex) : String

🚫 주의 : beginIndex 부터 endIndex - 1 까지 반환

3. 문자열 대체

.replace(char oldChar, char newChar) : String

4. 문자열 분리

.split("나누는 기준") : String[]

⭕ String타입을 charAt을 쓰지않고 원소 하나씩 분리하는 방법 = .split("")

String arr = "abbabbacc";
String[] arr1 = arr.split("b");
System.out.println(Arrays.toString(arr1)); //결과 : [a, , a, , acc] 

String[] arr2 = arr.split("");
System.out.println(Arrays.toString(arr2)); //결과 : [a, b, b, a, b, b, a, c, c] 

5. 문자열에서 특정 문자열/문자 찾기

✅ 특정 문자열이 시작하는 첫 인덱스를 반환하고 없으면 -1 반환
✅ 매개변수 int ch는 아스키코드다

indexOf( ) : int


6. 자료형 변환

1) String ->

Integer.parseInt(String s) : int
Double.parseDouble(String s) : double
Boolean.parseBoolean(String s) : boolean
Long.parseLong(String s) : long


2) -> String

String.valueOf(char, bloolean, int, float, double, char[]) : String

String greet= "안녕하세요";
greet.valueOf(...) //이것도 가능하지만 이렇게 쓸 일이 거의 없음..

//String.valueOf()
greet = String.valueOf(..) //이렇게 다른 자료형을 문자열로 변환하여 return 값 받는 경우가 많아섭

char -> String

1. String.valueOf(char ch 또는 char[] chArray) : String
2. Character.toString(char ch) : String
3. ""

🚫 Character.toString(char ch)
: char[]은 안되기 때문에 길이가 1개인 String만 반환하는 격이다.

// ""이용하기

String -> char

##특수문자도 공백도 포함됨

1. .charAt(int index) : char
2. .toCharArray() : char[]

⭕ String을 String[]로 하고 싶다면 .split("")을 사용하는게 나음



🍋 배열

배열의 출력

1. 반복문 사용 // int[] 이거면 int에 접근하기 때문에 가능한건
2. Arrays.toString()

💡 자바에서 String vs Array 출력 차이

✅ 둘 다 참조 자료형이다

참조 자료형은 실제 데이터가 힙(heap) 에 저장되고, 변수는 그 데이터를 참조하는 주소(참조값) 를 가지고 있어.

🧵 그럼 왜 출력 결과는 다를까?

1. String은 toString()이 오버라이딩 되어 있다

System.out.println(str);

이런 식으로 String을 출력하면, 내부적으로 str.toString()이 호출돔.

그런데 String 클래스는 Object 클래스의 toString()을 오버라이딩 해서, 사람이 읽을 수 있는 문자열을 반환하게 만들어져 있다.

String str = "hello";
System.out.println(str); // 결과: hello

→ 내부적으로 str.toString() 호출
→ String 클래스의 오버라이딩된 toString()이 실행
→ 실제 문자열이 출력됨

2. 배열은 toString()을 오버라이딩하지 않았다

반면, 배열은 객체이긴 하지만 toString()을 오버라이딩하지 않았기 때문에, Object 클래스의 기본 toString()이 호출된다.

Object의 기본 toString()은 → 클래스명 + "@" + 해시코드(16진수)

int[] arr = {1, 2, 3};
System.out.println(arr); 
// 결과: [I@15db9742 같은 이상한 값이 출력됨

→ arr.toString() 호출
→ 배열 클래스는 Object의 기본 toString을 사용
→ 그래서 이상한 "주소 비슷한" 해시값이 나옴

🤔 그래서 어떻게 출력하냐?

  1. 반복문
for (int i : arr) {
    System.out.print(i + " ");
}
  1. Arrays.toString() 사용
import java.util.Arrays;

System.out.println(Arrays.toString(arr)); 
// 결과: [1, 2, 3]

🔍 요약

자료형 toString 오버라이딩 여부 출력 결과
String ✅ (오버라이딩함) 문자열 자체 출력
Array ❌ (기본 toString 사용) 클래스명@해시코드 출력

그러면 Integer처럼 참조자료형인데 for문 쓰면 해결되는 이유는?

자바의 오토박싱, 언박싱, 그리고 객체의 toString() 동작 방식때문에

Integer[] 배열도 for문으로 돌리면 각 요소가 Integer 객체고, System.out.print()는 그 객체의 toString()을 호출해서 출력함.

✳️ Integer는 참조형, 그런데 왜 출력 잘되는가?

Integer[] nums = {1, 2, 3};

for (Integer num : nums) {
    System.out.print(num + " ");
}

➡ 여기서 중요한 건 num은 Integer 객체지만
System.out.print(num)을 하면 자바가 내부적으로 이렇게 동작함:

🔁 내부 동작

System.out.print(num); 
// 실제로는 -> System.out.print(num.toString());

즉, Integer 클래스는 toString()을 오버라이딩해서 숫자를 문자열로 반환하도록 구현되어 있음!

🧠 참고: Integer.toString() 오버라이딩 확인
Integer 클래스 내부 일부:

public String toString() {
    return String.valueOf(value);
}

→ value는 내부에 저장된 int 값이야
→ 그래서 "1", "2", "3" 이렇게 나오는 거지!

❓그럼 기본형 배열과의 차이는?

int[] arr = {1, 2, 3};
System.out.println(arr); 
// => [I@15db9742 (이상한 주소)

Integer[] boxedArr = {1, 2, 3};
System.out.println(boxedArr);
// => [Ljava.lang.Integer;@1b6d3586 (이것도 이상함)

for (int n : arr) System.out.print(n);         // 123
for (Integer n : boxedArr) System.out.print(n); // 123 ✅

→ 둘 다 반복문 쓰면 잘 출력되는데
→ 그 이유는: 값 자체를 출력하니까 toString()이 동작함

toString()이 오버라이딩 되어 있는 대표 클래스들

클래스	toString() 오버라이딩 여부	출력 예시
String	✅ 있음	"hello"
Integer	✅ 있음	"42"
Double, Float, Long 등	✅ 있음	"3.14", "100L"
ArrayList	✅ 있음	"[1, 2, 3]"
HashMap	✅ 있음	"{key=value}"
LocalDate, LocalDateTime	✅ 있음	"2025-04-17" 등

배열의 기본 초기값

정수 : 0 , boolean: , 참조: null, 실수:

배열의 복사

: 배열은 참조자료형이라서 대입을 하면 주소값이 복사된다.

int[] arr1 = {1,2,3,4};
int[] answer = {0};

answer = arr1 

주소값이 복사되면 arr1과 answer은 같은 객체를 가르키는 것이기때문에 arr1을 수정하면 answer도 수정하게 된다.

1. 길이 변경 복사

1) 변경하고자 하는 길이를 가진 새로운 객체 만들기
2) for문 사용하여 내용 복사

2. 그대로 복사

  • for문 써서

  • Arrays.copyOf(복사할 배열, 배열길이)

int[] a1 = new int[]{1,2,3}
int[] a2 = Arrrays.copyof(a1, a1.length)

배열의 조각

다차원 배열

int[][] arr = {{3,4}, {2,3}, {3,5}}

🍋기본자료형 <-> 참조자료형

: 경험상 Array.sort()를 사용하게 되면 안정정렬과 불안정정렬로 나눠지는데 안정정렬로 하게 되면 같은값일때 인덱스가 유지된다. 그래서 인덱스가 필요한 경우 int[] -> integer[]

https://zkvn1103.tistory.com/13

int[] arr = {1,2,3,4,5};
// int[] -> Integer[]
Integer[] arr2 = Arrays.stream(arr).boxed().toArray(new IntFunction<Integer[]>() {

	  @Override
	  public Integer[] apply(int value) {
			return new Integer[value];
	 }
			
});

System.out.println(Arrays.toString(arr2));
		
// Integer[] -> int[]
int[] arr3 = Arrays.stream(arr2).mapToInt(i->i).toArray();
System.out.println(Arrays.toString(arr3));

기본적으로 알아야 할 개념

int ↔ Integer : 박싱/언박싱으로 자동 변환 가능

int[] ↔ Integer[] : 자동 변환 ❌ (직접 변환해야 함)

sort

Arrays.sort(int[], char[], String[] ,,,,)

기본자료형 오름차순

Arrays.sort(배열)

기본자료형 내림차순

// int[] 안됨 , String[] 됨
int[] arr2 = {1, 3, 2};
Arrays.sort(arr2, Comparator.reverseOrder()); // 에러

String[] arr = {"banana", "apple", "cherry"};
Arrays.sort(arr, Comparator.reverseOrder());

Arrays.sort(T[] a, Comparator<? super T> c)

Comparator 배열의 타입이 객체여야 함 그래서 기본자료형은 안됨

🤔 그럼 Comparator.reverseOrder()랑 Collections.reverseOrder()는 뭐가 달라?
사실상 거의 같음. 내부적으로 Collections.reverseOrder()는 Comparator.reverseOrder()를 리턴해주는 식으로 구현되어 있어. 요즘은 Comparator.reverseOrder()를 더 많이 쓰는 추세야.

int[] primitiveArr = {3, 1, 2};
Integer[] arr = Arrays.stream(primitiveArr).boxed().toArray(Integer[]::new);
Arrays.sort(arr, Comparator.reverseOrder());

Arrays.stream(primitiveArr) // 1단계: int[] → IntStream
.boxed() // 2단계: IntStream → Stream
.toArray(Integer[]::new); // 3단계: Stream → Integer[]

int[] arr = new int[] { 2, 5, 1, 4, 3 };

		// 기본자료형 오름차순 정렬
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));

		// 기본자료형 내림차순 정렬
		// Comparator.reverseOrder()안됨 (문자열은 됨)
//	    Arrays.sort(arr, Comparator.reverseOrder());
	    String[] names = {"최길동", "박길동", "홍길동", "김길동"};
        Arrays.sort(names);
        System.out.println("문자열 오름차순-----------------");
        System.out.println(Arrays.toString(names));

        System.out.println("문자열 내림차순-----------------");
        Arrays.sort(names, Collections.reverseOrder());
        System.out.println(Arrays.toString(names));
	    
	    
        // 기본자료형을 내림차순으로 정렬하기 위해 int -> Integer로 변환
		Integer[] arr2 = Arrays.stream(arr).boxed().toArray(Integer[]::new);
		System.out.println("정수 내림차순--------------------");
		Arrays.sort(arr2, Collections.reverseOrder());
		System.out.println(Arrays.toString(arr2));


		// 정렬알고리즘 응용
		// Map 배열을 정렬해서 출력
		Map<String, Object> map = new HashMap<>();
		map.put("name", "박길동");
		map.put("score", 60);
		Map<String, Object> map2 = new HashMap<>();
		map2.put("name", "김길동");
		map2.put("score", 80);
		Map<String, Object> map3 = new HashMap<>();
		map3.put("name", "이길동");
		map3.put("score", 100);
		Map<String, Object> map4 = new HashMap<>();
		map4.put("name", "최길동");
		map4.put("score", 70);

		List<Map> list = new ArrayList<>();
		list.add(map);
		list.add(map2);
		list.add(map3);
		list.add(map4);

		Collections.sort(list, new Comparator<Map>() {
			@Override
			public int compare(Map o1, Map o2) {
//	                return (int)o2.get("score") - (int)o1.get("score"); // 내림차순
				return (int) o1.get("score") - (int) o2.get("score"); // 오름차순
			}
		});
		
		list.stream().forEach(m -> System.out.println(m));






profile
치열하게 살지는 않아도 후회되는 순간은 만들지 말자

0개의 댓글