Skip to content
jsjune edited this page Mar 16, 2022 · 6 revisions

- String vs StringBuffer vs StringBuilder

- String

  • String은 불변(immutable)의 속성을 갖는다.
String str = "hello";
str = str + "world";
  • 기존에 "hello"값이 들어가있던 String 클래스의 참조변수 str이 "hello world"라는 값을 가지고 있는 새로운 메모리영역을 가리키게 변경되고 처음 선언했던 "hello"로 값이 할당되어 있던 메모리 영역은 Garbage로 남아있다가 GC(garbage collection)에 의해 사라지게 되는 것 입니다.
  • String 클래스는 불변하기 때문에 문자열을 수정하는 시점에 새로운 String 인스턴스가 생성된 것이다.
  • 위와 같이 String은 불변성을 가지기 때문에 변하지 않는 문자열을 자주 읽어들이는 경우 String을 사용해 주시면 좋은 성능을 기대할 수 있다.
  • 그러나 문자열 추가, 수정, 삭제 등의 연산이 빈번하게 발생하는 알고리즘에 String 클래스를 사용하면 힙 메모리(Heap)에 많은 임시 가비지(Garbage)가 생성되어



- StringBuffer/StringBuilder

  • String과는 반대로 StringBuffer/StringBuilder는 가변성 가지기 때문에 .append() .delete() 등의 API를 이용하여 동일 객체내에서 문자열을 변경하는 것이 가능하다.
  • 따라서 문자열의 추가, 수정, 삭제가 빈번하게 발생할 경우라면 String클래스가 아닌 StringBuffer/StringBuilder를 사용해야 한다.
StringBuffer sb = new StringBuffer("hello");
sb.append("world");



- StringBuffer vs StringBuilder

  • 가장 큰 차이점은 동기화의 유무로써 StringBuffer는 동기화 키워드를 지원하여 멀티쓰레드 환경에서 안전하다는 점(thread-safe) 이다.
  • String도 불변성을 가지기때문에 마찬가지로 멀티쓰레드 환경에서의 안전성(thread-sage)을 가지고 있다.
  • 반대로 StringBuilder는 동기화를 지원하지 않기때문에 멀티쓰레드 환경에서 사용하는 것은 적합하지 않지만 동기화를 고려하지 않는 만큼 단일쓰레드에서의 성능은 StringBuffer보다 뛰어나다.

  • String :
    • 짧은 문자열을 더할 경우
    • 문자열 연산이 적고 멀티쓰레드 환경일 경우
  • StringBuffer :
    • 스레드에 안전한 프로그램이 필요할 때나, 개발 중인 시스템의 부분이 스레드에 안전한지 모를 경우
    • 문자열 연산이 많고 멀티쓰레드 환경일 경우
  • StringBuilder :
    • 스레드에 안전한지 여부가 전혀 관계 없는 프로그램을 개발할 경우
    • 문자열 연산이 많고 단일쓰레드이거나 동기화를 고려하지 않아도 되는 경우






- Scanner vs BufferedReader

- Scanner

  • InputStream을 받아온다.
  • InputStreamReader를 통해 StreamDecoder를 호출한다.
  • 바이트 단위 데이터를 Character 단위 데이터로 변환한다.
  • 이후 next(), nextInt(), nextDouble(), nextFloat() 등을 통해 값을 받는다.
    • 참고로 효율성이 떨어지는 이유는 뒤에 정규식 검사를 많이 하기 때문이다.
Scanner sc = new Scanner(System.in);
  • System.in은 InputStream의 정적필드이다.
  • System.in으로만 입력을 받고 처리를 안한다면 바이트 단위로 받게되어 UTF-8의 입력을 처리할 수 없다.



- BufferedReader

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  • InputStreamReader를 통해 바이트 단위의 데이터를 char로 처리한다.
  • buffer를 이용해서 문자를 쌓아두고 한 번에 문자열처럼 보낸다.
  • br.readline() 메서드는 한줄을 통으로 String으로 받아온다.
  • inputStream -> InputStreamReader -> BufferReader
  • 위 과정을 통해 byte, char, String 타입으로 변환이 된다.
  • 버퍼가 있는 스트림이고, 정규식 검사를 하지 않기 때문에 빠르다.
  • 키보드의 입력이 있을 때마다 바로 이동시키는 것 보다는, 중간에 버퍼를 두어 한번에 묶어 보내는 것이 더 효율적이고 빠른 방법이다.



- Scanner/StringBuffer

  • Scanner : 키보드가 눌릴 때마다 데이터를 목적지에 이동
  • StringBuffer : 버퍼에 값들을 모았다가 모인 데이터를 목적지로 이동
  • Scanner가 사용하기는 더 편리하지만, 데이터 양이 많아질 겨우 StringBuffer를 사용하는 것이 효율적으로 데이터를 전달할 수 있다.




- Object 클래스

- java.lang 패키지

  • java.lang 패키지는 자바에서 가장 기본적인 동작을 수행하는 클래스들의 집합이다.
  • 자바에서는 java.lang 패키지의 클래스들은 import문을 사용하지 않아도 클래스 이름만으로 바로 사용할 수 있도록 하고 있다.



- java.lang.Object 클래스

  • java.lang 패키지 중에서도 가장 많이 사용되는 클래스는 바로 Object 클래스이다.
  • Object 클래스는 모든 자바 클래스의 최고 조상 클래스가 된다.
  • 따라서 자바의 모든 클래스는 Object 클래스의 모든 메소드를 바로 사용할 수 있다.



- toString()

  • toString() 메소드는 해당 인스턴스에 대한 정보를 문자열로 반환한다.
  • 이때 반환되는 문자열은 클래스 이름과 함께 구분자로 '@'가 사용되며, 그 뒤로 16진수 해시 코드(hash code)가 추가된다.
  • 16진수 해시 코드 값은 인스턴스의 주소를 가리키는 값으로, 인스턴스마다 모두 다르게 반환된다.
package algorithmn;
class Car{ }
public class Test {
    public static void main(String[] args) {
        Car car1 = new Car();
        Car car2 = new Car();
        System.out.println(car1.toString());
        System.out.println(car2.toString());
    }
}
> algorithmn.Car@3f3afe78
> algorithmn.Car@7f63425a

- equals()

  • equals() 메소드는 해당 인스턴스를 매개변수로 전달받는 참조 변수와 비교하여, 그 결과를 반환한다.
  • 이때 참조 변수가 가리키는 값을 비교하므로, 서로 다른 두 객체는 언제나 false를 반환하게 된다.
package algorithmn;
class Car{ }
public class Test {
    public static void main(String[] args) {
        Car car1 = new Car();
        Car car2 = new Car();
        System.out.println(car1.equals(car2));
        car1=car2;
        System.out.println(car1.equals(car2));
    }
}
> false
> true



- clone()

  • clone() 메소드는 해당 인스턴스를 복제하여, 새로운 인스턴스를 생성해 반환한다.
  • 하지만 Object 클래스의 clone() 메소드는 단지 필드의 값만을 복사하므로, 필드의 값이 배열이나 인스턴스면 제대로 복제할 수 없다.
  • 따라서 이러한 경우에는 해당 클래스에서 clone() 메소드를 오버라딩하여, 복제가 제대로 이루어지도록 재정의해야 한다.
package algorithmn;

import java.util.ArrayList;

class Car implements Cloneable{
    private String modelName; // modelName 선언
    private ArrayList<String> owners = new ArrayList<String>(); // Arraylist 'owners' 선언

    public String getModelName(){return this.modelName;} // modelName의 값을 반환함
    public void setModelName(String modelName){this.modelName=modelName;} // modelName의 값을 설정함

    public ArrayList getOwners(){return this.owners;} // owners의 값을 반환함
    public void setOwners(String ownerName){this.owners.add(ownerName);} // owners의 값을 추가함

    public Object clone(){
        try {
            Car clonedCar = (Car)super.clone();
//            clonedCar.owners=(ArrayList)owners.clone();
            return clonedCar;
        } catch (CloneNotSupportedException ex) {
            ex.printStackTrace();
            return null;
        }
    }
}
public class Test {
    public static void main(String[] args) {
        Car car1 = new Car();
        car1.setModelName("아반떼");
        car1.setOwners("홍길동");
        System.out.println("Car1 : " + car1.getModelName() + ", " + car1.getOwners() + "\n");

        Car car2 = (Car)car1.clone();
        car2.setOwners("이순신");
        System.out.println("Car1 : " + car1.getModelName() + ", " + car1.getOwners());
        System.out.println("Car2 : " + car2.getModelName() + ", " + car2.getOwners());
    }
}
Car1 : 아반떼, [홍길동]

Car1 : 아반떼, [홍길동, 이순신]
Car2 : 아반떼, [홍길동, 이순신]
- 주석 지우면 -
Car1 : 아반떼, [홍길동]

Car1 : 아반떼, [홍길동]
Car2 : 아반떼, [홍길동, 이순신]
  • 정확한 복제를 위해서는 위처럼 배열이나 인스턴스인 필드에 대해서는 별도로 clone()메소드를 구현하여 호출해야 한다.



- Object 메소드

메소드 설명
Protected Object clone() 해당 객체의 복제본을 생성하여 반환함
boolean equals(Object obj) 해당 객체와 전달받은 객체가 같은지 여부를 반환함
Protected void finalize() 해당 객체를 더는 아무도 참조하지 않아 가비지 컬렉터가 객체의 리소스를 정리하기 위해 호출함.
Class get Class() 해당 객체의 클래스 타입을 반환함.
int hashCode() 해당 객체의 해시 코드값을 반환함
void notify() 해당 객체의 대기(wait)하고 있는 하나의 스레드를 다시 실행할 때 호출함.
void notifyAll() 해당 객체의 대기(wait)하고 있는 모든 스레드를 다시 실행할 때 호출함.
String toString() 해당 객체의 정보를 문자열로 반환함.
void wait() 해당 객체의 다른 스레드가 notify()나 notifyAll() 메소드를 실행할때까지 현재 스레드를 일시적으로 대기(wait)시킬때 호출함.
void wait(long timeout) 해당 객체의 다른 스레드가 notify()나 notifyAll() 메소드를 실행하거나 전달받은 시간이 지날 때까지 현재 스레드를 일시적으로 대기(wait)시킬 때 호출함.
void wait(long timeout, int nanous) 해당 객체의 다른 스레드가 notify()나 notifyAll() 메소드를 실행하거나 전달받은 시간이 지나거나 다른 스레드가 현재 스레드를 인터럽트(interrrupt) 할 때까지 현재 스레드를 일시적으로 대기(wait)시킬 때 호출함.





- 래퍼 클래스 (Wrapper Class)

  • 자바의 자료형은 기본 타입(primitive type)과 참조 타입(reference type)으로 나누어진다.
    • 기본 타입은 정수, 실수, 문자, 논리 리터럴을 저장하는 타입
    • 참조 타입은 배열, 열거, 클래스, 인터페이스 등 객체의 위치를 참조하는 타입



- 래퍼 클래스란?

  • 래퍼 클래스란 8개의 기본 타입에 해당하는 데이터를 객체로 표현하기 위해 포장해주는 클래스
  • 기본 타입의 객체화를 말한다.



- 래퍼 클래스 특징

  • 기본 타입은 값을 갖는 객체인 포장 객체를 생성할 수 있다.
  • 래퍼 클래스는 각 타입에 해당하는 데이터를 파라미터로 전달받아 해당 값을 가지는 객체로 만들어준다.
  • 래퍼 클래스로 감싸고 있는 기본 타입 값은 외부에서 변경할 수 없다.
  • 변경하기 위해서는 새로운 포장 객체를 만들어야 한다.

기본 타입 래퍼 클래스
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean



- 래퍼 클래스 구조

  • wrapper class들은 모두 java.lang 패키지에 포함되어 제공된다.
  • Object 크래스 : 모든 wrapper class의 부모 클래스
  • Number 클래스 : 내부적으로 숫자를 다루는 wrapper class들의 부모 클래스



- 박싱(Boxing)과 언박싱(Unboxing)

  • 박싱 : 기본타입의 데이터 -> 래퍼 클래스의 인스턴스로 변환하는 과정
  • 언박싱 : 래퍼 클래스의 인스턴스에 저장된 값 -> 기본 타입의 데이터로 꺼내는 과정
// 박싱
// Integer 래퍼 클래스 num에 21의 값을 저장
Integer num = new Integer(21);

// 언박싱
// 래퍼 클래스 num의 값을 꺼내 가져온다.
int n = num.intValue();
// 오토 박싱
Integer num = 21;

// 오토 언박싱
int n = num;

Clone this wiki locally