강한 결합과 느슨한 결합이 무엇인지 설명해주세요.
강한 결합
말 그대로 한 객체가 다른 객체와 강하게 의존 관계가 형성되어 있을 경우 그 결합을 강한 결합이라고 함.
public class B {
private A a;
public B() {
this.a = new A();
}
public void doB() {
a.doA();
}
}
public class A {
public void doA() {
System.out.println("doA()");
}
}
예를 들어 이렇게 A 클래스가 없으면 B 클래스를 정의할 수 없는 상황인 경우 B 클래스는 A 클래스에 의존한다고 표현함. 그리고 이 때 A 클래스를 다른 클래스로 바꾸면 B 클래스의 코드도 바꿔줘야 함!
간단한 코드라 망정이지 복잡한 코드면 유지 보수하기 넘 빡셈!!
이걸 해결할 수 있는 방법이 인터페이스를 활용하는 거임!!!
느슨한 결합
public interface C {
void doC();
}
public class A implements C {
@Override
public void doC() {
System.out.println("doA()");
}
}
public class D implements C {
@Override
public void doC() {
System.out.println("doD()");
}
}
public class B {
private C c;
public B(C c) {
this.c = c;
}
public void doB() {
c.doC();
}
}
이렇게 인터페이스를 활용하면 B 클래스 내부적으로 코드의 변경이 일어날 필요 없이, 생성자를 통해서 객체를 받아 멤버 변수에 대입하기만 하면 오브젝트를 변경할 수 있게 됨!!! -> 유지보수가 아주 쉬워짐!!!
직렬화와 역직렬화에 대해서 설명해주세요.
자바에서 입출력을 할 때에는 스트림이라는 통로를 통해 데이터가 이동함. 하지만 객체는 바이트형이 아니라서 스트림을 통해 파일에 저장하거나 네트워크로 전송할 수 없음.따라서 객체를 스트림을 통해 입출력하려면 바이트 배열로 변환하는 것이 필요한데, 이를 '직렬화' 라고 함. 반대로 스트림을 통해 받은 직렬화된 객체를 원래 모양으로 만드는 과정을 역직렬화라고 함.
Serializable 이라는 인터페이스를 구현(implements)해야 직렬화할 수 있음!
자바의 동시성 이슈(공유 자원 접근)에 대해 설명해주세요.
스레드는 cpu 작업의 한단위이다.
여기서 멀티스레드 방식은 멀티태스킹을 하는 방식 중, 한 코어에서 여러 스레드를 이용해서 작업을 처리하는 방식임.
멀티 스레드를 이용하면 공유하는 자원이 멀리 프로세스방식보다 context switcing 오버헤드가 작아, 메모리 리소스가 상대적으로 적다는 장점이 있다. 하지만 자원을 공유해서 단점도 존재한다.
그게 바로 동시성(concurrency) 이슈이다.
여러 스레드가 동시에 하나의 자원을 공유하고 있기 때문에 같은 자원을 두고 교착상태(deadlock) 같은 문제가 발생하는 것이다.
Immutable 객체와 Mutable 객체의 차이점에 대해 설명해주세요.
객체들은 기본적으로 heap 영역에 할당되고 stack 영역에 레퍼런스 값을 갖는 참조 변수들로 접근 가능함!
Immutable 객체
String, Boolean, Integer, Float, Long 등이 있음 (String 빼고는 원시타입임!)
new 연산자로 객체를 생성하면 heap영역에 객체가 생기고 래퍼런스 값을 가지는 변수가 stack에 생길 것이다. 불변 객체라는 것은 이 객체의 값을 heap 영역에서 바꿀 수 없다는 뜻이다.
우리는 오직 새 객체를 만들어 래퍼런스 값을 주는 재 할당만이 가능하다.
String a = "a";
a = a.concat("bc");
System.out.println(a);
예를 들어,
처음 a변수에 "a"의 주소가 할당된다.
그 후 a에 "bc"를 이어 주면 a는 "abc"로 출력이 될 것이다.
a가 불변객체인데 변한 것 처럼 보일 수 있다.
하지만 변한 것이 아니고 "abc"라는 새로운 객체를 만들어서 a에 재 할당 된것이다.
이거 전에 설명들었던 것 중에 코테 문제 풀 때 String + String 이런 식으로 문자열을 연결시키지 말고 StringBuilder.append() 써서 문자열 연결시켜야 된다는 거랑 일맥 상통함!
Mutable 객체
Mutable객체는 불변객체와 다르게 heap영역에 생성된 객체를 변경 할 수 있다.
대표적인 가변 객체는 List, ArrayList, HashMap, StringBuilder, StringBuffer 등이 있다.
가변객체를 multi-thread 환경에서 사용하려면 별도의 동기화 처리를 해줘야한다.
이렇게 동기화 처리된 객체중 하나가 StringBuffer이다.
자바에서 null을 안전하게 다루는 방법에 대해 설명해주세요.
Connection conn = getConnection();
if(conn == null) {
throw new RuntimeException("Connection is null");
}
이런 식으로 null을 방지할 수 있지만, 밑의 3가지 방법으로 더 간단하게 null을 방지할 수 있음!
1. Java : 단정문 (assertion)
public method가 아닌 곳에는 assert를 사용하여 null을 방어할 수 있음.
2. Java : java.util.Objects
메소드의 인자를 받을 때 Objects.requireNonNull()을 사용하여 방어할 수 있음.
3. Java : java.util.Optional
Optional을 사용해 리턴 타입에서 null을 반환하지 않도록 방어할 수 있음.
물론 애초에 NullPointerException이 나지 않게 설계하는게 제일 좋다고 함!