Strong Root

문제

출력결과는 무엇일까요?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.HashSet;
import java.util.Set;
 
public class Main {
 
    public static void main(String[] args) {
        Set<Set<Integer>> sets = new HashSet<>();
 
        Set<Integer> set1 = new HashSet<>();
        set1.add(1);
        set1.add(11);
        sets.add(set1);
 
        System.out.println(sets.size());
 
        set1.add(111);
        sets.remove(set1);
        System.out.println(sets.size());
    }
}
cs

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

정답

 

 

해설

HashSet.remove() 소스코드를 계속 따라가보면 HashMap.removeEntryForKey() 까지 이어지고,

여기서 코드를 잘보면 hashCode() 값 비교를 통해 remove를 시도하고 있습니다.

 

그런데 현재 Set 의 멤버도 Set 이므로 HashSet.hashCode() 를 살펴봐야합니다.

해당 소스코드를 보면 충격적이게도,

반복문을 돌며 멤버 전체의 hashCode() 를 더해 리턴하고 있습니다.

따라서 Set 의 내용물(멤버)이 바뀌면 hashCode() 값도 바뀌게 됩니다.

 

문제로 돌아가보면,

16라인에서 set1 의 내용물이 바뀜과 동시에 set1 의 hashCode() 값도 변해버려서

17라인에서 remove() 가 set1 을 찾지못해 지우는데 실패하게된 것입니다.

 


문제


출력 결과는 무엇일까요?


1
2
3
4
5
6
7
8
9
10
11
public class Person {
    public String name = "CGun";
    
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return 29;
    }
}
cs



1
2
3
4
5
6
7
public class Man extends Person {
    public String name = "CGun2";
 
    public int getAge() {
        return 30;
    }
}
cs



1
2
3
4
5
6
7
public class Test {
    public static void main(String[] args) {
        Man m = new Man();
        
        System.out.println(m.getName() + ", " + m.getAge());
    }
}
cs
















정답







해설


틀린 분 많으시죠?


상속시, 함수 오버라이딩은 많이들 아시겠지만 변수 오버라이딩에 대해서는 모르는 분이 많으실 겁니다.



변수는 오버라이딩되지 않습니다. (자식에 의해 덮어써지지 않고 계속 살아있습니다)


재미있는 결과를 더 알려드리겠습니다.



1
2
3
4
Man m = new Man();
 
System.out.println(m.name);    // CGun2
System.out.println(((Person) m).name);    // CGun
cs


3라인은 Man 의 name 값인 "CGun2" 가 출력되며,


4라인은 Person 의 name 값인 "CGun" 이 출력됩니다.



문제


출력 결과는 무엇일까요?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Test {
    public static void main(String[] args) {
        int[] arr = new int[2];
 
        try {
            arr[0= 0;
            System.out.println(arr[0]);
 
            arr[1= 1;
            System.out.println(arr[1]);
 
            arr[2= 2;
            System.out.println(arr[2]);
        }
        catch (NullPointerException e) {
            System.out.println(3);
        }
        catch (ArrayIndexOutOfBoundsException e) {
            System.out.println(4);
        }
        catch (Exception e) {
            System.out.println(5);
        }
        finally {
            System.out.println(6);
        }
 
        System.out.println(7);
    }
}
cs
















정답







해설


1. Exception 발생 즉시 try 문은 건너뛰고 catch 문으로 간다.


2. catch 가 여러개이면 맨 위부터 현재 Exception 을 잡아줄 수 있는지 체크하며,


   잡아줄 수 있는 최초의 catch 문만 수행하고 finally 로 간다.


3. finally 문이 있다면 수행 후 빠져나가고 프로그램은 아래로 계속 진행된다.



문제


출력 결과는 무엇일까요?


1
2
3
4
5
6
7
8
9
10
11
12
13
public class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public int getAge() {
        return age;
    }
}
cs



1
2
3
4
5
6
7
8
9
10
11
12
public class Test {
    public static void main(String[] args) {
        Person p1 = new Person("CGun"29);
        Person p2 = p1;
        
        p1.age = 30;
        p2.name = "CGun2";
        
        System.out.println(p1.name + ", " + p1.age);
        System.out.println(p2.name + ", " + p2.age);
    }
}
cs
















정답







해설


Person p2 = p1; 실행시에 일어나는 동작을 아는 것이 중요하다.


p1 객체를 복사하여 p2 에 할당하는 것이 아니라,


p1 객체와 같은 곳을 p2 가 가리키게 하는 구문이다.


즉,  reference 값만 복사된다는 뜻이며 결국 p1 과 p2 가 같은 객체를 가리키고 있다는 뜻이다.



문제


출력 결과는 무엇일까요?


1
2
3
4
5
6
7
8
9
10
11
12
13
public class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public int getAge() {
        return age;
    }
}
cs



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Test {
    static void increase(Person p, int weight) {
        p.age = 30;
        weight = 70;
    }
 
    public static void main(String[] args) {
        Person p = new Person("CGun"29);
        int weight = 60;
        
        increase(p, weight);
        
        System.out.println(p.age + ", " + weight);
    }
}
cs
















정답







해설


객체 변수는 Call by Reference 로 동작하므로 의도대로 값이 들어갔지만,


일반 변수는 Call by Value 로 동작하므로 increase 함수 내부 변수만 값이 증가하며

해당 함수가 종료되면 내부 변수는 증발한다.



문제


출력 결과는 무엇일까요?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Test {
 
    public static void main(String[] args) {
        String a = "CGun";
        String b = new String("CGun");
        String c = a;
        String d = b;
        
        a += " Good";
        b += " Good";
        
        System.out.println(c);
        System.out.println(d);
    }
}
cs











정답












해설


"java string immutable" 혹은 "java string 불변"


으로 검색해보시면 많은 정보를 얻으실 수 있습니다.



이유1: 객체 생성시 초기화 작업


일반 변수들의 경우, 생성자 없이 전역에서 바로 초기화를 해줘도 됩니다.


하지만 불가능해서 꼭 생성자에서 초기화를 해줘야하는 경우도 있습니다.


1
2
3
4
5
import java.io.FileInputStream;
 
public class FileHandler {
    private FileInputStream fis = new FileInputStream("\tmpFile");
}
cs


위 코드는 컴파일에러가 발생하며, 아래와 같이 수정해야 합니다.


1
2
3
4
5
6
7
8
9
10
import java.io.FileInputStream;
import java.io.FileNotFoundException;
 
public class FileHandler {
    private FileInputStream fis;
    
    public FileHandler() throws FileNotFoundException {
        fis = new FileInputStream("\tmpFile");
    }
}
cs


new FileInputStream() 에서 FileNotFoundException 을 throw 하므로 받아줘야 하기 때문입니다.











이유2: 객체 생성시 필수입력값을 강제하기


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Human {
    private String name;
    private String nickName;
    private int age;
    
    public Human(String name) {
        this.name = name;
    }
 
    public void setNickName(String nickName) {
        this.nickName = nickName;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
}
cs


사람 객체를 생성시 name 을 필수입력 항목으로 강제하는 코드입니다.


그외  nickName 과 age 는 원하는 경우에 한해 set 함수로 입력할 수 있습니다.



문제


출력 결과는 무엇일까요?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Test {
 
    public static void main(String[] args) {
        User a = new User("CGun"29);
        User b = new User("CGun"29);
        User c = a;
        
        System.out.println(a == b);
        System.out.println(a == c);
        System.out.println(a.equals(b));
    }
 
    public static class User {
        private String name;
        private int age;
        
        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
}
cs











정답







해설


위 소스코드를 자세히 보시면 User 클래스 안에 equals() 메서드가 없습니다.


근데 왜 컴파일 에러가 안날까요?



Java 에서 모든 클래스들은 기본적으로 Object 클래스를 상속받습니다.


extends Object 가 생략되었을 뿐입니다.


그리고 이 Object 클래스 안에 equals() 메서드가 존재하고 있으며, 소스코드는 아래와 같습니다.


네. 따라서 a.equals(b) 는  a == b 와 완전히 같습니다.


String.equals() 문제에 익숙한 분들을 향한 함정 문제였습니다.






참고


String.equals()







출처


GC - java.lang.Object

GC - java.lang.String