회고록 블로그

[공부 필기] Java 기본 공부하기 (10) 본문

2. 프로그래밍 언어 공부/Java

[공부 필기] Java 기본 공부하기 (10)

김간장 2021. 10. 26. 22:29

공부 중인 강의 : 윤성우 선생님, 윤성우의 열혈 Java 프로그래밍 강의.

링크 : https://cafe.naver.com/cstudyjava

 

윤성우의 프로그래밍 스터디그룹 [C/... : 네이버 카페

윤성우의 스터디 공간입니다. C와 JAVA를 공부하시는 분들은 모두 들어오세요. ^^

cafe.naver.com

 


 

1. String 클래스

- 우리가 알고 있는 "문자열"도 String 클래스임

String 클래스

- String 클래스가 "문자열"을 저장하는 과정을 이해하려면 String 클래스 내부를 먼저 봐야함

   → Java SE 16 기준 공식 문서 中 "String 클래스"에 대한 설명

https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/lang/String.html

 

String (Java SE 16 & JDK 16)

All Implemented Interfaces: Serializable, CharSequence, Comparable , Constable, ConstantDesc The String class represents character strings. All string literals in Java programs, such as "abc", are implemented as instances of this class. Strings are constan

docs.oracle.com

        * String 클래스에는 많은 메소드와 변수들이 있음

        * 문자열을 저장하는 곳은 "value"라는 인스턴스 변수인 듯함

String 클래스 내부 멤버들

   → 즉, 아래와 같은 코드가 있다면 문자열은 String 인스턴스를 먼저 생성한 후 "value"라는 변수에 문자열을 저장하는 것으로 보임

...
String school = "서울대학교";
...

   → 아래의 코드에서 "school"이라는 변수는 String 인스턴스를 가리키는 참조변수라고 함

        * school 이라는 변수는 문자열을 가리키고 있지 않음

           문자열을 담고 있는 String 인스턴스를 가리키고 있음

        * 인스턴스를 생성하고 접근하려면 "참조변수"가 필요하다고 이전에 배웠고

           참조변수에는 "참조값(주소값)"이 저장된다고 배웠기 때문에, school 이라는 참조변수에도 주소값이 들어 있을 것으로 추측됨

...
String school = "서울대학교";
...

- 참고로, String 인스턴스는 아래와 같이 생성할 수도 있음 (하지만, 위의 방법과 약간의 차이가 존재함, 별첨1 참고)

String school = new String("서울대학교");

 

- JVM은 "문자열"을 만나면 반드시 String 인스턴스를 생성하게 됨

   → 아래와 같은 코드가 있다고 가정하면,

        "Hello"라는 문자열이 들어있는 String 인스턴스를 먼저 생성하고, 문자열을 저장한 후 그 참조값(주소값)을 반환함

        println 메소드는 참조값을 인수로 받아서 출력을 해줌

System.out.println("Hello");

   → 마치, 아래와 같이 보통의 정수(1, 2, 3 등)를 출력하고자 할 때, 가장 먼저 "3"이라는 숫자를 int형으로 메모리에 할당하고 출력해주듯이.

System.out.println(3);

- JDK7 버전 부터는 switch문의 소괄호 안에 문자열이 들어갈 수 있다고 함

 

2. String 클래스의 메소드

- String 클래스에는 많은 메소드가 있음

   → length, concat 등

- 더 많은 메소드가 궁금하다면 Java 공식 문서 참고

   e.g. JDK 16 버전 기준 공식 문서 : 

https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/lang/String.html

 

String (Java SE 16 & JDK 16)

All Implemented Interfaces: Serializable, CharSequence, Comparable , Constable, ConstantDesc The String class represents character strings. All string literals in Java programs, such as "abc", are implemented as instances of this class. Strings are constan

docs.oracle.com

 

2.1. 문자열 내용 비교

   → 비교연산자(==)를 사용할 수도 있지만, 이때 비교 연산자는 "참조값"을 비교하는 것임

   → "문자열 내용"을 비교하려면 equals 메소드, compareTo 메소드, compareToIgnoreCase 메소드를 사용함

- 아래의 1번 코드는 컴파일러에 의해서 2번의 코드로 자동 변환됨

// 1번 코드
System.out.println("Pizza"+"Pasta");

// 1번 코드는 컴파일러에 의해서 2번 코드로 자동 변환된다
// 2번 코드
System.out.println("Pizza".concat("Pasta"));

 

2.2. 문자열 연결시키는 메소드 concat

   → String 인스턴스는 기본적으로 Immutable 인스턴스이기 때문에

         문자열을 연결시켜서 나오는 새로운 문자열은 모두 "새로운 인스턴스"

   → concat 메소드 뿐만 아니라 다른 메소드도 마찬가지임

         Immutable 인스턴스이기 때문에 기존 인스턴스의 값을 수정/변경하는게 아니라 새로운 인스턴스가 생성되는 것

- 복합대입연산자를 사용할 때

   → 문자열이라 복합대입연산자는 사용 불가능할 것 같아 보이지만 가능함

   → 문자열에서 복합대입연산자를 사용하는게 좋은 코드라고 할 수는 없지만, 문법적으로 문제는 없는 코드임

   → "menu1 += menu2"는 아래와 같은 과정을 통해 새로운 인스턴스가 생성된다고 생각하면 됨

   → 이때 중요한 사실은 "menu1" 변수에 저장된 문자열은 기존 인스턴스와는 전혀 다른 '새로운 인스턴스'라는 점

- 아래와 같이 문자열과 다른 자료형의 데이터(숫자 등)를 연결할 수도 있음

// 예시
String menu1 = 1+"Americano";

   → 이때 중요한 점은 숫자 "1"이 valueOf 메소드를 통해서 "문자열"로 치환된다는 점임

 

2.3. 문자열 결합 최적화 진행할 때

- 아래와 같은 코드가 있다고 가정

String menu1 = 1 + ":" + "Americano" + 1; // 1번 메뉴는 Americano 1잔
String menu2 = 2 + ":" + "Latte" + 1; // 2번 메뉴는 Latte 1잔

- 위에서 본 '문자열과 다른 데이터 결합 과정'을 여기에 적용해보면 굉장히 많은 불필요한 인스턴스들이 생성되어버림

문자열 결합 최적화를 하지 않을 때

- 그렇기 때문에 컴파일러는 이렇게 비효율적으로 문자열을 결합하지 않고 아래와 같이 문자열을 결합해줌

   → 과도하게 많은 인스턴스를 생성하지 않고도 문자열을 결합해줌

문자열 결합 최적화를 한 경우

- 보충설명

   → StringBuilder 인스턴스에 Buffer가 있다?

         * 정확하게는 StringBuilder의 부모 클래스에게 str을 넘기고 거기에서 Buffer에 저장되는 것으로 예상됨

   → append 메소드는 인스턴스의 참조값을 반환한다?

 

2.4. StringBuilder

- StringBuilder는 개발자가 직접 사용할 수 있음

- 사용방법은 아래 글을 참고

https://hardlearner.tistory.com/288

 

자바 StringBuilder 사용법 및 사용하는 이유

StringBuilder 사용법 및 사용하는 이유 자바에서 문자열하면 자연스럽게 String이 떠오른다. String은 소위 불변(immutable)객체라고 한다. String str1 = "abc"; , String str2 = "def"; 2개의 String객체가 있..

hardlearner.tistory.com

- StringBuilder를 사용하는 이유는 2.3. 에서 언급했듯이 문자열 결합 최적화를 위함

 

2.5. StringBuffer

- StringBuilder와 기능적으로 동일함

   (생성자를 포함한 메소드 수도 동일하고, 메소드의 기능도 동일하고, 메소드 이름과 매개변수의 선언도 동일하다고 함)

- 그렇다면 StringBuffer가 존재하는 이유는?

   → Thread의 안전을 위해서

   → 쓰레드가 안전하기는 한데... 불필요한 상황에서 사용하면  성능 저하를 유발함

- StringBuffer가 먼저 만들어졌는데,

   쓰레드의 안정성을 필요로 하지 않을 때, 사용하기에는 너무 느렸음.. 그래서 만들어진게 StringBuilder

   → 따라서, StringBuilder가 더 빠름

 

> 별첨1. String 인스턴스 생성 방법의 차이

String str = "";과 String str = new String(""); 은 둘 다 문자열을 저장한다는 공통점은 있지만

분명한 차이점이 있다. 그 차이가 무엇일까 찾아봤다.

 

실제로는 이렇게 쉬운 개념은 아니겠지만,

아직 초보이고 쉽게 이해하기 위해서 포괄적으로 차이점을 적어봤다.

 

우선 코드를 하나 가져왔음

// 1번 코드
String str1 = "고등학교";
String str2 = "고등학교";

// 2번 코드
String str3 = new String("고등학교");
String str4 = new String("고등학교");

- 먼저, String pool을 간단하게 이해해보자.

   → 간단하게 말하면 Java에는 String 객체를 모아둘 수 있는 공간이 있는데 그곳이 바로 String pool임

   → 이 String pool은 Heap Memory 안에 있다고 함

   → 그림으로 표현하자면... 이런 느낌..?

- 이제 1번 코드를 보자.

// 1번 코드
String str1 = "고등학교";
String str2 = "고등학교";

   → 1번 코드에서 str1과 str2는 "고등학교"라는 문자열을 가리키고 있는데

        이 "고등학교"라는 문자열은 String pool에 할당됨

   → 심지어 두 변수(str1, str2)는 "같은" 데이터(참조값)를 가리킴 ("고등학교"라는 문자열을 2개 생성해서 각각 가리키는게 아님)

   → 이때 JVM은 "고등학교"라는 문자열을 또 만들지 않고,

        (효율성을 고려해서?) str1이 만들어 놓은 "고등학교"라는 문자열을 그대로 str2도 사용하게(?) 만듦

   → 즉, 완벽히 같은 문자열(여기에서는 "고등학교")을 가리키는 변수들(여기에서는 str1, str2)이 100개, 1000개 있다면

        문자열을 100개, 1000개 생성해서 각각 가리키도록 하는게 아니라,

        문자열을 하나만 생성하고 모든 변수가 해당 문자열을 참조하도록 함

 

- 2번 코드를 보자.

// 2번 코드
String str3 = new String("고등학교");
String str4 = new String("고등학교");

   → 이 경우는 String pool에 할당하는게 아닌 Java Heap에 각각의 객체를 생성하게 됨

   → 그림으로 표현하면 아래와 같은 상황..?

   → 둘은 각각의 객체이기 때문에 참조값도 다름

   → 완벽히 같은 문자열(여기에서는 "고등학교")이라도 각각의 String 인스턴스로 생성되고

         가리키는 참조값(주소값)이 다 다르기 때문에

         String 인스턴스를 100개, 1000개 생성하면 "고등학교"라는 문자열이 100개, 1000개 만들어져서 할당됨

 

- 1번 코드를 사용하면 위험하지 않을까...?

   (둘은 같은 참조값을 가리키고 있으니까 str1에서 문자열을 변경해버리면 str2도 영향을 받지 않을까?)

// 1번 코드
String str1 = "고등학교";
String str2 = "고등학교";

   → String 인스턴스는 "Immutable 인스턴스"

         (이건 Java에서 기본적으로 정해놓은 규칙이라고 함)

   → Immutable(불변의) 인스턴스?

         인스턴스가 자신이 가지고 있는 데이터의 변경을 허용하지 않는 것

   → 즉, 한번 생성되면 그 데이터를 수정/변경할 수 없는 것이 Immutable 인스턴스임

   → 만약 데이터의 변경이 필요하다면? 기존의 인스턴스는 버리고 새로운 인스턴스를 만듦

   → 따라서, String 인스턴스는 기본적으로 한번 생성 후에는 데이터를 수정할 수 없는 Immutable 인스턴스이기 때문에

        str1의 값을 변경했다고 해서 str2의 값이 변경되는 상황은 발생할 수가 없음

 

 

※ Java의 메모리 스택과 힙에 대한 설명은 아래 블로그 참고

https://yaboong.github.io/java/2018/05/26/java-memory-management/

 

자바 메모리 관리 - 스택 & 힙

개요 Java 에서 메모리 관리는 어떻게 이루어지는지 알아보기 위함. Stack 과 Heap 영역 각 역할에 대해 알아본다. 간단한 코드예제와 함께 실제 코드에서 어떻게 Stack 과 Heap 영역이 사용되는지 살펴

yaboong.github.io

 

참고 자료 : 윤성우 선생님, 윤성우의 열혈 Java 프로그래밍 강의, https://cafe.naver.com/cstudyjava

 

윤성우의 프로그래밍 스터디그룹 [C/... : 네이버 카페

윤성우의 스터디 공간입니다. C와 JAVA를 공부하시는 분들은 모두 들어오세요. ^^

cafe.naver.com

 

추가 참고 자료 : https://readystory.tistory.com/140

 

Java의 String 이야기(2) - String pool이란 무엇인가?

우리는 지난 포스팅을 통해 Java의 String은 왜 불변인가에 대해 알아보고, Java에서는 String을 String constant pool에서 관리한다는 것을 알아보았습니다. 2019/12/19 - [JAVA] - Java의 String 이야기(1) - St..

readystory.tistory.com

 

 

Comments