2023.01.19 - 안드로이드 앱개발자 과정

CHA·2023년 1월 24일
0

JAVA



문자열 객체 String

String은 클래스 입니다. 그리고 이러한 클래스를 인스턴스화 하여 멤버들을 사용할 수 있게 됩니다. 그리고 멤버들을 사용하기 위해서는 참조변수을 선언해주어야 합니다. 참조변수를 사용하여 객체의 주솟값을 받아와 사용해야하기 때문입니다. 아래 코드는 그 차이를 알아볼 수 있는 예제입니다.

int a = 10;
int b = a;
b=11;

System.out.println(a);
출력값 : 10
// 원본 a의 값은 10으로 변하지 않는다!

String s = "Hello";
String s2 = s;

s2 = "Nice"
System.out.println(s);
출력값 : Nice
//  String 참조변수는 주솟값을 참조하기 때문에 참조변수 s의 값이 변하게 된다!


그런데, 아까전에 String 은 클래스 이며 인스턴스화 하여 사용해야한다고 하였습니다. 그런데 위 코드를 보면 String s = "Hello" 만 사용하였고, 객체화 하기 위한 new 연산자는 사용하지 않았습니다.

사실, Java 에서는 문자열을 너무 많이 다루기 때문에 문자열을 사용할 때 마다 new 연산자를 사용하는 것은 비효율적이라고 생각하여 자동으로 new 연산자를 만들어 줍니다. 그런데 여기서 약간의 차이점이 있습니다. 자바에서는 자동으로 new 연산자로 만들어주는 객체는 String constant pool 이라는 메모리 공간에서 메모리를 관리해줍니다. 물론 객체이기 때문에 Heap 영역 안에서 말이죠.
(Java 7 버전 이전에는 Perm 영역에서 관리 되었으나 7 버전 이후에 Heap 영역으로 옮겨졌습니다.)

그리고 String constant pool 메모리 공간안에서는 기존에 만들었던 문자는 다시 만들지 않으며, 기존 문자의 주솟값을 참조변수에 전달할 수 있습니다. 그렇다면, 어떤 원리로 이게 가능한걸까요? 바로 String의 immutable 성질 때문입니다.

그렇다면 String은 왜 immutable 한 성질을 가지고 있는지에 대해 간단하게만 짚고 넘어가겠습니다. String이 immutable 한 성질을 가지고 있게 된다면, String constant pool 메모리 공간에서 자동 new 연산자에 대한 String 객체를 관리할 수 있기 때문에 메모리의 절약을 할 수 있게 됩니다. 이 외에도 보안이나 안전성, 효율성 등의 이유로 String 을 불변으로 처리합니다. 보안이나 안정성등의 부분은 추후에 더 알아보겠습니다.

자, 그러면 문자열 객체가 가지고 있는 기능들에는 어떤것들이 있을까요? 굉장히 많은 수의 기능들이 String 클래스에 존재합니다. 그 중에서 가장 많이 쓰이는 기능들에 대해서 알아봅시다.


문자열 객체의 기능들


  • 1. 문자열 데이터의 길이(글자수) 를 리턴해주는 기능(method) - length()

    String str = "hello";
    int len = str.length();
    출력결과 : 5
  • 2. 문자열 값 비교 기능 - equals(Object obj)

    String str = "Nice";
    System.out.println(str2 == "Nice"); // true : 주소비교. 자동 new 연산자는 기존의 동일한 문자열의 주솟값을 가져온다.
    String str2 = new String("Nice");
    System.out.println(str2 == "Nice"); // false : new 연산자를 통해 heap 영역에 새로운 메모리 공간을 만듬.
    System.out.println(str.equals(str2_1)); // true : 값비교이기 때문에 true.
    System.out.println(str.equals(new String("Nice"))); // true : 값비교이기 때문에 true.

    == 연산자는 값을 비교하는 연산자 입니다. 그리고 앞선 설명에서 이야기 했듯, 참조변수 str 에 있는 값은 리터럴값이 아닌 주솟값 입니다. 그래서 str == str2strstr2 의 값을 비교하는것이 아닌, 참조하고 있는 주솟값 을 비교하는 연산이 됩니다. 그래서 문자열의 값을 비교하기 위해서는 equals 메소드를 사용해야 합니다.

  • 2-1. 대소문자 비교 - equalsIgnoreCase(String str)

    String str = "Hello";
     System.out.println(str.equals("hello")); // false
     System.out.println(str.equalsIgnoreCase("hello")); // true
  • 3. 문자열에서 특정 char 얻어오기 - charAt(int idx)

    String str = "hello";
    System.out.println(str.charAt(0) + 1);
    System.out.println(str.charAt(0) + 'A');
    
    for (int i = 0; i < str.length(); i++) {
          System.out.print(str.charAt(i));
    }
    출력결과 : 73 / 137 / Hello
  • 3-1.Scanner 객체를 이용해 char 한문자 입력받기

    Scanner scan = new Scanner(System.in);
     String s1 = scan.next(); // 문자열 입력받기 
     char c = s1.charAt(0);
     System.out.println("c : " + c);
  • 4. 문자열안에 특정한 '문자열' 이 포함되어 있는지 여부 - contains(Charsequence s)

    String s2 = new String("Hello world! Hello android! nice world!");
     boolean bool = s2.contains("!"); // 매개변수는 문자열!
     System.out.println(bool); // true
    
  • 5. 문자열안에 특정 '문자'가 몇번째 위치에 있는지 알려주는 기능 - indexOf(int ch)

     String str = new String("Hello World!");
     int index = str.indexOf('W');
     System.out.println(index); 
     System.out.println(str.lastIndexOf('!')); 
     출력결과 : 6 / 11 

    해당 글자가 한개가 아니라 여러개라면, 맨 앞 글자의 인덱스를 가져오게 되어있습니다. 만일, 맨 앞글자의 인덱스가 아니라 맨 뒷글자의 인덱스를 찾고 싶다면 lastIndexOf() 를 이용하면 좋습니다. 다만 헷갈리지 말아야 할 부분은 앞에서 찾든, 뒤에서 찾든 인덱스의 값은 동일합니다. 찾는 과정이 앞에서 부터 시작하냐, 뒤에서 부터 시작하냐의 차이일 뿐입니다.

  • 5-1. 특정'문자열'의 시작위치도 검색가능 - indexOf(String str)

    System.out.println(s3.lastIndexOf("ello"));
    System.out.println(s3.lastIndexOf("Hello"));
    출력결과 : 1 / 0
  • 5-2. 특정 '위치'부터 검색 요청도 가능 - indexOf(String str,int fromidx)

    System.out.println(s3.indexOf("Hello", 5)); // 5번 인덱스 위치부터 검색 시작!
  • 6. 문자열 결합기능 - concat(String str)

     String str = "nice world";
     String str2 = str.concat(" nice android!");
    
     System.out.println(str);
     System.out.println(str2);
     // 출력결과 : nice world / nice world nice android
     
     str2 = str + " nice ios"; // 결합연산자 +
     System.out.println(str2);
     // 출력결과 : nice world nice ios
    

    String 객체는 immutable 속성이 있기 때문에 절대로 원본이 변하지 않습니다. strconcat() 메소드를 사용하여 문자열 결합을 한다고 해도, 참조변수 str 가 가르키는 주소에 들어있는 값은 변하지 않습니다.

    그런데 사실, 결합연산자 + 를 이용하여 문자열의 결합을 하는것이 훨씬 직관적이고 편하기 때문에 concat() 메소드는 잘 사용하지 않습니다. 또한 결합연산자 + 는 내부적으로 concat() 을 사용하여 문자열을 결합합니다.

  • 7. 문자열이 특정한 문자열로 '시작' 되는지 여부 - startsWith(String str)

    String str = "Hello";
     System.out.println(str.startsWith("H")); // true
     System.out.println(str.startsWith("h")); // false
  • 7-1. 특정한 문자열로 '종료' 되는지 여부 - endsWith(String str)

     System.out.println(str.endsWith("o")); // true
      System.out.println(str.endsWith("d")); // false
    
  • 8. 대소문자 변환 기능 - toUpper(Lower)Case()

    String str = "Hello";
     System.out.println(str.toUpperCase());
      System.out.println(str.toLowerCase()); 
      System.out.println(str);
      // 출력결과 : HELLO / hello / Hello
      
      str = str.toUpperCase();
      System.out.println(str); 
      // 출력결과 : HELLO

    역시 마찬가지로 원본은 변경되지 않습니다. 만일, 원본을 변경하고 싶다면, 원본 참조변수 str 에 변경된 값을 다시 대입해주면 가능합니다.

  • 9. 문자열의 '앞','뒤' 공백을 제거하는 기능 - trim()

    String str = "  Hel     lo      ";
     System.out.println("[" + str + "]");
     System.out.println("[" + str.trim() + "]");
    // 출력결과 : [  Hel     lo      ] / [Hel     lo]

    trim() 은 앞, 뒤 공백만 제거해줄뿐, 중간에 들어있는 공백은 제거가 불가능합니다. 만일, 공백을 모두 지우고싶다면 replace를 사용하면 됩니다.

  • 10. 특정 '문자' 바꿔치기 기능 - replace(char oldCh,char newCh)

    String str = "Hello World! Hello Android! Nice World!";
     System.out.println(str.replace('H', '♥')); 
     System.out.println(str.replace(' ', '♥')); 
     // 출력결과 : ♥ello World! ♥ello Android! Nice World!
     //           Hello♥World!♥Hello♥Android!♥Nice♥World!

    replace()의 왼쪽 파라미터에는 바뀌기전 글자를, 오른쪽에는 바뀐 후의 글자를 전달해주면 됩니다. 그러면 해당하는 글자 모두를 바꿔줍니다. 또한 문자열에는 문자열을 대체시켜야 하며, 한문자에는 한문자를 대체시켜야 한다는 사실을 기억합시다. 추가로 한문자는 빈 문자를 만들수 없습니다. 그래서 만일 공백을 없애고 싶다면 한문자를 파라미터로 전달하면 안되고 문자열을 파라미터로 전달해주어야 합니다. 이 역시 마찬가지로 원본은 불변입니다.

  • 10-1. 특정 '문자열' 바꿔치기 기능 - replace(String oldStr,String newStr)

    System.out.println(str.replace("Hello", "Shit"));
     System.out.println(str.replace(" ", ""));
     // 출력결과 : Shit World! Shit Android! Nice World!
     //           HelloWorld!HelloAndroid!NiceWorld!

    한 문자 대신 문자열이 파라미터로 들어간 형태 입니다. 위 코드 두번째 줄처럼 하면 공백을 모두 지울 수 있습니다. 그리고 빈 문자열도 length가 0인 객체 입니다.

  • 11. 문자열 잘라내기 - subString(int idx)

    String str = "Hello World! Hello Android! Nice World!";
    int index = 1;
     System.out.println(str.substring(index)); // index부터 시작
     System.out.println(s3.substring(13, 18)); // 13~17 까지
    // 출력결과 : ello World! Hello Android! Nice World!
    //           Hello
  • 12. 문자열값의 대소비교 - compareTo(String str)

    String str1 = "aaa";
     String str2 = "bbb";
     // System.out.println(s5 < s6);//error! 
     System.out.println(str.compareTo("aaazfzz"));
            // 그런데 .compareTo 는 잘 안쓴다! 배열이나 리스트에 이미 sort 기능이 있기 때문!

    참조변수 str1str2 을 비교연산자를 통해 비교하게 되면 에러가 납니다. str1 < str2 은 각 참조변수가 참조하는 주소값을 대소비교 한것이며, 자바에서는 주소 대소비교가 불가하기 때문입니다. 그래서 자바에서는 compareTo() 메소드를 통해 비교합니다. compareTo() 를 활용해서 문자열의 비교값을 구하는 과정은 좀 재밌는데, 다른 글에서 따로 설명해보겠습니다. - 링크!@!@!@!@!@

  • 13. 문자열을 특정'문자'를 기준으로 분리해서 여러개의 문자열배열로 리턴 - split(String str)

    String str = "android,ios,web";
     String[] arr = str.split(",");
     System.out.println(arr[2]);
    
     for (int i = 0; i < arr.length; i++) {
          System.out.println(arr[i]);
      }
    // 출력결과 : web   /   android / ios / web

문자열 객체와 관련한 static 메소드


  • 1. 특정 포맷(모양,형식)의 문자열을 '생성' 하고 싶을때 사용하는 기능 메소드 - format(String str,Object args..)

    int hour = 13; // 시
     int min = 5; // 분
     int sec = 4; // 초
     System.out.println(hour + ":" + min + ":" + sec);
     System.out.printf("%02d:%02d:%02d\n", hour, min, sec); 
     // 출력형태를 무조건 CLI 환경의 console 에만 출력함.
    
     // 실무환경에서는 GUI 환경으로 데이터를 표시하며 이 표시는 반드시 문자열로 처리된다.
     String ss = String.format("%02d:%02d:%02d", hour, min, sec);
     System.out.println("현재시간  " + ss);
  • 2. 기본형 자료형(premitive)을 String 객체로 변환하는 메소드 - valueOf(Object obj)

    int num = 100;
     String s10 = String.valueOf(num);
     System.out.println(s10.length());
    
     String s11 = String.valueOf(num);
     System.out.println(s11.length());
    
     String s12 = String.valueOf(num);
     System.out.println(s12.length());
     // GUI 환경에서 기본형을 문자열로 변환하는 코드는 아주 빈번함.
     // 하지만 자주 사용되지 않음 -> 결합연산자를 이용하면 더 간결!
     String s13 = 1000 + "";
     String s14 = 5.22 + "";
     String s15 = true + "";
    
     // 반대로, 문자열을 기본형으로 변환하고 싶다면??
     // 이 기능은 String 클래스에 없음
     // 이 기능을 가진 클래스들이 있음. 이 클래스들의 static 메소드를 사용
     // 이런 클래스들을 Wrapper 클래스(8개)라고 부름.
     // -> Boolean, Byte, Character, Short, Integer, Long, Double
            
profile
Developer

0개의 댓글