스프링을 들어가기 전 마지막으로 자바 시험을 보았습니다.
괜찮다 싶은 문제들이 몇 개 있어 기록용으로 남겨두려합니다.
1. int[] arr[];
2. int[] arr = {1,2,3,};
3. int[] arr = new int[5];
4. int[] arr = new int[5]{1,2,3,4,5};
5. int arr[5];
6. int[] arr[] = new int[3][];
1번의 경우, 일반적인 배열 선언 방식이 아닙니다.
만약 제 팀원이 이런식으로 배열을 짰다면... 흠... 싶겠지만, 문법적으로 문제가 없습니다.
2차원 배열을 선언하는 방법 중 하나입니다.
2번의 경우 또한 일반적인 배열 선언 방식이 아닙니다.
초기화 부분에 , 이 있는데, 어떻게 잘못되지 않은거냐! 싶을 수 있지만,
자바 컴파일 시, javac이 해당 부분을 보고 컴파일 시 지워줍니다.
3번의 경우는 올바른 배열 선언 방식입니다.
크기가 5이고, 각 요소가 int의 디폴트값인 0으로 초기화된 배열이 생성됩니다.
4번의 경우 잘못된 배열 선언 및 초기화입니다.
int[] arr = new int[]{1,2,3,4,5}; 가 올바른 표현입니다.
5번의 경우 잘못된 배열 선언입니다. 크기를 지정하여 선언할 수 없습니다. int[] arr 으로 선언하면 됩니다.
6번의 경우 2차원 배열 선언 방법 중 하나입니다. 이해하기 쉽게 행렬로 설명하자면, 행의 크기를 3으로 초기화하고 열의 크기는 지정하지 않은 배열 선언 방식입니다.
public class test {
public static void main(String[] args) {
int i = 0;
for( ; i < 4; i += 2){
System.out.print(i + " ");
}
System.out.println(i);
}
}
0 2 4 입니다.public class test {
public static void main(String[] args) {
System.out.println(true+null);
}
}
+)은boolean 기본 자료형과 null 사이에는 정의되지 않기 때문입니다.The operator + is undefined for the argument type(s) boolean, null )public class CallTest{
static String str;
public static void main(String[] args){
System.out.println(str+'A'+'B'+true);
}
}
str은 static 변수라서, 클래스가 로딩될 때 메모리가 초기화됩니다.
명시적 초기화 및 static 초기화 블럭이 없기에, 참조형의 기본 값인 null로 초기화됩니다.
이러한 String 타입의 str에 'A' 를 더해주면, 비록 값이 null일지라도 타입 자체는 유지되기에, String 타입의 + 연산자가 호출됩니다.
String타입의 null에 char을 더하면, "null" 이라는 문자열과 "A"를 더한 "nullA"가 됩니다.
문자 'B'와의 합 또한 마찬가지로 적용되어, "nullAB" 가 됩니다. 이 또한 String 타입입니다.
String타입에 boolean 타입의 true 를 더해주면 해당 문자열에 "true" 라는 문자열이 붙습니다. 결과적으로 값이 "nullABtrue" 가 됩니다.
interface IfA {
public int MEM1 = 20;
public int var2;
public void display();
public int value(){return var2;}
}
인터페이스의 모든 멤버 변수에는 묵시적으로 public static final 의 제어자가 붙습니다.
인터페이스의 멤버 메서드에는 public abstract 의 제어자가 묵시적으로 붙습니다.
MEM1 과 같은 경우는, 인터페이스 상수로 final 제어자에 따라 초기화되어야 하고, 초기화가 잘 수행되었습니다.
var2는 인터페이스 상수이지만 초기화가 되지 않았기에 잘못되었습니다. 오류가 발생합니다.
display()는 추상 메서드로 선언이 잘 되었습니다. 구현체가 없고, 이를 상속받아 구현할 자식클래스를 위해 잘 정의된 것입니다.
value()는 추상 메서드여야하지만, 구현 부분이 존재합니다. 오류가 발생합니다.
cf. JDK 8버전 이후에 인터페이스의 메서드에 default 제어자를 붙일 수 있게 되었습니다. ( static 또한 마찬가지입니다 )
1. String 멤버변수는 "" 로 자동 초기화된다.
2. 지역변수는 반드시 초기화해야 한다.
3. 생성자보다 초기화 블럭이 먼저 수행된다.
4. 인스턴스변수보다 클래스변수가 먼저 초기화된다.
1번의 경우, String 타입의 멤버 변수는 명시적 초기화 / 초기화 블럭 / 생성자가 없을 시, null로 초기화됩니다.
지역변수는 메서드 내에 선언한 뒤, 반드시 명시적으로 초기화해주어야 합니다.
3번이 중요한 내용이었는데요. 인스턴스 생성 시 명시적 초기화 / 초기화 블럭 / 생성자의 호출 순서가 중요합니다. 이를 이해함으로써 스프링의 필드 주입, 생성자 주입이 이해하는 데 도움이 된다 생각합니다. 인스턴스 초기화 시, 명시적 초기화 -> 초기화 블럭 -> 생성자 순서로 호출됩니다.
클래스 변수가 인스턴스 변수보다 먼저 초기화됩니다.
인스턴스 생성 이전 해당 클래스를 static 영역 ( JDK 8 이후 PermGen 영역 )으로 클래스 로더가 올려놓기 때문입니다.
package com.kosta.lec;
public class ExceptionTest{
static void test() throws RuntimeException{
try {
System.out.println("test");
throw new RuntimeException();
} catch ( Exception ex ){
System.out.println("exception");
}
}
public static void main(String[] args){
try {
test();
} catch (RuntimeException ex){
System.out.println("runtime");
}
System.out.println("end");
}
}
test() 가 실행될 때, untimeException 날립니다. 이는, Exception의 자식 예외이므로, 메서드 내의 catch 문에서 핸들링 됩니다. ( "exception" 이 출력됩니다. )
물론, test() 메서드는 명시적으로 RuntimeException을 날리기에 외부에서 호출 시, catch 처리를 해주어야합니다만, 이미 test() 클래스 내부에서 핸들링을 해놨기에 main 문에서의 catch는 실행되지 않습니다.
test
exception
end
순으로 출력되게 됩니다.
void add(int a, int b) throws InvalidException, NotNumberException {}
class NumException extends Exception {}
class InvalidaException extends NumException {}
class NotNumException extends NumException {}
1. void add(int a, int b) throws InvalidException, NotNumException {}
2. void add(int a, int b) throws InvalidException {}
3. void add(int a, int b) throws NumException {}
4. void add(int a, int b) throws Exception {}
예외처리와 상속에 대해 물어본 문제였습니다.
부모 클래스의 메서드를 오버라이딩 하는 경우, 접근제어자는 같거나 더 넓은 범위로 ( protected로 상속받은 경우 protected 또는 public으로 변환만 가능 ) , 던지는 예외는 같거나 더 좁은 범위로만으로 설정할 수 있습니다.
이 때, 주의해야할 것이 있습니다. 던지는 예외의 범위는 던지는 예외의 개수가 아니라, 포함할 수 있는 예외의 종류 범위를 의미합니다.
즉, 3번의 경우, NumException 하나만을 던지지만, 이는 InvalidaException 과 NotNumException의 부모 예외이기에, 실상 더 넓은 범위의 예외를 던진 것이 됩니다.
따라서 답은 3번과 4번입니다.
package com.kosta.test;
@Getter
public class UserVO{
private int seq;
private String userId;
private String email;
}
package com.kosta.test;
public class CallTest{
public static void main(String[] args){
UserVO uvo = new UserVO();
System.out.println(uvo.getUserId() + " " + uvo.getEmail() + " " + uvo.getSeq());
}
}
처음에는 NPE 가 나오는 문제가 아닌가 생각했습니다.
정답은 null null 0 입니다.
멤버변수의 경우, 그 타입이 참조형이던, 기본형이던
명시적 초기화 / 초기화 블럭 / 생성자를 통해 초기화가 되지 않으면, 해당 타입의 기본 값으로 초기화 됩니다.
이로 인해 ORM을 사용할 때, NPE 문제도 생길 수 있다 하여, 이를 명시적 초기화로 일부러 String의 경우 ""로 명시적 초기화를 할 수도 있다 합니다.
처음 생각했을 때는 막연히 신기했지만, 이렇게 글을 정리하면서 느끼는 것은 class는 곧 사용자 정의 참조형이니 생성자를 통해 초기화될 때, Heap영역에서 기본 값으로 초기화되는 것이 당연하다는 생각이 들었습니다.