ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Java - 기본 클래스(String 클래스)4
    개발언어/JAVA 2023. 11. 6. 14:09

    String을 선언하는 두 가지 방법

    String str1 = new String("abc");  //생성자의 매개변수로 문자열 생성
    String str2 = "test"			  //문자열 상수를 가리키는 방식

     

    String 타입의 변수를 생성하는 방식에는 두가지가 존재한다. 문자열을 생성자의 매개변수로 하여 생성하는 방식과 이미 생성된 문자열 상수를 가리키는 방식이 그것이다.

     

    이 두 방식은 언뜻 비슷해 보이지만, 내부적으로는 두 가지 방식에 큰 차이가 있다. new 예약어를 사용하여 객체를 생성하는 경우는 "abc" 문자열을 위한 메모리가 할당되고 새로운 객체가 생성된다. 하지만 str = "test"와 같이 생성자를 이용하지 않고 바로 문자열 상수를 가리키는 경우에는 str2가 기존에 만들어져 있던 "test"라는 문자열 상수의 메모리 주소를 가리키게 된다. 따라서 String str3 = "test"코드를 작성하면 str2와 str3는 주소 값이 같게 된다. 

     

    test나 10,20 등과 같이 프로그램에서 사용되는 상수 값을 저장하는 공간을 '상수 풀(constant pool)'이라고 한다.

    package stirng;
    
    public class StringTest1 {
        public static void main(String[] args) {
            String str1 = new String("abc");
            String str2 = new String("abc");
    
            //인스턴스가 매번 새로 생성되므로 str1과
            //str2의 주소 값이 다르다.
            System.out.println(str1 == str2);
            
            //문자열 값은 같으므로 true 반환
            System.out.println(str1.equals(str2));
            
            String str3 = "abc";
            String str4 = "abc";
    
            //문자열 abc는 상수 풀에 저장되어 있으므로
            //str3과 str4가 가리키는 주소값이 같다.
            System.out.println(str3 ==  str4);
            //문자열 값도 같으므로 true 반환
            System.out.println(str3.equals(str4));
        }
    }

     

     

    String 클래스의 final char[ ] 변수

    public final class String
       implements java.io.Serializable, Comparable<String>, CharSequence{
       /** The vlaue is used for character storage.*/
       private final char value[];
       }

     

    다른 프로그래밍 언어는 문자열을 구현할 때 일반적으로 char[ ]배열을 사용한다. 자바는 String 클래스를 제공해 char [ ] 배열을 직접 구현하지 않고도 편리하게 문자열을 사용할 수 있다. String.java 파일을 보면 위와 같이 선언 되어있다.

     

    String클래스의 구현 내용을 보면 private final char value[ ]라고 선언된 char형 배열이 있다.  프로그램에서 String s = new String("abc")라고 쓰면 abc는 String 클래스의 value변수에 저장된다. 그런데 이 변수는 final로 선언되어 있다. final은 문자열을 변경할 수 없다는 뜻이다. 다라서 한번 생성된 문자열은 변경되지 않는다. 이런 문자열의 특징을 '문자열은 불변(immutable)한다'  그렇다면 기존에 new 연자를 이용해 생성된 String에 concat()함수를 이용해서 특정 문자열을 연결 후 처음 생성했던 변수에 다시 대입하면 어떻게 될까? 이런 경우 기존에 생성된 문자열이 변경되는 것이 아니라 두 문자열이 연결된 새로운 문자열이 생상된다. 

     

    두 문자열 연결하기

    package stirng;
    
    public class StringTest2 {
        public static void main(String[] args) {
            String javaStr = new String("java");
            String androidStr = new String("android");
    
            System.out.println(javaStr);
            //java
    
            //처음 문자열 주소 값
            System.out.println(System.identityHashCode(javaStr));
            //1435804085
    
            //문자열 javaStr과 문자열 androidStr을
            //연결하여 javaStr에 대입
            javaStr = javaStr.concat(androidStr);
    
            System.out.println(javaStr);
            //javaandroid
    
            //연결된 문자열 주소 값
            System.out.println(System.identityHashCode(javaStr));
            //1784662007
        }
    }

     

     

    기존에 new 연자를 이용해 생성된 String에 concat()함수를 이용해서 특정 문자열을 연결 후 처음 생성했던 변수에 다시 대입하면 어떻게 될까? 이런 경우 기존에 생성된 문자열이 변경되는 것이 아니라 두 문자열이 연결된 새로운 문자열이 생상된다. 

     

    StringBuffer와 StringBuilder 클래스 활용하기

    프로그램을 만들다 보면 문자열을 변경하거나 연결해야 할 때가 많다. 그런데 String 클래스는 한번 생성되면 그 내부의 문자열이 변경되지 않기 때문에 String 클래스를 사용하여 문자열을 계속 연결하거나 변경하는 프로그램을 작성하면 메모리가 많이 낭비된다. 이 문제를 해결하는 것이 StirngBuffer와 StringBuilder 클래스이다.

     

    StirngBuffer와 StringBuilder는 내부에 변경 가능한(즉, final이 아닌) char[ ]를 변수로 가지고 있다. 이 두 클래스를 사용하여 문자열을 연결하면 기존에 사용하던 char[ ] 배열이 확장되므로 추가 메모리를 사용하지 않는다. 따라서 문자열을 연결하거나 변경할 경우에 두 클래스 중 하나를 사용하면 된다. 

     

    StringBuffer와 StringBuilder의 차이점은  여러 작업(스레드)이 동시에 문자열을 변경하려 할때 문자열이 안전한게 변경되도록 보장을 해주는가 그렇지 않은가의 차이를 가진다. 

     

    StringBuilder는 스레드 세이프 하지 않은 대신 실행 속도가 빠르므로, 프로그램에서 따로 스레드를 생성하는 멀티 스레드 프로그램이 아니라면 사용하는것이 권장된다.

     

    StringBuilder 클래스 예제

    package stirng;
    
    public class StringBuilderTest {
        public static void main(String[] args) {
            String javaStr = new String("java");
    
            //인스턴스가 처음 생성됐을때 메모리 주소
            System.out.println(System.identityHashCode(javaStr));
            //1435804085
    
            //String으로 StringBuilder생성
            StringBuilder buffer = new StringBuilder(javaStr);
            
            //연산전 buffer 메모리 주소
            System.out.println(System.identityHashCode(buffer));
            //1784662007
    
            //문자열 추가
            buffer.append(" and");
            buffer.append(" android");
            buffer.append(" programming is fun");
    
            //연산 후 buffer 메모리 주소
            System.out.println(System.identityHashCode(buffer));
            //1784662007
    
            //String 클래스로 반환
            javaStr = buffer.toString();
    
            System.out.println(javaStr);
            // java and android programming is fun
    
            //연결된 javaStr 문자열 주소
            System.out.println(System.identityHashCode(javaStr));
            //997110508
        }
    }

     

    위 코드에서 append()메서드로 새로운 문자열을 추가하기 전과 추가 한 후에 해시코드가 같은것을 미루어보아 메모리가 새로 생성되는 것이아니라 하나의 메모리에 계속해서 새로운 문자열이 추가되고 있는 것을 확인할 수 있다.

     

    [출저 - Do it! 자바 프로그래밍 입문 , 박은종]

    http://www.easyspub.co.kr/20_Menu/BookView/A001/267/PUB

     

    http://www.easyspub.co.kr/20_Menu/BookView/A001/267/PUB

     

    www.easyspub.co.kr

     

    댓글

Designed by Tistory.