
자바의 신 : VOL.1 기초 문법편 3판 총정리, Chapter 7 ~ 13Java 에서의 배열 Java 는 완전한 객체지향 언어를 목표로 설계되었다. 그래서 Java 의 다차원 배열 은 정말로 배열의 배열 이다. 배열의 배열 이기 때문에 아주 간편히 ragged array 를 만들 수 있다.
배열과 같은 객체가 print 될 때 어떻게 보여질까?Enhanced for loop JDK 5 부터 Java 에도 Enhanced for loop 를 사용할 수 있다. 쉽게 말해 Python 에서의 for 문 마냥 사용할 수 있다는 것이다.
생성자생성자란 어느 클래스 타입의 객체가 생성될 시, 객체의 필드 등의 초기화를 위한 메서드의 일종이다.
Java 의 기본 생성자는 오직 compiler 에 의해서 자동으로 만들어지는 생성자이다. 기본 생성자는 클래스의 어떠한 생성자도 존재하지 않아야 생성되며, 이는 그냥 빈 생성자 형태이다.
클래스 변수 와 static block 클래스 변수 를 초기화 하는 방법 중 static block 을 이용하는 방법이 있다. 이 때 static block 은 해당 클래스 객체가 처음 사용될 때 단 한번만 실행되는 block 이다.
때문에 어느 클래스의 클래스 변수 가 존재할 시, 해당 클래스 타입의 객체가 다수 존재하더라도 statkc block 과 클래스 변수 는 단 한번만 초기화/실행 되고, 해당 타입의 모든 객체가 그 클래스 변수 를 공유한다.
Java 의 가변인자 Java 에서도 가변인자 를 사용해 메서드를 선언할 수 있다. 가변인자 는 Variable Arguments 또는 Arbitary Number of Arguments 로 불리며, 메서드 호출 시 필요한 인자의 숫자가 정해지지 않은 선언 방식을 말한다.
가변인자 는 배열 형식으로 주어진 매개변수 와 매우 유사하다. 하지만 그렇다고 배열 형식인 매개변수 에 가변인자 처럼 메서드에 넘겨주는 것은 가능하지 않다.
Java 의 package 와 import Java 의 package 는 그저 폴더 의 개념 보다는 C++ 의 namespace 에 좀더 가까운 개념이다. 분명히 package 를 이용해 소스를 모듈화 시킬 순 있지만 package-private 등과 같은 namespace 의 개념이 포함되어 있다.
package 는 소스의 최상단에 위치해야 하며, import 는 아래에 위치하여야 한다. 이를 지키지 않을 시 compile error 를 일으킨다.
더불어 Oracle Docs 에 Package Naming Convention 이 언급되어 있는데, 이는 다음과 같다.
package 이름은 소문자로 작성한다.
package 이름에 Java 예약어를 사용하지 않는다. (최소한 _ 라도 넣어라)
package 가 java 또는 javax 로 시작하지 않는다.
덧붙여 문서에는 나와있지 않지만, 영리 단체는 com 으로, 비영리 단체는 org 로 시작해 package 이름을 붙인다는 관용이 있다.
import Java 에서 import 키워드를 이용해 특정 package 속 특정 클래스, 또는 package 속에 포함된 모든 클래스를 가져올 수 있다.
덧붙여 JKD 1.5 이후 버전부터 import static 이 추가되었다. 이는 static 한 것들 (클래스 변수, static 메서드 등) 을 불러오고자 할 때 용이하다.
상속 과 메서드 Overriding Java 에도 당연히 상속 이 있고 Override 와 Overload 가 있다. 이 때 상속 은 extends 키워드를 이용해 진행할 수 있으며, implements 와 유사하지만 엄연히 다름에 유의해야 한다.
어느 클래스를 상속 받으면 C++ 에서와는 다르게 부모의 생성자가 자동으로 상속 되지 않는다. 상속 관계가 정해졌을 시, super 키워드를 이용해 부모 클래스의 메서드, 생성자 등에 접근할 수 있다.
부모 클래스의 메서드를 Override 할 시, 해당 메서드의 가시성 (Visibility) 는 제한될 수 없다.
메서드의 가시성 은 다음과 같은 순서를 갖는다. (내림차순)
public <-- package-private <-- protected <-- private
여기서 package-private 한 메서드는 각별한 주의가 필요하다. 왜냐하면 해당 메서드를 Override 하려해도 같은 package 가 아니라면 접근조차 안되기 때문이다.
상속 관계 클래스간 형 변환 과 Polymorphism 간략히 말하면 (자식 --> 부모) 로의 형변환은 가능하다. 반면 (부모 --> 자식) 으로의 형 변환은 될수도 있고 안될수도 있다.
(부모 --> 자식) 으로의 형변환을 진행하면 runtime error 를 발생시킬 수 있다.
이러한 형 변환은 Java 의 다형성 (Polymorphism) 을 보여주는 한 예시이다. Java 에는 이러한 서브타입 다향성 외에도 매개변수의 다향성, 임시 다향성 등이 존재한다.
final 키워드 만약 클래스에 final 키워드를 이용해 선언한다면, 해당 클래스는 더이상 상속될 수 없다.
마찬가지로 메서드에 final 키워드를 이용한다면, 해당 메서드는 더이상 Override 될 수 없다. (Overloading 은 가능하다)
java.lang.Object 의 메서드 Object 클래스는 Java 내 모든 클래스의 부모인 클래스이다. 해당 클래스에는 크게 2 종류의 메서드가 존재하고, 이는 다음과 같다.
객체 처리를 위한 메서드
Method | 설명 |
|---|---|
protected Object clone() | 객체의 복사본을 만들어 리턴한다. |
public boolean equals(Object obj) | 현재 객체와 매개 변수로 넘겨받은 객체가 같은지 확인한다. |
protected void finalize() | 현재 객체가 더 이상 쓸모 없어졌을 때, GC (Garbage Collector) 에 의해서 이 메서드가 호출된다. 하지만 여러 문제점 때문에 JDK 9 부터 Deprecated 되었다. |
public Class<?> getClass() | 현재 객체의 Class 클래스의 객체를 리턴한다. |
public int hashCode() | 객체에 대한 hash code 값을 리턴한다. 이 때 해쉬 코드는 "16 진수로 제공되는 객체의 메모리 주소" 를 말한다. |
public String toString() | 객체를 문자열로 표현하는 값을 리턴한다. |
스레드 처리를 위한 메서드
Method | 설명 |
|---|---|
public void notify() | 이 객체의 모니터에 대기하고 있는 단일 스레드를 깨운다. |
public void notifyAll() | 이 객체의 모니터에 대기하고 있는 모든 스레드를 깨운다. |
public void wait() | 다른 스레드가 현재 객체에 대한 notify() 메서드나 notifyAll() 메서드를 호출할 때까지, 현재 스레드가 대기하고 있도록 한다. |
public void wait(long timeout) | wait() 메서드와 동일한 기능을 제공하며, 매개 변수에 지정한 시간 만큼만 대기한다. 여기서 매개 변수 timeout 은 ms 단위이다. |
public void wait(long timeout, int nanos) | wait() 메서드와 동일한 기능을 제공한다. 해당 메서드는 timeout + nanos 시간 만큼 스레드를 대기시킨다. 이 때 timeout 은 ms 단위이고, nanos 는 ns 단위이다. |
비교 연산자 == 와 equals 메서드의 차이hashCode 와 System.identityHashCode 의 차이점추상화 Java 에서 abstract 는 "추상 클래스" (abstract classes) 또는 "추상 메서드" (abstract methods) 를 선언하기 위한 키워드이다.
이 때 "추상" 또는 "추상화" 란 "어느 시스템의 기반을 담당하는 과정 등을 일반화하고 뭉뚱그려, 더 효율적으로 수행하기 위한 방법론" 이다. Java 의 encapsulation 과 유사한 개념이라 생각할 수 있다.
이에 대한 대표적인 예시가 추상 메서드, interface, 그리고 추상 클래스 이다.
추상 메서드 와 interface 추상 메서드 란 선언만 되어있을 뿐 구현이 되어있지 않은 메서드를 말한다. interface 는 Java 에서 추상화 를 가능케하는 키워드 중 하나로, interface 는 추상 메서드 와 final, static 변수 들의 집합을 선언할 수 있다.
더불어 JDK 8 부터 interface 에 default, static method 를 선언할 수 있게 되었다. 이를 이용해 좀더 유연한 추상화 가 가능하다.
추상 클래스 추상 클래스 란 Java 에서 추상화를 가능케 하는 클래스로, interface 보다 더 유연한 추상화 가 가능하다.
추상 클래스 와 interface 의 차이점 추상 클래스 와 interface 는 유사한 점이 많다. 두 가지 모두 인스턴스화 할 수 없고, 추상 메서드 를 선언할 수도 안 할수도 있다. (interface - default method)
하지만 당연히 차이점이 존재하는데, 추상 클래스 는 static 또는 final 하지 않은 필드 를 선언할 수 있으며, public, protected, private 메서드를 만들어 사용할 수 있다.
반면 interface 의 경우, 선언한 필드는 모두 자동적으로 public static 또는 public final 이며, 선언한 메서드 또한 모두 public 이다.
덧붙여 추상 클래스 는 단 하나의 (클래스 이므로)추상 클래스 만 extend 할 수 있으며, interface 의 경우 다수의 interface 를 implement 할 수 있다.
위 설명을 정리하면 다음처럼 나타낼 수 있다.
구분 | abstract class | interface |
|---|---|---|
field | 뭐든지 가능 | public static, public final 만 가능 |
method | 뭐든지 가능 | public 메서드만 가능 (JDK 8 <= default, static method 가능) |
extend | 오직 1 개만 extend 가능 | (class 이므로) 불가능 |
implement | (interface 이므로) 불가능 | 여러개 implement 가능 |
열거형 클래스(?) Java 에도 열거형이 존재한다. 하지만 이는 C 의 것과는 아주 다르다. Java 는 객체지향 언어라 열거형 또한 클래스로 선언되어, enum 이 생성자, 메서드를 가질 수 있기 때문이다.
거기다 또 한가지 큰 차이점이 있는데, C 에서는 열거형 상수가 어느 정수로 정확히 대응될 수 있는 반면, Java 는 절대 그렇지 않고 열거형 상수 또한 어느 클래스 라는 것이다.
Enum 클래스 와 메서드 Java 의 모든 열거형은 java.lang.Enum 의 자식들이다. Enum 클래스 또한 java.lang.Object 의 자식이기 때문에, Object 의 메서드 또한 Override 되어있다.
그런데 이 중, 다음 4 가지는 더이상 Override 할 수 없게 선언되어 있다.
Method Declaration | Description |
|---|---|
protected final Object clone() | 객체를 복제하기 위한 메서드이지만 Enum 에서 사용할 경우 CloneNotSupportedException 를 발생시킨다. |
protected fianl void finalize() | GC 가 발생할 때 처리하기 위한 메서드, Deprecated |
fianl int hashCode() | enum 상수에 대한 hash code 를 반환하는 메서드 |
fianl boolean equals(Object other) | 주어진 객체가 상응하는 enum 상수인지 판별하는 메서드 |
이 외에도 다음과 같은 메서드가 추가로 선언되어 있다.
Method Declaration | Description |
|---|---|
final int compareTo(E e) | 메서드에 주어진 enum 타입의 매개변수 (e) 와의 순서 차이 (ordinal) 를 리턴한다. |
final Class<E> getDeclaringClass() | 해당 enum 상수의 클래스를 나타내는 객체를 반환한다. |
final String name() | 해당 enum 상수의 선언된 이름을 반환한다. |
final int ordinal() | 해당 enum 상수의 선언된 순서를 반환한다. |
static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) | 주어진 enumType 중 name 에 해당하는 enum 상수를 반환한다. static 메서드이므로 Enum.valueOf 로 접근해 사용할 수 있다. |
마지막으로 열거형 클래스에는 values() 라는 메서드가 존재하는데, 이는 미리 선언되거나 정의된 메서드가 아닌 compiler 에 의해 자동으로 추가되는 메서드이다.
때문에 values() 메서드의 선언은 절대 찾을 수 없다. 다만 다음 예시처럼 직접 작동하는 것을 확인할 수는 있다.
enum SomeEnum {
Zero, One, Two, Three
}
for (Object obj : SomeEnum.values()) {
System.out.println(obj + "\t" + obj.getClass());
}
Zero class SomeEnum
One class SomeEnum
Two class SomeEnum
Three class SomeEnum