본문 바로가기

일기

2023-03-03

면접 스터디를 시작하고 매주 받는 과제들로부터 조사한 내용들의 정리

 

 

 

String, StringBuilder, StringBuffer 각각의 차이점

String

자바에서 String 객체는 참조 클래스로, 다른 객체와 다르게 생성자를 이용하지 않고도 문자열 객체를 생성할 수 있습니다.
자바의 클래스 중에 유일하게 String 클래스만 이런 특수성 띄고 있다.
immutable(불변적) 특징을 가지고 있는데, String 객체 그 자체를 편집할 수 없습니다.

 

🤔 어? 기존에 변경 했던 것 같은데…?

String str = "hello";
str = str + " world";

처음에 String 은 불변적이다 라고 했습니다.

그런데 우리는 위의 코드처럼 기존에도 변경해서 사용했었습니다.

 

그런데, 사실 변경이 되는 것 처럼 느껴질 뿐이지 실제로는 기존의 String 객체의 참조변수를 버리고 편집된 새로운 String 객체의 참조변수로 바뀌는 형태입니다.

원리는 기존에 hello 값이 들어있던 참조변수 str이 “hello world” 라는 값을 가지고 있는 새로운 메모리 영역을 가리키게 됩니다. 이후에 처음 선언했던 “hello” 가 가리키던 메모리 영역은 Garbage 로 남아 있다가 Garbage Collection 에 의해 삭제됩니다.

이말은 String 객체를 가지고 계속해서 편집하면 객체들이 계속 생성된다는 의미가 됩니다. 만약 이런경우가 잦다면 메모리 관리적으로 한번 고려해봐야 합니다.

 

StringBuilder

가변 클래스이며 문자열을 수정할 때 마다 기존 객체 내부의 문자열을 바로 수정합니다.
이로 인해 위에서 기존의 String 객체를 수정하기 위해서 새로운 객체를 생성하지 않아도 되며, 문자열 연산이 빈번하게 일어날 경우 메모리를 효율적으로 사용할 수 있습니다.

동기화를 지원하지 않기 때문에 단일 스레드에서 StringBuffer 보다 성능이 뛰어납니다.

 

StringBuffer

마찬가지로 가변 클래스 이며 StringBuilder 와 기능면에서는 큰 차이가 없습니다.
하지만, StringBuilder 와는 다르게 동기화를 지원하기 때문에 멀티스레드 환경에서 사용하기에 적합합니다.
이를 스레드 안전(thread-safe) 라고도 합니다.

 

Thread-Safe

StringBuffer 와 StringBuilder 를 비교해서 설명하면…

StringBuffer 는 내부적으로 Synchronized 키워드를 사용하는데, 이를 통해서 하나의 스레드가 StringBuffer 객체를 사용하는 동안 다른 스레드는 해당 객체를 사용할 수 없도록 제한합니다.
이렇게 하면 여러 스레드가 동시에 StringBuffer 객체를 사용해도, 하나의 스레드가 해당 객체를 사용하는 동안 다른 스레드는 기다려야 하므로 일관성이 보장됩니다.
이는 멀티 스레드 환경에서 여러 스레드가 동시에 하나의 자원에 접근할 때, 해당 자원의 일관성을 보장하는 것을 말합니다. 즉, 여러 스레드가 동시에 해당 클래스의 객체를 사용해도 안전하게 동작한다는 의미입니다.
StringBuffer strTest = new StringBuffer("hello");
strTest.append(" world");

 

 

정리 하자면…

  • String 자바에서 String 객체는 참조 클래스로, 다른 객체와 다르게 생성자를 이용하지 않고도 문자열 객체를 생성할 수 있습니다. String 클래스만 이러한 특수성 띄고 있다. immutable(불변적) 특징을 가지고 있는데, String 객체 그 자체를 편집할 수 없습니다.
  • StringBuilder 가변 클래스이며 String과 다르게 문자열을 수정할 때 기존 객체 내부의 문자열을 바로 수정합니다. 동기화를 지원하지 않기 때문에 단일 스레드에서 StringBuffer 보다 성능이 뛰어납니다.
  • StringBuffer StringBuilder 와 기능면에서 큰 차이는 없지만 thread-safe 를 지원합니다. 이 덕분에 StringBuilder 와는 다르게 동기화를 지원해 멀티 스레드 환경에 적합합니다.

String 은 불변, StringBuffer와 StringBuilder는 가변의 속성을 가집니다. StringBuilder 는 ****동기화를 지원하지 않기 때문에 단일 스레드에서 StringBuffer 보다 성능이 뛰어납니다. StringBuffer는 StringBuilder와는 다르게 동기화를 지원해 멀티 스레드 환경에 적합합니다.

 

 

 

 

Spring Bean 생성 주기에 대해 알고 있는지?

스프링의 컨테이너는 Bean 객체들을 관리합니다.
이는 객체의 생성과 소멸, 즉 생명주기(LifeCycle) 를 관리한다는 것을 의미합니다.
스프링의 Bean 생성 주기는 크게 3가지로 구분됩니다.

대략적인 흐름

스프링컨테이너 생성 -> 스프링 빈 생성 -> 의존관계 주입 -> 초기화 콜백 -> 사용 -> 소멸전 콜백 -> 스프링 종료

  1. Bean 생성
    • Spring IOC 컨테이너가 Bean 의 클래스를 로드합니다.
    • Bean 의 생성자가 호출되어 객체가 생성됩니다.
    • 생성된 객체는 스프링 컨테이너의 Bean 팩토리에 등록됩니다.
  2. 의존성 주입
    • 스프링 컨테이너는 생성된 Bean 객체의 의존성을 주입합니다.
  3. 초기화 및 소멸
    • Bean 객체가 모두 생성되고 의존성이 주입된 후, 초기화 메서드가 호출됩니다. 초기화 메서드는 개발자가 지정한 메서드입니다.
    • Bean 객체가 소멸될 때, 소멸 메서드가 호출됩니다. 이 또한 개발자가 지정합니다.

 

3가지 초기화 및 소멸 방법

 

1. Bean 초기화, 소멸 메서드 지정

인터페이스를 구현하지 않고 @Bean 어노테이션의 속성에 initMethod, destroyMethod 속성을 추가해서 초기화, 소멸 메서드의 구현이 가능합니다. 
이는 수정이 불가능한 외부 클래스, 아래에서 말하는 두 인터페이스를 구현 불가능한 클래스의 객체를 스프링 컨테이너에 등록할 때 유용합니다.

@Bean(initMethod = "init", destroyMethod="close"

하지만 아래에의 예제에서는 destroyMethod="close" 가 없는데, 이는 @Bean 의 destroyMethod 의 기본값이 inferred 로 되어있기 때문입니다. 

즉, close 또는 shutdown 의 종료 이름 메소드가 보이면 그 메소드를 자동으로 호출 해줍니다.

 

예제 코드

@Configuration
public class TestConfig {
    @Bean(initMethod="init")
    public TestClient testClient() {
        TestClient testClient = new TestClient();
				testClient.setFormat("%s, Hello World!");
        return testClient;
    }
}

 

 

2. @PostConstruct, @PreDestroy 어노테이션 사용

Spring 2.5 이후 부터 지원하는 어노테이션 입니다.
스프링 컨테이너는 @PostConstruct@PreDestroy 어노테이션을 활용해서, Bean 객체의 초기화 및 소멸 메서드의 작성도 가능합니다.
즉, 방금 말한 두 어노테이션을 붙여 원하 메서드를 생명주기 메서드로 지정이 가능합니다.

하지만 이 기능은 JavaEE Module 인 java.xml.ws.annotation 의 일부인데, 이것이 Java9 부터 Deprecated 되었습니다.

그래서 이를 사용하려면 javax.annotations 종속성을 추가해서 사용하면 가능합니다.

 

예제 코드

@Component
public class TestComponent {
	...

	// 객체의 초기화 단계 입니다.
	// 객체 생성 후 진행할 초기화 작업을 위해 실행하는 메서드를 선언합니다.
	@PostConstruct
	public void init() {
	    System.out.println("초기화 메서드 호출");
	}

	// 객체의 소멸 단계 직전 입니다.
	// 스프링 컨테이너에서 객체(Bean) 을 제거하기 전에 수행할 메서드에 선언합니다.
	@PreDestroy
	public void destroy() {
	    System.out.println("종료 메서드 호출");
	}
}

 

 

InitializingBean, DisposableBean 인터페이스 사용

Bean의 생성 주기를 관리하는 인터페이스로 InitializingBean 과 DisposableBean 이 있습니다.
다만, 이방법은 스프링 전용 인터페이스로 스프링에 의존합니다.
또, 초기화와 소멸 메서드의 이름의 변경이 불가능합니다.
  • InitializingBean
    Bean 객체가 초기화되기 전에 호출될 메서드를 정의하는 인터페이스 입니다.
  • DisposableBean
    Bean 객체가 소멸될 때 호출될 메서드를 정의하는 인터페이스 입니다.
@Component
public class TestComponent implements InitializingBean, DisposableBean{
	@Override
	public void afterPropertiesSet() throws Exception {
		// @PostConstruct 역할을 합니다.
	}
	@Override
	public void destroy() throws Exception {
		// @PreDestroy 역할을 합니다.
	}
}

'일기' 카테고리의 다른 글

2023-03-06  (0) 2023.03.06
2023-03-04  (0) 2023.03.04
2023-03-02  (0) 2023.03.02
2023-03-01  (0) 2023.03.02
2023-02-28  (0) 2023.02.28