본문 바로가기
JAVA

자바 핵심 기본 내용

by khds 2021. 10. 17.

 
이 글은 'JAVA 프로그래밍 면접 이렇게 준비한다 - 노엘 마크엄(번역: 정원천)'을 보면서 자바에 대한 핵심적이고 기본적인 내용들을 간단하게 정리한 글이다. 
 
 

1. 원시 타입

Boolean, int, double 같은 각각의 기본 타입은 원시타입이라고 한다. JVM은 이들을 객체라고 알려진 참조 타입과는 다른 방식으로 다룬다. 그 이유는 원시 타입은 객체와 다르게 Null이 될 수 없기 때문이다.
int와 long타입의 변수를 컴파일러는 두 터입을 구분할 수 있어야 하기에 long 타입이면 뒤에 L을 붙여서 구분한다. float와 double 사이에서도 F, D로 구분한다.
char는 값의 범위가 유니코드 값이므로 0~65535까지이다.(unsigned)
하위 타입에서 상위 타입으로 바로 변환할 수 있지만 그 반대는 불가능하다.(ex. int에서 long으로 변경은 바로 가능, long에서 int로 변경하려면 (int)를 표시해준다)
 
 

2. Integer.MIN_VALUES 에 대응하는 양수가 없는 이유는?

short, int, long 타입의 2진수 값 저장소는 메모리에서 2의 보수 값을 사용한다. 양수에서 음수, 음수에서 양수로 변경하려면 NOT비트 연산을 적용한 후 1을 더한다. 예를 들어 1111 1111(-128)을 양수로 바꾼다고 해보자. NOT비트 연산을 적용하면 0000 0000이고 여기서 1을 더하면 0000 0001로 1이 나온다. 즉, 언더플로우가 발생한 것이다. 즉, 2의 보수 값으로 음수를 표현하기 때문에 Integer.MIN_VALUE에 해당하는 양수는 없는 것이고 Integer.MIn_VALUE 보다 작은 값이나 Integer.MAX_VALUE 보다 큰 값을 표현하기 위해서는 보다 상위 타입을 사용해야 하고 그렇지 않으면 언더플로우, 오버플로우가 발생할 것이다.
 
 

3. 자바에서 객체란 무엇인가?

객체는 상태와 행위가 있다고 생각하면 쉽다. 여러 변수들과 메서드들이 있기 때문이다. 
원시 타입을 제외하면 자바 언어의 다른 모든 변수들은 참조 타입이다. 이들은 객체로 더 잘 알려져 있다. 객체는 빈 객체를 의미하는 표현인 Null이 존재한다. 변수들이 Null로 표현될 수 있고 메서드도 Null을 반환할 수 있다. 하지만 Null 참조에 대한 메서드를 호출하면 NullPointerException 이 발생하며 에러가 날 것이다.(ex. String s는 null이지만 s.length( ) 호출)
객체는 참조 타입이기에 변수에 할당할 때 할당된 메모리 위치를 가리킨다는 것도 기억하자.
 
 

4. final 키워드

윈시 타입이나 참조 타입(객체)나 final로 지정하면 메모리 주소를 변경할 수 없게 된다.(처음 할당된 후 새롭게 할당이 불가능하다) 하지만 객체는 메모리 주소를 변경할 수 없다는 거지 내부에 변수들에 final이 아니라면 그 변수들은 변경할 수 있다.
 
 

5. 객체의 가시성 수정자는 어떻게 작동되는가?

가시성 수정자(visibility modifier)는 클래스의 캡슐화된 상태와 인스턴스 행동을 조정하는 메서드의 접근을 제어하는 역할을 한다.

  • private: 같은 클래스의 모든 인스턴스에서 접근 가능, 하위 클래스에서는 접근 불가능
  • <none>: 같은 패키지의 모든 클래스에서 접근 가능
  • protected: 모든 하위 클래스에서 접근 가능
  • public: 어디서든 접근 가능

 
 

6. 메서드와 변수에 사용되는 static(정적) 키워드의 역할은 무엇인가?

클래스 내부에 정의하지만 인스턴스에는 속하지 않는다. 이는 모든 인스턴스에 공통으로 적용된다는 것이고 특정 인스턴스보다는 클래스 이름을 통해 정적 메서드와 정적 변수에 접근한다. 즉, 인스턴스를 만들지 않고도 바로 접근이 가능하다. static이 붙은 변수나 메서드는 프로그램이 실행되면 바로 메모리에 올려지기에 인스턴스를 만들지 않아도 바로 접근할 수 있는 것이다.
 
 

7. 다형성과 상속

다형성과 상속은 객체지향 개발의 두가지 핵심 개념이다.
상속은 부모 클래스에서 클래스의 행동과 정의를 가져다 사용할 수 있게 해 준다. 새로운 클래스를 정의할 때 이전에 정의된 클래스에서 정의와 상태를 상속할 수 있고 새로운 행동을 추가하거나 새로운 타입에 대한 행동을 오버라이드 할 수 있다.
다형성은 부모클래스를 요청했을 때 하위 클래스를 대신 사용하는 것으로 생각할 수 있다.
하위 클래스 is -a 상위 클래스인 것이다.
 
 

8.  오버라이드

https://securityspecialist.tistory.com/41 를 참고
 
 

9. 배열

위에서 언급했다시피 원시 타입을 제외한 모든 변수들은 참조 타입이며 객체이다. 즉, 자바에서 배열은 객체이다. 이는 참조로 전달될 수 있다는 것을 의미한다.
 
 

10. String

JVM과 컴파일러는 특정 상황에서 특별한 방법으로 String 객체를 처리한다. String 객체 대부분은 원시 타입처럼 취급한다. 그러므로 String 리터럴(따옴표 사이에 있는 모든 문자들)을 생성할 때 new 키워드를 이용할 필요가 없다. 실제 컴파일할 때 String 리터럴은 Stirng 객체로 생성된다.
String은 불변 객체이다. 인스턴스로 표현되는 값은 절대 변경할 수 없다. 이러한 불변 객체는 스레드에 안전하다는 장점이 있다.
 
 

11. 인터닝

클래스가 JVM에 로드되면 모든 리터럴이 상수 풀(인턴 풀)에 위치하게 된다. 그리고 String 리터럴의 모든 반복은 풀 안의 같은 상수를 참조해서 이루어지는데, 이를 Stirng 인 터닝(interning)이라고 한다. 
인터닝은 이 풀 안에 있는 상수들이 JVM에서 실행되는 모든 클래스를 참조할 수 있게 한다. 
String 인턴 풀은 컴파일할 때 단지 String 리터럴을 가져오는 게 아니라 intern 메서드를 이용해 모든 String 인스턴스를 이 풀에 추가한다. 여러 반복되는 데이터가 읽혀질 때에는 인터닝하며 JVM의 메모리 내부에는 하나의 유일한 인스턴스만 존재할 것이다. equals 메서드도 같은 주소를 가리키는지 두 인스턴스를 비교하는 것이다. 
 
 

12. 제네릭

제네릭(Generic)은 클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정되는 것을 의미한다. 제네릭(generic, 일반적인) 타입인 것이다. 자료구조에서 매우 유용하게 사용된다.
우리가 자주 사용하는 HashMap, ArrayList, LinkedList 등이 제네릭 클래스이다.
제네릭 타입은 원시 타입은 될 수 없고 참조 타입만이 가능하기에 String, Integer, Double 같은 래퍼 타입이 주로 사용된다.
자세한 내용은 https://st-lab.tistory.com/153 를 참고하길 바란다.
 
 

13. 오토 박싱과 언박싱

오토 박싱은 int 타입을 Integer 타입으로 변경하거나 boolean 타입을 Boolean 타입으로 변경하는 것처럼 원시 타입을 참조 타입으로 자동 변경하는 것이다. 자바 5 이전에는 이를 new Integer(42) 나 Integer.valueOf(42)처럼 수동으로 타입을 변경했어야 했는데 이 연산을 박싱이라고 한다.
언박싱은 반대로 Float, Integer, Boolean 같은 참조 타입을 자신들의 원시 타입인 float, int, boolean 타입으로 변경하는 것을 말한다. 언박싱도 컴파일러에서 제공하는 연산이다.
컴파일러는 참조 타입을 원시 타입으로 변경할 때 Null 값이 아니라고 생각하기에 만약 참조 타입이 Null 값이면 NullPointerException 이 발생할 수 있다.
 
 

14. 자바의 예외 처리 구조를 이루는 주요 클래스

 
 

출처:&nbsp;http://esanglee.blogspot.com/2016/05/exception-handling.html

 
모든 클래스는 Throwable 클래스를 확장해서 예외 처리를 할 수 있다.
Throwable는 Error와 Exception이라는 두 개의 하위 클래스를 갖는다. Exception은 프로그래머의 책임이지만 Error는 프로그래머 스스로 복구할 수 있는 게 아니다.
Exception은 Checked Exception(확인해야 하는 예외)과 Unchecked Exception(확인하지 않아도 되는 예외)으로 구분할 수 있다.
이에 대한 자세한 설명은 https://madplay.github.io/post/java-checked-unchecked-exceptions 를 참고하길 바란다.
 
Checked Exception은 코드에서 무엇이 잘못되었는지 직접 확인해야 한다. 그렇기에 이 예외를 처리하는 메서드를 구현할 때에는 가능한 예외를 명시해 주어야 한다.
반드시 명시적으로 처리해야 하기 때문에 Checked Exception이라고 하며, try catch를 해서 에러를 잡든 throws를 통해서 호출한 메서드로 예외를 던져야 한다.
 
Unchecked Exception 은 런타임 예외라고도 하며 메서드에 예외를 정의하는 것이다 예외를 다시 처리하려고 try/catch/finally문을 사용하는 것은 모두 선택 사항이다.
 
API를 만들 때 런타임 예외로 할지 확인해야 하는 예외로 할지 결정해야 할 때는 런타임 예외를 많이 선호한다고 한다. 그 이유는 try/catch/finally문을 이용하면 간단한 메서드 호출에도 코드가 길어지고 유지보수가 어려워지기 때문이라고 한다.
 
연쇄 예외란 에러를 해결하기 위해 예외를 처리할 때는 해당 예외를 다시 처리하거나 다른 타입의 예외를 처리하는 경우가 있다. 이는 확인해야 하는 예외에서 런타임 예외로 방법을 변경하거나 예외를 기록하고 나서 다시 처리하는 경우가 있기 때문이다. 새 예외의 생성자에는 이전 예외에 대한 참조를 추가한다. 이렇게 하는 이유는 전혀 처리되지 않는 예외를 디버깅하는 데 이런 연쇄 예외가 매우 유용하기 때문이다. 그리서 콘솔에서 예외를 확인할 때 'caused by'라는 것으로 시작해 경로를 알려준다. 이 경로는 맨 처음 예외가 난 경로이다. 
https://thebook.io/006985/ch05/01/07-01/ 를 참고하길 바란다.
 
 
 
 
 

참고

JAVA 프로그래밍 면접 이렇게 준비한다 - 노엘 마크엄
https://securityspecialist.tistory.com/41

자바(JAVA) 상속 2 오버라이드(Override) & super 키워드

오버라이드(Override)란? 부모 클래스에 있는 메소드를 자식 클래스에서 재정의 하는 것입니다. 자식 클래스가 부모 클래스를 상속하여 자식에게 없는 메소드를 호출하면 부모클래스에 가서 해당

securityspecialist.tistory.com

https://st-lab.tistory.com/153 

자바 [JAVA] - 제네릭(Generic)의 이해

정적언어(C, C++, C#, Java)을 다뤄보신 분이라면 제네릭(Generic)에 대해 잘 알지는 못하더라도 한 번쯤은 들어봤을 것이다. 특히 자료구조 같이 구조체를 직접 만들어 사용할 때 많이 쓰이기도 하고

st-lab.tistory.com

https://madplay.github.io/post/java-checked-unchecked-exceptions

자바 예외 구분: Checked Exception, Unchecked Exception

자바에서 예외는 어떻게 구분할까? Checked Exception과 Unchecked Exception의 차이는 무엇일까?

madplay.github.io

https://thebook.io/006985/ch05/01/07-01/

가장 빨리 만나는 코어 자바 9: 5.1.7 예외 다시 던지기와 예외 연쇄 - 1

thebook.io