java의 특징
- 자바는 객체지향 프로그래밍 언어
- 기본 자료형을 제외한 모든 요소들이 객체로 표현되고, 객체 지향 개념의 특징인 캡슐화, 상속, 다형성이 잘 적용된 언어
장점
- JVM(자바가상머신) 위에서 동작하기 때문에 운영체제에 독립적이다.
- GabageCollector 를 통한 자동적으로 메모리 관리가 가능하다
단점
- JVM 위에 동작하기 때문에 실행 속도가 상대적으로 느리다.
- 다중 상속이나 타입에 엄격하며, 제약이 많다
JVM의 역할
- JVM은 스택 기반으로 동작하며, Java Byte Code를 OS에 맞게 해석 해주는 역할을 하고 가비지컬렉션을 통해 자동적인 메모리 관리를 해줍니다.
Java의 컴파일 과정에 대한 설명
- 개발자가 .java 파일을 생성
- build 한다
- Java Compiler의 javac의 명령어를 통해 바이트코드(.class)를 생성한다
- Class Loader를 통해 JVM 메모리 내로 로드한다.
- 실행엔진을 통해 컴퓨터가 읽을 수 있는 기계어로 해석된다.(각 운영체제에 맞는 기계어)
https://lavender1122.tistory.com/296
Java에서 제공하는 원시 타입들에 무엇이 있고, 각각 몇 바이트를 차지
- 정수형 byte, short, int, long 1,2,4,8 바이트
- 실수형 float, double 4, 8 바이트
- 문자형 char 2바이트
- 논리형 boolean 1바이트
오버라이딩(Overriding)과 오버로딩(Overloading)에 대해 설명
- 오버라이딩은 상위클래스에 있는 메소드를 하위 클래스에서 재정의하는것
- 오버로딩은 매개변수의 개수나 타입을 다르게 하여 같은 이름의 메소드를 여러 개 정의하는 것
객체지향 프로그래밍(OOP)에 대해 설명
- 우리가 실생활에서 쓰는 모든 것을 객체라 하며, 객체지향 프로그래밍은 프로그램 구현에 필요한 객체를 파악하고 상태와 행위를 가진 객체를 만들고 각각의 객체들의 역할이 무엇이지를 정의하여 객체들 간의 상호작용을 통해 프로그램을 만드는 것을 말합니다.
- 즉, 기능이 아닌 객체가 중심이며 "누가 어떤 일을 할 것인가?"가 핵심 특징으로는 캡슐화, 상속, 다형성, 추상화 등이 있고, 모듈 재사용으로 확장 및 유지보수가 용이
try-with-resources에 대한 설명
- try-with-resources는 try-catch-finally의 문제점을 보완하기 위해 나온 개념
- try(...) 안에 자원 객체를 전달하면, try블록이 끝나고 자동으로 자원 해제 해주는 기능을 말합니다.
- 따로 finally 구문이나 모든 catch 구문에 종료 처리를 하지 않아도 되는 장점이 있습니다.
불변 객체가 무엇이지 설명하고 대표적인 Java의 예시 설명
- 불변 객체는 객체 생성 이후 내부의 상태가 변하지 않는 객체
- Java에서는 필드가 원시 타입인 경우 final 키워드를 사용해 불변 객체를 만들 수 있고,
- 참조 타입일 경우 추가적인 작업이 필요합니다.
참조 타입일 경우 추가적인 작업은 어떤게 있는지 설명
- 참조 타입은 대표적으로 1.객체를 참조할 수 있고, 2. 배열이나 3. List 등을 참조 할 수 있습니다.
1. 참조 변수가 일반 객체인 경우 객체를 사용하는 필드의 참조 변수도 불변 객체로 변경해야 합니다.
2. 배열일 경우 배열을 받아 copy해서 저장하고, getter를 clone으로 반환하도록 하면 됩니다.(배열을 그대로 참조하거나, 반환할 경우 외부에서 내부 값을 변경할 수 있음. 때문에 clone을 반환해 외부에서 값 변경하지 못하게 함)
3. 리스트인 경우에도 배열과 마찬가지로 생성시 새로운 List를 만들어 값을 복사하도록 해야 합니다.
배열과 리스트는 내부 복사하여 전달하는데, 이를 방어적 복사(defensive-cope)라고 합니다.
불변 객체나 final을 굳이 사용해야 하는 이유
불변 객체나 final 키워드를 사용해 얻는 이점
1. Thread-Safe 하여 병렬 프로그래밍에 유용하며, 동기화를 고려하지 않아도 된다.
(공유 자원이 불변이기 때문에 항상 동일한 값 반환)
2. 실패 원자적인 메소드를 만들 수 있다.
(어떠한 예외가 발생되더라도 메소드 호출 전의 상태를 유지할 수 있어 예외 발생 전과 똑같은 상태로 다음 로직 처리 가능)
3. 부수효과를 피해 오류를 최소화 할 수 있다
※부수효과 : 변수의 값이 바뀌거나 객체의 필드 값을 설정하거나 예외나 오류가 발생하여 실행이 중단되는 현상
4. 메소드 호출 시 파라미터 값이 변하지 않는다는 것을 보장할 수 있다.
5. 가비지 컬렉션 성능을 높일 수 있다.
(가비지 컬렉터가 스캔하는 개체의 수가 줄기 때문에 GC 수행 시 지연시간도 줄어든다.)
추상 클래스와 인터페이스를 설명 & 차이
- 추상 클래스는 클래스 내 추상 메소드가 하나 이상 포함되거나 abstract로 정의된 경우
- 인터페이스는 모든 메소드가 추상 메소드로만 이루어져 있는것을 말합니다./확장 관련(implements)
공통점
- new 연산자로 인스턴스 생성 불가능
- 사용하기 위해서는 하위 클래스에서 확장/구현 해야한다
차이점
- 인터페이스는 그 인터페이스를 구현하는 모든 클래스에 대해 특정한 메소드가 반드시 존재하도록 강제함에 있고,
- 추상클래스는 상속받은 클래스들의 공통적인 로직을 추상화 시키고, 기능 확장을 위해 사용한다.
- 추상클래스는 다중상속이 불가능하지만, 인터페이스는 다중상속이 가능하다
https://lavender1122.tistory.com/80
싱글톤 패턴
- 싱글톤 패턴은 단 하나의 인스턴스를 생성해 사용하는 디자인 패턴
- 인스턴스가 1개만 존재해야 한다는 것을 보장하고 싶은 경우와 동일한 인스턴스를 자주 생성해야 하는 경우에 주로 사용합니다.(메모리 낭비 방지)
- 싱글톤 패턴의 대표적인 예시는 Spring Bean 입니다.
- 스프링의 빈 등록 방식은 기본적으로 싱글톤 스코프이고, 스프링 컨테이너는 모든 빈들을 싱글톤으로 관리합니다.
- 스프링은 요청할 때마다 새로운 객체를 생성해서 반환하는 기능도 제공(프로토타입 빈, @Scope("prototype"))
가비지 컬렉션(Garbage Collection)에 대해 설명
- 가비지 컬렉션은 JVM의 메모리 관리 기법 중 하나로 시스템에서 동적으로 할당됐던 메모리 영역 중에서 필요없어진 메모리 영역을 회수하여 메모리를 관리해 주는 기법
가비지 컬렉션 과정 설명
- GC의 작업을 수행하기 위해 JVM이 어플리케이션의 실행을 잠시 멈추고, GC를 실행하는 쓰레드를 제외한 모든 쓰레드들의 작업을 중단 후 (Stop The World 과정) 사용하지 않는 메모리를 제거(Mark and Sweep 과정)하고 작업이 재개
- GC의 작업은 Young 영역에 대한 Minor GC와 Old 영역에 대한 Major GC로 구분
객체지향의 설계원칙
- SPR (단일 책임 원칙) : 한 클래스는 하나의 책임만 가져야 한다.
- OCP (개방-폐쇄 원칙) : 확장에는 열려있고, 수정에는 닫혀있어야 한다.
- LSP (리스코프 치환 원칙) : 하위 타입은 항상 상위 타입을 대체 할 수 있어야 한다.
- ISP (인터페이스 분리 원칙) : 인터페이스 내에 메소드는 최소한 일수록 좋다.(하나의 일반적인 인터페이스보다 여러 개의 구체적인 인터페이스가 낫다.)
SRP와 같은 문제에 대한 두가지 다른 해결책이다. - DIP (의존관계 역전 원칙) : 구체적인 클래스보다 상위 클래스, 인터페이스, 추상 클래스와 같이 변하지 않을 가능성이 높은 클래스와 관계를 맺어라.
DIP 원칙을 따르는 가장 인기있는 방법은 의존성 주입(DI)이다.
자바의 메모리 영역
- 자바의 메모리 공간은 크게 Method 영역, Stack 영역, Heap 영역으로 구분되고, 데이터 타입에 따라 할당
- 메소드(Method) 영역 : 전역변수와 static 변수를 저장하며, Method영역은 프로그램의 시작부터 종료까지 메모리에 남아있다.
- 스택(Stack) 영역 : 지역변수와 매개변수 데이터 값이 저장되는 공간이며, 메소드가 호출될 때 메모리에 할당되고 종료되면 메모리가 해제된다.
LIFO(Last In First Out) 구조를 갖고 변수에 새로운 데이터가 할당되면 이전 데이터는 지워진다. - 힙(Heap)영역 : new 키워드로 생성되는 객체(인스턴스), 배열 등의 Heap 영역에 저장되며, 가비지 컬렉션에 의해 메모리가 관리된다.
각 메모리 영역의 할당되는 시정 언제인가?
- Method 영역 : JVM이 동작해서 클래스가 로딩될 때 생성
- Stack 영역 : 메소드가 호출될 때 할당
- Heap 영역 : 런타임시 할당
https://lavender1122.tistory.com/295
클래스와 객체에 대해 설명
- 클래스는 객체를 만들어내기 위한 설계도 혹은 틀 이라고 할 수 있고, 객체를 생성하는데 사용합니다.
- 객체는 설계도(클래스)를 기반으로 생성되며, 자신의 고유 이름과 상태, 행동을 갖습니다.
- 여기서 상태는 필드(fields), 행동은 메소드(Method)라고 표현합니다.
- 객체에 메모리가 할당되어 실제로 활용되는 실체는 '인스턴스'라고 부릅니다.
https://lavender1122.tistory.com/307
생성자(Constructor)에 설명
- 생성자는 클래스와 같은 이름의 메소드로, 객체가 생성될 때 호출되는 메소드입니다.
- 명시적으로 생성자를 만들지 않아도 default로 만들어지며, 생성자는 파라미터를 다르게하여 오버로딩 할 수 있습니다.
Wrapper Class란 무엇이며, Boxing과 UnBoxing은 무엇인지 설명
- 기본 자료형(Primitive data type)에 대한 객체표현을 Wrapper class라고 합니다.
- 기본 자료형 → Wrapper class 변환하는 것을 Boxing 이라 하며,
- Wrapper class → 기본 자료형으로 변환하는 것을 UnBoxing 이라 합니다.
래퍼 클래스란?(Wrapper Class)
- 자바의 자료형은 크게 기본타입(primitive type)과 참조타입(reference type)으로 나누어진다.
- 대표적으로 기본타입 char, int, float, double, boolean, long, short 있고 참조 타입은 class, interface 등이 있는데 프로그래밍을 하다 보면 기본타입의 데이터를 객체로 표현해야 하는 경우가 종종 있다.
이럴 때에 기본 자료타입(primitive type)을 객체로 다르기 위해서 사용하는 클래스들을 래퍼 클래스(wrapper class)라고 한다. - 자바는 모든 기본타입(primitive type)값을 갖는 객체를 생성할 수 있다.
- 이런 객체를 포장객체라고 하는데 그 이유는 기본 타입의 값을 내부에 두고 포장하기 때문 이다.
- 래퍼 클래스로 감싸고 있는 기본 타입 값은 외부에서 변경할 수 없다. 만약 값을 변경하고 싶다면 새로운 포장 객체를 만들어야 한다.
래퍼 클래스 종류
기본 타입(primitive type) | 래퍼 클래스(wrapper class) |
byte | Byte |
char | Character |
int | Integer |
float | Float |
double | Double |
boolean | Boolean |
long | Long |
short | Short |
- 래퍼클래스는 java.lang 패키지에 포함되고 있고, char타입과 int 타입이 각각 Character와 Integer의 래퍼클래스를 가지고 있고 나머지는 기본 타입의 첫 글자를 대문자로 바꾼 이름을 가지고 있다.
primitive 자료형 - Wrapper클래스 관계
int | Integer |
primitive 자료형(long, float, double ...) | Wrapper 클래스(객체) |
산술 연산이 가능하다 | Unboxing을 하지 않으면 산술 연산이 불가능 하지만 null 값을 처리 할 수 있다. |
null로 초기화 할 수 없다 | null 값 처리가 용이하기 때문에 SQL과 연동할 경우 처리가 용이함 |
DB에서 자료형이 정수형이지만 null값이 필요한 경우 Integer 사용 |
박싱(Boxing)과 언박싱(UnBoxing)
public class Wrapper_Ex {
public static void main(String[] args){
Integer num = new Integer(17); //박싱
int n = num.intValue(); //언박싱
System.out.println(n);
}
}
Auto boxing / unboxing
- 자바에서는 모든 경우가 아니지만 대부분의 경우에 자동으로 boxing/unboxing 해준다
int i = 1;
Integer integer = i; //int -> Integer(Auto boxing)
int i2 = integer; //Integer -> int (Auto unboxing)
Synchronized에 대해 아는 대로 말해주세요
- 여러 개의 쓰레드가 한 개의 자원을 사용하고자 할 때 , 현재 데이터를 사용하고 있는 쓰레드를 제외하고 나머지 쓰레드들은 데이터에 접근할 수 없게 막는 개념입니다.
- 데이터의 thread-safe를 하기 위해 자바에서 Synchronized 키워드를 제공해 멀티 쓰레드 환경에서 쓰레드간 동기화를 시켜 데이터의 thread-safe를 보장합니다.
- Synchronized는 변수와 메소드에 사용해서 동기화 할 수 있으며, Synchronized 키워드를 남발하게 되면 오히려 프로그램의 성능저하를 일으킬 수 있습니다.
new String()과 리터럴("")의 차이에 대해 설명
- new String()은 new 키워드로 새로운 객체를 생성하기 때문에 Heap 메모리 영역에 저장되고,
- ""는 Heap 안에 있는 String Constant Pool 영역에 저장됩니다.
String, StringBuffer, StringBuilder의 차이를 설명
- String은 불변의 속성을 가지며, StringBuffer와 StringBuilder는 가변의 속성을 가집니다.
- StringBuffer는 동기화를 지원하여 멀티 쓰레드 환경에서 주로 사용
- StringBuilder는 동기화를 지원하지 않아 싱글 쓰레드 환경에서 주로 사용합니다.
String, StringBuffer, StringBuilder의 차이와 장단점
- Java에서 문자열을 다루는 대표적인 클래스 String, StringBuffer, StringBuilder가 있다.
- 알아보기에 앞서 이 클래스들의 공통점은 모두 다 String(문자열)을 저장하고 관리하는 클래스들이 라는 것이다.
- 연산이 많지 않을때는 위에 나열된 어떤 클래스를 사용하더라도 이슈가 발생할 가능성은 거의 없다
그러나 연산횟수가 많아지거나 멀티쓰레드, Race condition 등의 상황이 자주 발생한다면, 각 클래스의 특징을 이해하고 상황에 맞는 적절한 클래스를 사용해야 할 것이다.
String vs StringBuffer / StringBuilder
- String과 StringBuffer/StringBuilder 클래스의 가장 큰 차이점은 String은 불변(immutable)의 속성을 갖는다는 점이다.
- 아래의 예제에서 "hello" 값을 가지고 있던 String 클래스의 참조변수 str이 가리키는 곳에 저장된 "hello"에 "world" 문자열을 더해 "hello world"로 변경한 것으로 착각할 수 있다
String str = "hello"; //String str = new String("hello");
str =str + "world"; //[hello world]
- 하지만 기존에 "hello" 값이 들어가있던 str이 "hello world" 라는 값을 가지고 있는 새로운 메모리 영역을 가리키게 변경되고,
처음 선언했던 "hello"로 값이 할당 되어 있던 메모리 영역은 Garbage로 남아 있다가 GC(garbage collection)에 의해 사라지게 된다. - String 클래스는 불변하기 때문에 문자열을 수정하는 시점에 새로운 String 인스턴스가 생성된 것이다.
- 위에 같이 String은 불변성을 가지기 때문에 변하지 않는 문자열을 자주 읽어들일 경우 String을 사용하면 좋은 성능을 발휘한다.
그러나 문자열 추가, 수정, 삭제 등의 연산이 빈번하게 발생하는 경우 String 클래스를 사용하면 힙 메모리(Heap)에 많은 Garbage가 생성되어 힙 메모리 부족으로 성능에 치명적인 영향을 끼친다. - 이를 해결하기 위해 Java에서 가변(mutable)성을 가지는 StringBuffer / StringBuilder 클래스를 도입했다.
String 과는 반대로 StringBuffer / StringBuilder는 가변성을 가지기 때문에 .append() .delete() 등의 API를 이용하여 동일 객체 내에서 문자열을 변경하는 것이 가능하다. 따라서 문자열의 추가, 수정, 삭제가 빈번하게 발생할 경우라면 String 클래스가 아닌 StringBuffer / StringBuilder를 사용해야 한다.
StringBuffer sb = new StringBuffer("hello");
sb.append("world")
StringBuffer vs StringBuilder
- 동일한 API를 가지고 있는 StringBuffer와 StringBuilder의 차이점은 무엇일까?
- 가장 큰 차이점은 동기화의 유무로써 StringBuffer는 동기화 키워드를 지원하여 멀티쓰레드 환경에서 안전(thread-safe) 하다.
- 참고로 String도 불변성을 가지기 때문에 마찬가지로 멀티쓰레드 환경에서의 안전성(thread-safe)을 가지고 있다.
반대로 StringBuilder는 동기화를 지원하지 않기 때문에 멀티쓰레드 환경에서 사용하는 것은 적합하지 않지만 동기화를 고려하지 않는 만큼 단일쓰레드에서의 성능은 StringBuffer보다 뛰어나다.
결론
- 단순히 성능만 놓고 본다면 연산이 많은 경우 StringBuilder > StringBuffer >>> String 정도로 보면 된다.
하지만 각 클래스들은 성능 이슈 외에도 사용 편의성, 멀티 스레드 환경 등 여러가지 고려해야할 요인이 있으므로 아래와 같은 경우에 맞게 사용하면 될 것이다. - String : 문자열 연산이 적고 멀티쓰레드 환경일 경우
- StringBuffer : 문자열 연산이 많고 멀티쓰레드 환경일 경우
- StringBuilder : 문자열 연산이 많고 단일쓰레드 이거나 동기화를 고려하지 않아도 되는 경우
String | StringBuffer | StringBuilder | |
Storage | String pool | Heap | Heap |
Modifiable | No(immutable) | Yes(mutable) | Yes(mutable) |
Thread safe | Yes | Yes | No |
Synchronized | Yes | Yes | No |
Performance | Fast | Slow | Fast |
String 객체가 불변인 이유에 대해 아는대로 설명
- 캐싱 기능에 의한 메모리 절약과 속도 향상
- Java에서 String 객체들은 Heap의 String Pool 이라는 공간에 저장되는데, 참조하려는 문자열이 String Pool에 존재하는 경우 새로 생성하지 않고 Pool에 있는 객체를 사용하기 때문에 특정 문자열 값을 재사용하는 빈도가 높을 수록 상당한 향상을 기대할 수 있다.
- thread-safe
- String 객체는 불변이기 때문에 여러 쓰레드에서 동시에 특정 String 객체를 참조하더라도 안전하다.
- 보안기능
- 중요한 데이터를 문자열로 다루는 경우 강제로 해당 참조에 대한 문자열 값을 바꾸는 것이 불가능하기 때문에 보안에 유리하다.
접근 제한자(Access Modifier)에 대해 설명
- 변수 또는 메소드의 접근 범위를 설정해주기 위해서 사용하는 Java의 예약어를 의미하며, 총 4가지 종류있다
- public - 접근 제한이 없다(같은 프로젝트 내 어디서든 사용 가능)
- protected - 해당 패키지 내, 다른 패키지에서 상속받아 자손 클래스에서 접근 가능하다.
- (default) - 해당 패키지 내에서만 접근 가능
- private - 해당 클래스에서만 접근 가능
클래스 멤버 변수 초기화 순서에 대해 설명
- static 변수 선언부 : 클래스가 로드 될 때 변수가 제일 먼저 초기화된다
- 필드 변수 선언부 : 객체가 생성될 때 생성자 block 보다 앞서 초기화 된다.
- 생성자 block : 객체가 생성될 때 JVM이 내부적으로 locking(thread-safe 영역)
static에 대해 설명
- static 키워드를 사용한 변수나 메소드는 클래스가 메모리에 올라갈 때 자동으로 생성되며 클래스 로딩이 끝나면 바로 사용할 수 있습니다.
즉, 인스턴스(객체) 생성 없이 바로 사용 가능합니다. - 모든 객체가 메모리를 공유한다는 특징이 있고, GC 관리 영역 밖에 있기 때문에 프로그램이 종료될 떄 까지 메모리에 값이 유지된 채로 존재하게 됩니다.
static 변수와 static 메소드
- static은 고정된이란 의미를 가지고 있다.
- static 이라는 키워드를 사용하여 static변수와 static메소드를 만들 수 있는 데 다른말로 정적필드와 정적메소드라고도 하며, 이 둘을 합쳐 정적 멤버(=클래스 멤버)라고 한다.
- 정적필드와 정적메소드는 객체(인스턴스)에 소속된 멤버가 아니라 클래스에 고정된 멤버이기에 클래스 로더가 클래스를 로딩해서 메소드메모리 영역에 적재할 때 클래스별로 관리된다. 따라서 클래스의 로딩이 끝나는 즉시 바로 사용할 수 있다.
- 객체 생성을 하지 않고 클래스 변수 나 메소드를 호출하도록 하는 제어자
- static 키워드를 통해 생성된 정적멤버들은 Heap 영역이 아닌 Static 영역에 할당된다
- Static 영역에 할당된 메모리는 모든 객체가 공유하여 하나의 멤버를 어디서든지 참조할 수 있는 장점을 가지지만, Garbage Collector의 관리 영역 밖에 존재하기 때문에 프로그램이 종료될 때까지 메모리에 값이 유지된 채로 존재하게 된다.
그렇기에 static을 남발하게되면 성능에 악영향을 줄 수 있다.
static 변수
- 예를 들어 게시물의 좋아요를 누를때마다 좋아요 값을 증가시키는 LikeCount 기능을 구현한다는 가정
package study;
public class LikeCount {
int count; // static int count;
public LikeCount() {
this.count++;
System.out.println("좋아요 개수 :" + count);
}
public static void main() {
LikeCount lc1 = new LikeCount();
LikeCount lc2 = new LikeCount();
}
}
- 위의 예제를 먼저 보면, lc1, lc2 객체가 생성될 때 lc1의 count와 lc2의 count가 서로 다른 메모리를 할당 받게 된다.
좋아요 개수 :1
좋아요 개수 : 1
Procss finished with exit code 0
- 그러나 아래와 같이 static변수를 사용하면 두 객체가 생성될 때 lc1, lc2 객체는 하나의 메모리를 공유하게 되는 것이다.
package study;
public class LikeCount {
static int count;
public LikeCount() {
this.count++;
System.out.println("좋아요 개수 :" + count);
}
public static void main() {
LikeCount lc1 = new LikeCount();
LikeCount lc2 = new LikeCount();
}
}
좋아요 개수 :1
좋아요 개수 : 2
Procss finished with exit code 0
static 메소드
- static메소드는 객체의 생성 없이 호출이 가능하고, 객체에서는 호출이 불가능하다.
또한 static 메소드 안에서는 인스턴스 변수 접근이 불가능하다.
package study;
public class LikeCount {
int count;
public LikeCount() {
this.count++;
System.out.println("좋아요 개수 :" + count);
}
public static int getCount() {
return count;
}
public static void main() {
LikeCount lc1 = new LikeCount();
LikeCount lc2 = new LikeCount();
System.out.println("총 좋아요 개수 :" +LikeCount.getCount());
}
}
- 위와 같이 static 메소드 안에서 인스턴스 변수는 접근이 불가능 하다.
package study;
public class LikeCount {
static int count;
public LikeCount() {
this.count++;
System.out.println("좋아요 개수 :" + count);
}
public static int getCount() {
return count;
}
public static void main() {
LikeCount lc1 = new LikeCount();
LikeCount lc2 = new LikeCount();
System.out.println("총 좋아요 개수 :" +LikeCount.getCount());
}
}
static 메소드 안에서 static변수만 접근이 가능한 것을 볼 수 있다.
결론
1. 인스턴스에 공통적으로 사용해야 하는 것에 static을 붙인다.
- 인스턴스를 생성하면, 각 인스턴스들은 서로 다른 독립적인 메모리 할당받기 때문에 서로 다른 값을 유지한다.
- 경우에 따라 인스턴스들이 공통적인 값이 유지되어야 하는 경우에는 static을 붙인다.
2. static이 붙은 멤버변수는 인스턴스를 생성하지 않아도 사용 할 수 있다.
- static이 붙은 멤버변수(클래스변수)는 클래스가 메모리에 올라갈 때 이미 자동적으로 생성되기 때문이다.
3. static이 붙은 메소드(함수)에서 인스턴스 변수를 사용할 수 없다.
- static 메소드는 인스턴스 생성 없이 호출 가능한 반면, 인스턴스 변수는 인스턴스를 생성해야만 존재하기 때문에 static이 붙은 메소드를 호출 할 때 인스턴스가 생성되어 있을 수 도 아닐 수 도 있기 때문에 static이 붙은 메소드에서 인스턴스 변수의 사용을 허용하지 않는다.
- 반대로, 인스턴스 변수 메소드 에서 static이 붙은 멤버들을 사용하는 것은 가능(인스턴스변수가 존재한다는 것은 static 멤버들은 이미 메모리에 존재한다는 것을 의미하기 때문)
4. 메소드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다.
- 메소드 호출시간이 짧아지기 때문에 효율이 높아진다.
5. 클래스 설계시 static의 사용지침
- 클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지 해야하는 것이 있는지 보고 있다면 static을 붙여준다
- 작성한 메소드 중 인스턴스 변수를 사용하지 않는 메소드에 대해서 static을 붙일 것을 고려한다.
일반적으로 인스턴스변수와 관련된 작업을 하는 메소드는 인스턴스메소드(static X) 이고,
static변수(클래스변수)와 관련된 작업을 하는 메소드는 클래스메소드 (static O)이다.
static을 사용하는 이유에 대해 설명
- static은 자주 변하지 않는 값이나 공통으로 사용되는 값 같은 공용자원에 대한 접근에 있어서 매번 메모리에 로딩하거나 값을 읽어들이는 것보다 일종의 '전역변수'와 같은 개념을 통해 접근 하는 것이 비용도 줄이고 효율을 높일 수 있습니다.
- 인스턴스 생성 없이 바로 사용 가능하기 때문에 프로그램 내에서 공통으로 사용되는 데이터들을 관리 할 때 이용
Inner Class(내부 클래스)의 장점에 대해 설명
- 내부 클래스에서 외부 클래스의 멤버에 손쉽게 접근할 수 있다.
- 서로 관련 있는 클래스를 논리적으로 묶어서 표현함으로써, 캡슐화를 증가 시키고, 코드의 복잡성을 낮출 수 있다.
- 외부에서는 내부 클래스에 접근할 수 없으므로, 코드의 보안성을 높일 수 있다.
리플렉션(Reflection)이란 무엇인지 설명
- 리플렉션이란 구체적인 클래스 타입을 알지 못해도 그 클래스의 메소드, 타입, 변수들에 접근할 수 있도록 해주는 자바API 입니다.
리플렉션은 어떤 경우 사용되는지 설명
- 코드를 작성할 시점에는 어떤 타입의 클래스를 사용할지 모르지만, 런타임 시점에 지금 실행되는 있는 클래스를 가져와서 실행해야 하는 경우 사용됩니다.
- 프레임워크나 IDE에서 이런 동적인 바인딩을 이용한 기능을 제공합니다. interlliJ의 자동완성 기능, 스프링의 어노테이션이 리플렉션을 이용한 기능이라 할 수 있습니다.
Error와 Exception의 차이를 설명
- Error는 실행 중 일어날 수 있는 치명적 오류를 말합니다. 컴파일 시점에 체크할 수 없고, 오류가 발생하면 프로그램은 비정상 종료되며 예측 불가능한 UncheckedException에 속합니다.
- 반면, Exception은 Error보다 비교적 경미한 오류이며, try-catch를 이용해 프로그램의 비정상 종료를 막을 수 있습니다.
CheckedException과 UnCheckedException의 차이를 설명
- CheckedException은 실행하기 전에 예측 가능한 예외를 말하고, 반드시 예외 처리를 해야 합니다.
- 대표적인 Exception - IOException, ClassNotFoundException 등
- UnckeckedException은 실행하고 난 후에 알 수 있는 예외를 말하고, 따로 예외처리를 하지 않아도 됩니다.
- 대표적인 Exception - NullPointerException, ArrayIndexOutOfBoundException 등
- RuntimeException은 UnckeckedException을 상속한 클래스이고, RuntimeException이 아닌것은 CheckedException을 상속한 클래스 입니다.
Optional API에 대해 설명
- 개발할 때 가장 많이 발생하는 예외 중 하나가 NPE(NullPointerException)입니다.
- NPE를 피하려면 null 여부 검사를 필연적으로 하게 되는데 만약 null 검사를 해야하는 변수가 많은 경우 코드가 복잡해지고 번거롭습니다. 하지만 Java8부터 Optional<T>을 제공하여 null로 인한 예외가 발생하지 않도록 도와주고, Optional 클래스의 메소드를 통해 null을 컨트롤 할 수 있습니다.
컬렉션 프레임워크에 대해 설명
- 다수의 데이터를 쉽고 효과적으로 관리할 수 있는 표준화된 방법을 제공하는 클래스의 집합 의미
- 자바 컬렉션에는 List,Set,Map 인터페이스를 기준으로 여러 구현체가 존재하고, 이에 더해 Stack, Queue 인터페이스도 존재합니다.
List, Set, Map, Stack, Queue의 특징에 대해 설명
- List는 순서가 있는 데이터 집합, 데이터의 중복 허용
- 대표적인 구현체로는 ArrayList가 있고, 이는 Vector를 개선한 것 입니다. 이외에도 LinkedList등의 구현체가 있습니다.
- Vector, ArrayList, LinkedList, Stack, Queue
- Set은 순서가 없는 데이터의 집합이며, 데이터의 중복을 허용하지 않습니다.
- 대표적인 구현체로는 HashSet이 있고 ,순서를 보장하기 위해서는 LinkedHashSet을 사용합니다.(Map의 key-value 구조에서 key 대신 value가 들어가 value를 key로 하는 자료 구조)
- HashSet, LinkedHashSet, TreeSet
- Map은 키와 값이 한 쌍으로 이뤄져 있고, 키를 기준으로 중복을 허용하지 않으며, 순서가 없습니다.
key의 순서를 보장하기 위해서는 LinkedHashMap을 사용합니다.- HashMap, TreeMap, HashTable, Properties
- Stack 객체는 직접 new 키워드로 사용할 수 있으며, Queue 인터페이스는 LinkedList에 new키워드를 적용해 사용할 수 있습니다.
https://lavender1122.tistory.com/237
Set과 Map의 타입이 Wrapper Class가 아닌 Object를 받을 때 중복 검사는 어떻게 할건지 설명
- hashCode() 메소드를 오버라이딩하여 리턴된 해시코드 값이 같은지를 보고 해시코드 값이 다르다면 다른 객체로 판단하고, 해시코드 값이 같으면 equals() 메소드를 오버라이딩하여 다시 비교합니다. 이 두 개가 모두 맞으면 중복 객체입니다
Vector와 List의 차이 설명
- 벡터는 데이터 삽입시 원소를 밀어내지만 리스트는 노드를 연결만 하기 때문에, 삽입 삭제 부분에서 리스트가 시간복잡도의 우위를 가집니다.
- 벡터는 랜덤부분접근이 가능하지만 리스트는 더블링크드리스트(노드가 양쪽으로 연결)로 되어있기 때문에 랜덤 접근이 되지 않습니다. 검색적인 측면에서는 벡터가 우위에 있습니다.
- 벡터는 리스트와 달리 항상 동기화되는 장점이자 단점을 가지고 있습니다. 멀티 쓰레드 환경에서 안전하게 객체를 추가하고 삭제할 수 있지만, 단일 쓰레드 환경 일 때도 동기화를 하기 때문에 List보다 성능이 떨어집니다.
제너릭에 대해 설명, 왜 쓰는지
- 제네릭은 데이터의 타입을 하나로 지정하지 않고 사용할 때마다 범용적이고 포괄적으로 지정한다는 의미
- 제네릭 타입을 사용함으로써 잘못된 타입이 사용될 수 있는 문제를 컴파일 과정에서 제거할 수 있어 에러를 사전에 방지
final / finally / finalize 의 차이 설명
- final은 클래스, 메소드, 변수, 인자를 선언할 때 사용할 수 있으며, 한 번만 할당하고 싶을 때 사용
- final 변수는 한 번 초기화되면 그 이후에 변경할 수 없습니다.
- final 메소드는 다른 클래스가 이 클래스를 상속할 때 메소드 오버라이딩을 금지
- final 클래스는 다른 클래스에서 이 클래스를 상속할 수 없습니다.
- finally는 try-catch와 함께 사용되며, try-catch가 종료될 때 finally block이 항상 수행되기 때문에 마무리 해줘야 하는 작업이 존재하는 경웨 해당하는 코드를 작성해주는 코드 블록입니다.
- finalize는 Object 클래스에 정의되어 있는 메소드이며, GC에 의해 호출되는 메소드로 절대 호출해서는 안되는 메소드입니다. GC가 발생하는 시점이 불분명하기 때문에 해당 메소드가 실행된다는 보장이 없고, finalize() 메소드가 오버라이딩 되어 있으면 GC가 이루어질 때 바로 Garbage Collectiong 되지 않습니다. GC가 지연되면서 OOME(Out of Memory Exception)이 발생할 수 있기 때문에 finalize() 메소드를 오버라이딩하여 구현하는 것을 권장하지 않고 있습니다.
직렬화(Serialize)에 대해 설명
- 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 시스템에서도 사용할 수 있도록 바이트(byte)형태로 데이터 변환하는 기술
- 반대로 직렬화된 바이트 형태의 데이터를 다시 객체로 변환하는 과정을 '역직렬화'라고 합니다.
- (간단히) JVM의 메모리에 상주(힙 or 스택) 되어 있는 객체 데이터를 바이트 형태로 변환하는 기술
SerialVersionUID를 선언해야 하는 이유에 대해 설명
- JVM은 직렬화와 역직렬화를 하는 시점의 클래스에 대한 버전 번호를 부여하는데, 만약 그 시점에 클래스의 정의가 바뀌어 있다면 새로운 버전 번호를 할당하게 됩니다. 그래서 직렬화할 때의 버전 번호와 역직렬화를 할 때의 버전 번호가 다르며 역직렬화가 불가능하게 될 수 있기 때문에 이런 문제를 해결하기 위해 SerialVersionUID를 사용합니다.
- 만약 직렬화할 때 사용한 SerialVersionUID의 값과 역직렬화 하기 위해 사용했던 SVUID가 다르다면 InvalidClassException이 발생
equal() 메소드 와 == 차이점
- == 연산자는 비교하고자 하는 두개의 대상의 주소값을 비교
- String 클래스의 equals 메소드는 비교하고자 하는 두개의 대상의 값 자체를 비교
⇒String 이나 Wrapper 클래스 이용시 equals() 메소드를 사용하여 비교
https://lavender1122.tistory.com/344
출처
https://dev-coco.tistory.com/153
'이론 > ⭐' 카테고리의 다른 글
개발자 기술면접 질문 정리 - 네트워크 (5) | 2024.09.03 |
---|---|
개발자 기술면접 질문 정리 - 알고리즘 (0) | 2024.09.03 |
기술면접 질문 정리 - 자료구조 (6) | 2024.09.03 |
기술면접 질문 정리 - 백엔드 (2) | 2024.09.01 |
기술면접 질문 정리 - 데이터베이스 (2) | 2024.09.01 |