개요
*는 심화적인 내용이므로 처음 접한다면 넘어가도 좋다.
이번 포스팅에서 나오는 주요 키워드
- final 키워드
- static 키워드
- final과 static의 조합
- 예약어와 변수명
- snake case
- long 타입
- String 클래스와 불변성
- double 타입과 계산 정확도
- 객체 생성 및 메모리 할당
- Object 클래스 주요 메서드
- 기본 타입 & 참조 타입
- 지역 변수
- new 키워드와 객체 생성
- 묵시적 / 명시적 형 변환
- 조건문
본문
Q1. 왜 변수를 선언할 때 final을 쓰는가?
A1. final 키워드는 변수에 최초로 값을 할당한 이후에 다른 값을 할당할 수 없게 만든다.
이는 변수의 값이 변하지 않는다는 것을 명시적으로 표현하기 위함이다.
Q2. 변수를 선언할 때 static을 같이 쓰기도 한다. 왜 그런가?
A2. static 키워드는 클래스 변수를 선언할 때 사용한다.
클래스 변수는 클래스가 로딩될 때 생성되어 프로그램이 종료될 때까지 유지된다.
따라서 클래스 변수는 프로그램 전체에서 공유되는 변수이다.
Q3. final과 static을 같이 쓰는 경우의 장점은 무엇인가?
A3. final과 static을 같이 쓰면 프로그램 전체에서 공유되는 상수를 선언할 수 있다. final은 값 변경을 방지하고, static은 메모리를 효율적으로 사용하도록 한다.
추후에 안정성이나 재사용성을 늘려준다.
둘이 같이 쓴 변수 = 이 클래스 뿐만 아니라 다른 곳에서도 사용되는구나라고 팀원들이 명시적으로 이해할수 있다.
Q4. 예약어를 변수명으로 사용 시 오류가 발생하는 이유와 오류 메시지는 무엇인가?
A4. 예약어를 변수명으로 사용하면 컴파일러가 예약어를 변수명으로 사용하는 것을 인식하지 못하고 오류를 발생시킨다.
오류 메세지는 "Syntax error on token '예약어', invalid VariableDeclaratorId"이다.
Q5. 왜 DB에서는 snake case를 사용하는가?
A5. snake case는 단어 사이에 언더바(_)를 사용하여 변수명을 작성하는 방식이다.
DB에서는 snake case를 사용하는 이유는 일반적으로 DBMS에서 대소문자를 구분하지 않기 때문이다.
이는 성능과 관습적인 이유에서 사용된다.
Q6. long 형은 너무 범위가 크지 않나요? 실제로 언제 사용하나요?
A6.
1. 은행/결제 시스템이나 게임 서버에서 큰 수를 다룰 때 사용된다.
*2. 스프링 JPA에서 엔티티의 ID는 일반적으로 DB의 Primary Key와 매핑되며, BIGINT와 호환성을 고려해 long을 사용한다.
3. int로 선언 후 long으로 변경해야 하는 상황을 예방하기 위해 넉넉하게 long으로 선언하는 것이 유리하다.
Q7. String 내부를 보면 char 배열로 구성되어 있는데 왜 char 배열로 구성되어 있나요?
A7. String은 불변(immutable) 클래스이다.
char 배열은 불변이 아니므로 String은 안전한 데이터를 제공하기 위해 char 배열을 복사하여 내부적으로 사용한다.
String 객체는 toCharArray() 라는 메서드 또한 내장 하고 있다. 추후에 알고리즘 풀이시에도 자주 응용된다.
Q8. String은 왜 불변 클래스로 만들었나요?
A8.
1. 문자열 풀(String Pool)을 통해 메모리를 절약한다.
2. 멀티스레드 환경에서 안전성을 보장한다.
3. 보안성을 제공한다.
*https://deveric.tistory.com/123
Q9. double 타입으로 변수를 선언하고 0.1 + 0.2를 출력하면 왜 0.30000000000000004가 나오나요?
A9. double은 2진수로 표현되기 때문에 10진수로 정확하게 표현할 수 없는 숫자가 있다.
이를 이진 부동소수점 연산의 부정확성 문제라고 한다.
예를 들어, 0.1은 2진수로 정확히 나타낼 수 없으므로 미세한 오차가 발생한다.
Q10. 그럼 어떻게 해결하나요?
A10. BigDecimal 클래스를 사용하거나, 계산 중 정수를 사용하여(10진수를 흉내) 오차를 줄일 수 있다.
예: double result = (0.1 * 10 + 0.2 * 10) / 10;
왜 BigDecimal 은 가능할까?
- intVal: BigInteger 형태로 10진수 숫자를 표현
- scale: 소수점의 위치를 나타내는 정수로, 10진수 기준으로 사용,
예를 들어, 123.45는 intVal = 12345와 scale = 2로 표현 - precision: 전체 자릿수를 나타낸다. 성능 최적화를 위해 캐시로 사용(transient 로 Serialize 제외)
* Q11. new를 통해 객체를 생성하면 어떤 일이 일어나나요?
A11. new 키워드를 사용하면 Heap 메모리에 객체를 생성하고, 생성자가 호출되어 객체를 초기화한다.
생성된 객체의 참조값은 참조 변수에 저장된다.
Q12. 객체를 printf로 출력하면 나오는 문자열은 무엇인가요?
A12. 객체의 toString()
메서드가 호출된다. 기본적으로 클래스 이름과 해시코드를 반환한다.
Q13. toString() 메서드는 무엇인가요?
A13. toString() 메서드는 객체의 문자열 표현을 반환하며, Object 클래스에 정의되어 있다. 오버라이딩을 통해 사용자 정의 문자열을 반환할 수 있다.
Q14. toString() 이외에도 Object 클래스에 있는 필수 메서드는 무엇이 있나요?
A14. 주요 메서드:
1. equals() - 객체 비교
2. hashCode() - 해시코드 반환
3. clone() - 객체 복제
4. finalize() - 객체 소멸 시 호출
5. notify(), notifyAll(), wait() - 스레드 관리
Q15. 객체를 비교할 때 equals()를 사용하는 이유는 무엇인가요?
A15. equals()는 객체의 동등성을 비교한다. 오버라이딩하여 원하는 비교 조건을 정의할 수 있다.
Q16. hashCode()를 사용하는 이유는 무엇인가요?
A16. hashCode()는 객체의 고유 해시코드를 반환하며, 해시 기반 컬렉션 (HashMap, HashSet)에서 객체를 효율적으로 관리하기 위해 사용된다.
Q17. 기본 타입과 참조 타입에서 변수 변경 시에 결과값이 다르게 나오는 이유는 무엇인가요?
A17. 기본 타입은 변수에 값을 저장하고 참조 타입은 변수에 객체의 주소를 저장한다.
기본 타입은 변수에 값을 저장하기 때문에 변수의 값이 변경되어도 다른 변수에 영향을 주지 않는다.
참조 타입은 변수에 객체의 주소를 저장하기 때문에 변수의 값이 변경되면 다른 변수에 영향을 줄 수 있다.
Q18. 기본 타입의 변수가 메서드 내에서 변화하면 외부에서도 변화하지 않는 이유는 특성과 함께 설명해주세요.
A18. 기본 타입은 변수에 값을 저장하기 때문에 변수의 값이 변경되어도 다른 변수에 영향을 주지 않는다.
기본 타입은 스택(stack) 메모리에 저장된다.
*스택 메모리는 메서드가 호출될 때 생성되고 메서드가 종료될 때 소멸된다. 따라서 메서드 내에서 변수의 값이 변경되어도 외부에서는 영향을 받지 않는다.
Q19. 참조 타입의 변수가 메서드 내에서 변화하면 외부에서도 변화하는 이유는 특성과 함께 설명해주세요.
A19. 참조 타입은 변수에 객체의 주소를 저장하기 때문에 변수의 값이 변경되면 다른 변수에 영향을 줄 수 있다.
참조 타입은 힙(heap) 메모리에 저장된다.
*힙 메모리는 객체가 생성될 때 생성되고 객체가 소멸될 때 소멸된다.
따라서 메서드 내에서 변수의 값이 변경되면 외부에서도 영향을 받을 수 있다.
Q20. 객체를 생성할 때 new 키워드를 사용하는 이유는 무엇인가요?
A20. new 키워드를 사용하여 객체를 생성하면 메모리(heap)에 객체를 생성하고 객체의 주소를 반환한다.
객체의 생성자가 호출되어 객체의 초기화를 수행한다.
생성된 객체의 주소를 참조변수에 저장하여 객체를 사용할 수 있다.
Q21. 객체를 생성할 때 클래스를 사용하는 이유는 무엇인가요?
A21. 클래스는 객체를 생성하기 위한 틀이다. 클래스를 사용하여 객체를 생성하면 객체의 초기화를 수행할 수 있다.
Q22. 묵시적 형변환이 가능한 이유가 무엇인가요?
A22. 묵시적 형변환은 작은 크기의 데이터 타입에서 큰 크기의 데이터 타입으로 자동으로 형변환하는 것을 말한다.
묵시적 형변환은 데이터 손실이 발생하지 않기 때문에 자동으로 형변환할 수 있다.
Q23. 명시적 형변환이 가능한 이유가 무엇인가요?
A23. 명시적 형변환은 큰 크기의 데이터 타입에서 작은 크기의 데이터 타입으로 형변환하는 것을 말한다.
명시적 형변환은 데이터 손실이 발생할 수 있기 때문에 명시적으로 형변환해야 한다.
Q24. Scanner 클래스를 사용할 때 close()를 사용하는 이유는 무엇인가요?
A24. Scanner 클래스는 사용이 끝나면 close() 메서드를 호출하여 리소스를 반환해야 한다.
*close() 메서드를 호출하지 않으면 리소스 누수가 발생할 수 있다.
Q25. Scanner 클래스가 편리한 이유는 무엇인가요? 예외처리에 관련해서 답변해주세요.
A25. Scanner 클래스는 표준 입력 스트림(System.in)에서 데이터를 읽을 수 있는 클래스이다.
Scanner 클래스는 다양한 데이터 타입을 읽을 수 있어서 편리하다.
또한 예외처리를 자동으로 처리하기 때문에 사용자가 예외처리를 직접 작성할 필요가 없다.
Q26. switch-case 문과 if-else 문의 성능상 차이를 특성을 통해 설명해주세요. (조건문을 계산하는 시점을 고려해서)
A26. switch-case 문은 조건식을 계산한 결과에 따라 case 문을 실행한다.
switch-case 문은 조건식을 한 번만 계산하기 때문에 if-else 문보다 성능이 좋다.
if-else 문은 조건식을 계산할 때마다 조건식을 계산하기 때문에 switch-case 문보다 성능이 떨어진다.
Q27. for 문의 동작 순서에 대해서 설명해주세요.
A27. for 문의 동작 순서는 다음과 같다:
1. 초기화식 실행 → 2. 조건식 평가 → 3. 블록 실행 → 4. 증감식 실행. 조건식이 false가 될 때까지 이 과정을 반복한다.
출처 & 추가로 알아보면 좋은 것
- Effective Java (Joshua Bloch): Java 개발의 모범 사례.
- Java Language Specification: Java 문법 및 동작 원리 공식 문서.
- Java Memory Model and Garbage Collection: 메모리 구조 및 GC 동작 방식.
- Java Type Casting Documentation: 형변환 공식 자료.
- Oracle Java Tutorials: Java 입출력 및 클래스 설계.
- Java Performance Tuning: 조건문과 반복문 최적화.
- Head First Java: Java 객체지향 및 기본 문법 이해.
'Java' 카테고리의 다른 글
예제로 배우는 자바 String Pool 이해하기 (0) | 2025.01.20 |
---|---|
Java 조각모음 [2] (0) | 2025.01.17 |
ArrayList/LinkedList 단순 순회시 For, Enhanced For , Iterator, ListIterator, Stream.forEach() 성능비교 (1) | 2024.08.27 |
자바 가비지 컬렉터(GC)의 발전; 시리얼 컬렉터부터 ZGC까지 (0) | 2024.07.20 |
자바가상머신의 메모리 구조: JVM Runtime Data Area (0) | 2024.07.04 |