delpho
Java에 대하여 - 4 본문
1. 강한 결합과 느슨한 결합이 무엇인지 설명해주세요.
# 의존성
- 어떤 클래스A가 다른 클래스(B) 또는 B의 인터페이스를 이용할때 A가 B에 의존한다고 한다.
- A는 B없이 작동할 수 없음
- 여기서 A는 dependant / B는 dependency라고 함
- dependant는 자신의 dependencies들에게 의존
- 의존성이 높다는건(강하다는건) A객체를 수정했을때, 그 객체와 결합된 B에서도 코드를 수정해야되는 경우가 생기는 것
- 이때, 두 클래스는 결합(coupled)되어 있음.
- 두 클래스 사이의 결합은 강할수도, 느슨할 수도 있음
- 의존성이 강한지 약한지에 따라 달림
- 의존성, 결합은 방향이 존재
- A가 B에게 의존한다고해서 B가 A에 꼭 의존적인것은 아님!
# 결합도
- 서로 다른 모듈 간에 상호 의존하는 정도 또는 연관된 관계를 의미
# 의존도가 낮거나 결합도가 느슨할 경우
- 요구사항 변화에 자유롭다.
- 테스트 코드 작성에 유리하다.
- 코드의 중복을 줄일 수 있다.
# 강한 결합
- 어떠한 객체가 다른 객체에 강한 의존성을 가지고 있음
class SamsungTV {
public void seeing() {
System.out.println("냠냠");
}
}
class People {
SamsungTV c = new SamsungTV();
public void startSeeing() {
t.seeing();
}
}
- People 클래스는 SamsungTV 클래스가 없으면 정의 못함
- SamsungTV 클래스를 다른 tv으로 바꾸게 되면 or 메소드를 바꾸게 되면 People 클래스의 코드가 대부분 변경됨
--> 유지보수 측면에서 문제
# 느슨한 결합
- 결합되어있는 클래스간의 의존성을 약하게 만듬
- 다형성, 디자인 패턴(팩토리) 이용
- 다형성 이용
- interface 이용 + 상속 (메서드 재정의)
- 인터페이스를 이용함으로써 모든 TV 클래스가 같은 메소드들을 가질 수 밖에 없도록 강제할 수 있게 된것
- 이 메인 클래스에서는 TV 인터페이스 타입의 변수로 SamsungTV 객체를 참조한다.
- 이런 묵시적 형변환 (Promotion)을 이용해서 객체를 참조하게 되면 SamsungTV 를 LgTV 객체로 바꾸고 싶을 때,
참조하는 객체만 변경하면 되기 때문에 객체를 바꾸는게 아주 쉬워짐 - 수정이 최소화됨!
public interface TV {
public void powerOn();
}
public class SamsungTV implements TV {
public SamsungTV() {}
@Override
public void powerOn() {
System.out.println("SamsungTV----전원 켠다.");
}
}
public class LgTV implements TV {
public LgTV() {}
@Override
public void powerOn() {
System.out.println("LgTV----전원 켠다.");
}
public class TVuserPolymorphism {
public static void main(String[] args) {
TV tv = new SamsungTV();
// or TV tv = new LgTV();
tv.powerOn();
}
}
- 디자인 패턴(팩토리) 이용
- Factory 패턴은 사용할 객체 생성을 캡슐화 해서 TV.java 클래스와 TVuserPolymorphism.java 클래스 사이를 느슨한 결합 상태로 만들어줌
- Factory 를 사용하면 인터페이스를 사용할 때 보다 결합도도 훨씬 낮아지고,
- TVuserPolymorphism 클래스 내부적으로 코드의 변경이 일어날 필요 없이, Factory를 통해 값을 전달하여 원하는 객체를 받아 사용 가능
public class BeanFactory {
public BeanFactory() {}
public Object getBean(String beanName) {
if (beanName.equals("samsung")) {
return new SamsungTV();
} else {
return new LgTV();
}
}
}
public class TVuserFactory {
public static void main(String[] args) {
BeanFactory factory = new BeanFactory();
TV tv = (TV) factory.getBean("samsung");
tv.powerOn();
}
}
2. 직렬화와 역직렬화에 대해서 설명해주세요.
# 직렬화 역직렬화 필요성
- 흔히 객체를 직렬화 한다 라는 표현을 사용
- 즉, 데이터를 쓰거나 읽을 수 있게 지원하는 의미
- 디스크로의 저장 or 네크워크로의 데이터 전송에서 많이 사용
- 객체를 디스크에 저장하기 위해서
# 직렬화 (Serialization)
- 자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 시스템에서도 사용할 수 있도록 연속적인 바이트 형태로 데이터 변환하는 기술
- JVM의 메모리에 상주(힙 또는 스택)되어 있는 객체 데이터를 바이트 형태로 변환하는 기술
- 객체들의 데이터를 연속적인 데이터로 변형하여 Stream을 통해 데이터를 읽도록 해줌
- 주로 객체들을 통째로 파일로 저장하거나 전송하고 싶을 때 주로 사용
# 직렬화 과정
- 직렬화가 가능한 클래스에 implements Serializable 하기
- 여러가지 상황에 따라 직렬 가능한 클래스와 데이터가 결정
- Serializable 인터페이스를 implements
- Serializable 없는 경우
- 보통의 경우는 직렬화가 불가능
- Serializable을 implement한 클래스를 상속받은 경우 직렬화 가능
- transient를 이용하여 직렬화 대상에서 제외
- 보통 클래스의 멤버변수 전부 직렬화 대상에 해당
- but 멤버변수의 일부를 제외하고 싶다면 transient를 통해 지정
- 다른 객체를 멤버변수로 가지고 있는 경우
- Serializable 인터페이스를 구현한 클래스가 하나라도 없다면 직렬화불가
- 여러가지 상황에 따라 직렬 가능한 클래스와 데이터가 결정
# 역직렬화 (Deserialization)
- 바이트로 변환된 데이터를 다시 객체로 변환하는 기술
- 직렬화된 바이트 형태의 데이터를 객체로 변환해서 JVM으로 상주시키는 기술
- 직렬화된 파일 등을 역으로 직렬화하여 다시 객체의 형태로 만드는 것
- 저장된 파일을 읽거나 전송된 스트림 데이터를 읽어 원래 객체의 형태로 복원
3. 자바의 동시성 이슈(공유자원 접근)에 대해 설명해주세요.
# 동시성 이슈란
- 스레드 = cpu 작업의 한단위
- 멀티스레드 방식 = 멀티태스킹을 하는 방식 중, 한 코어에서 여러 스레드를 이용해서 작업을 처리하는 방식
- 멀티 스레드를 이용하면 여러 스레드가 동시에 하나의 자원을 공유하고 있기 때문에 같은 자원을 두고 교착상태(deadlock) 같은 문제가 발생하는 것
# 동시서 제어 방법
1. 암시적 Lock (synchronized)
문제가 된 메서드, 변수에 synchronized 키워드 추가
2. 명시적 Lock
직접적으로 Lock 객체를 생성하여 사용
class Count {
private int count = 0;
private Lock lock = new ReentrantLock();
public int view() {
return count++;
}
public Lock getLock(){
return lock;
};
}
3. 스레드 안전한 객체 사용
- concurrent 패키지는 각종 스레드 안전한 컬랙션을 제공
- 불변 객체 사용
4. Mutable 객체와 Immutable 객체의 차이점에 대해 설명해주세요.
# Mutable 객체
- 객체 생성 이후에도 객체의 속성이 변할 수 있음을 의미
- 불변객체와 다르게 heap영역에 생성된 객체를 변경 가능
- 대표적인 가변 객체는 List, ArrayList, HashMap,StringBuilder,StringBuffer 등
- 가변객체를 multi-thread 환경에서 사용하려면 별도의 동기화 처리를 해줘야함
- 동기화 처리된 객체중 하나가 StringBuffer
- Java에선 객체가 참조를 통해 공유되기 때문에 어떤 스레드에서 객체의 값을 변경할지 모름
- 그렇기 때문에 MUTABLE 객체는 자연스럽게 ‘thread-not-safe’
# Immutable 객체
- 객체 생성 이후에 객체의 속성이 변할 수 없음을 의미
- 힙 영역에 저장된 값을 수정할 수 없다
- new 연산자로 객체를 생성하면 heap영역에 객체가 생기고 래퍼런스 값을 가지는 변수가 stack에 생길 것이다.
- 오직 새 객체를 만들어 래퍼런스 값을 주는 재 할당만이 가능
String a = "Star";
a = a.concat("Craft");
- StarCraft라는 새로운 객체를 만들어서 a에 재할당된 것
- 대표적으로 String, Boolean, Integer, Float, Long 등이 있다
- 객체이므로 String을 제외하면 primitive의 래퍼타입
# class 불변 객체 만들기
- 클래스를 final로 선언 (클래스 상속 못하도록)
- 모든 멤버변수를 private, final로 설정
- setter 메서드를 구현 X
- 객체 생성을 위해 static 팩토리 메소드 제공 (기본생성자가 아닌 팩토리 메소드를통해 객체 생성 강요)
- 멤버변수 중 가변객체타입의 field 변수가 있을 경우, 그 가변객체 타입의 field변수에 대해 직접적으로 접근하지 못하도록 copy 객체를 생성하여 새로운 인스턴스를 반환하도록 방어적 복사본 전략을 사용
# 불변 객체 장단점
- 장점
- 객체에 대한 신뢰도가 올라간다.
- multi-thread 환경에서 동기화 처리 없이 객체를 공유 가능하다.(쓰레드에 안전하다 라고함)
- 단점
- 객체의 값이 할당될 때 마다 새로운 객체가 필요하다. 따라서 메모리 누수와 성능저하를 발생시킬 수 있다.
# Mutable vs Immutable
생성된 이후 수정 가능 | 생성된 이후 수정 불가능 |
이미 존재하는 객체에 재할당(값 변경) | 이미 존재하는 객체이더라도 새로운 객체를 생성하여 재할당 |
값을 변경할 수 있는 메소드 제공 | 값을 변경할 수 있는 메소드 제공 x |
Mutable class일 경우 Getter와 Setter 존재 | Immutable class일 경우 Getter와 Setter 미존재 |
thread safe하지 않을 수 있음(병렬처리 시 값 보장할 수 없게 됨) | thread safe(병렬처리 시 문제 없음) |
StringBuffer, StringBuilder, java.util.Date 등이 해당 | Legacy classes, Wrapper classes, String class 등이 해당 |
5. 자바에서 null을 안전하게 다루는 방법에 대해 설명해주세요.
# null 이란
- 객체가 없거나 상태가 정의되지 않은 상태
# null 참조
- 특별한 값이 없음을 나타내려고 null을 도입했고 이 값을 사용하려고 할 때 오류를 내도록 설계
- 두 참조값이 null일 때 두 참조는 동일하다고 판단
- null은 모든 타입의 멤버가 될 수 있음
- 참조 변수 사용 시 널을 확인해야 함
# null과 관련된 문제
- 런타임에 NPE(NullPointerException)라는 예외를 발생시킬 수 있습니다.
- NPE 방어를 위해서 들어간 null 체크 로직 때문에 코드 가독성과 유지 보수성이 떨어집니다.
# null을 안전하게 다루는 방법
- @NonNullApi를 패키지 레벨에 선언
- 패키지 하위의 class method의 인자 또는 리턴이 null일 경우 IDE에서 Warning으로 알려줌
- @NotNull 이나 @Nullable 어노테이션을 사용
- 메소드가 null safe인지 아닌지를 annotation을 사용하여 표시하는 것이 좋다.
- 그래야 컴파일러가 여러분이 미처 확인하지 못 한 또는 굳이 확인할 필요가 없는 부분에서 null check를 하도록 도와줄 수 있다.
- Optional 클래스 사용
- “존재할 수도 있지만 안 할 수도 있는 객체”, 즉, “null이 될 수도 있는 객체”을 감싸고 있는 일종의 래퍼 클래스
- 직접 다루기에 위험하고 까다로운 null을 담을 수 있는 특수한 그릇
- Optional 장점
- NPE를 유발할 수 있는 null을 직접 다루지 않아도 됩니다.
- 수고롭게 null 체크를 직접 하지 않아도 됩니다.
- 명시적으로 해당 변수가 null일 수도 있다는 가능성을 표현할 수 있습니다. (따라서 불필요한 방어 로직을 줄일 수 있습니다.)
- “존재할 수도 있지만 안 할 수도 있는 객체”, 즉, “null이 될 수도 있는 객체”을 감싸고 있는 일종의 래퍼 클래스
출처
https://velog.io/@huttels/%EC%9D%98%EC%A1%B4%EC%84%B1%EC%9D%B4%EB%9E%80
https://madplay.github.io/post/coupling-and-cohesion-in-software-engineering
https://swk3169.tistory.com/185
https://hanbulkr.tistory.com/14
https://steady-coding.tistory.com/576
https://codevang.tistory.com/164
https://cantcoding.tistory.com/41
https://choiblack.tistory.com/47
https://velog.io/@guswlsapdlf/Java%EC%9D%98-Mutable%EA%B3%BC-Immutable
https://www.daleseo.com/java8-optional-after/
'CS' 카테고리의 다른 글
DB에 대하여 - 1 (0) | 2022.06.19 |
---|---|
Spring에 대하여 - 5 (0) | 2022.06.19 |
Java에 대하여 - 3 (0) | 2022.06.10 |
Java에 대하여 - 2 (0) | 2022.06.08 |
Java에 대하여 - 1 (0) | 2022.06.08 |