Strong Root


문제


출력 결과는 무엇일까요?


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



프라미스 (Promise) 란


비동기적으로 결과를 리턴하는 함수에 대한 비동기 프로그래밍 패턴의 일종이다.


(※ 매우 중요한 개념이므로 필히 익히시기를 추천합니다.)






A부터 Z까지 Promises 의 모든 것


http://www.html5rocks.com/ko/tutorials/es6/promises/


너무도 완벽한 글을 찾아서 본문 없이 그냥 위 링크로 대체합니다.




한편, 퀄리티가 이 정도로 좋은 글을 쓰는 사람은 어떤 사람인지 궁금해서 찾아보았습니다.



네... 그렇습니다. 구글러네요.


전공적인 깊은 이해는 물론이고 글솜씨와 전개방식도 완벽합니다.


존경합니다.




 우리는 구형 브라우저가 HTML5 를 올바르게 다룰 수 있도록 지도할 수 있다. 심지어 Windows XP 2001 의 IE6 도 가능하다.







최종 해결책


1
2
3
<!--[if lt IE 9]>
  <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
cs


위 세 줄을 <head> 영역에 써주면 된다.









원리1. CSS 를 통한 대응


예를 들어 구형 브라우저 입장에서 Unknown Elements 인 HTML5 Elements 에 대하여 아래와 같이 대응할 수 있다.


1
2
3
header, section, footer, aside, nav, main, article, figure {
    display: block; 
}
cs






원리2. 새로운 사용자 정의 Element 추가하기


같은 원리로 새로운 Element 를 HTML 에 추가할 수도 있다:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html>
<head>
  <title>New element</title>
  <script>document.createElement("myHero")</script>
  <style>
  myHero {
      display:block;
      background-color:#ddd;
      padding: 50px;
      font-size: 30px;
  }  
  </style>
</head>
<body>
 
<myHero>My First Hero</myHero>
 
</body>
cs






원리3. 인터넷 익스플로러 (Internet Explorer) 의 문제점


위의 원리2 의 해결책을 통해 모든 HTML5 Elements 에 대응할 수 있지만,


IE8 이하에서는 unknown elements 에 대한 css 적용을 허용하지 않는 문제점이 있다.


이것까지 해결한 것이 "the shiv" 라는 js 파일이다:


1
2
3
<!--[if lt IE 9]>
  <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
cs


이 코드는 주석이지만 IE9 미만의 버전에서는 단순 주석이 아니라 실제 코드로써 동작한다.









출처


http://www.w3schools.com/html/html5_browsers.asp




프록시 (Proxy) 란


Proxy 의 사전적 의미는 "대행", "대리", "위임" 이다.


프록시 (Proxy) 는 객체에 수행되는 동작들 (예를들면 속성값 조회, 변경) 을 가로챌 수 있게 해주고, 커스터마이징도 할 수 있게 해주는 일종의 객체 감싸미다.


프록시는 세 요소로 구성된다:



 * 타겟 (target) : 프록시로 감쌀 대상 객체.


 * 핸들러 (handler) : 트랩 메서드들을 담고 있는 객체. 타겟에 대한 동작을 감지하여 그에 대응하는 트랩 메서드가 존재할 경우 해당 트랩 메서드를 호출한다.


 * 트랩 (trap) : 핸들러 안에 존재하는 메서드. 타겟 객체에 대한 동작을 가로채며, 사용자 정의 로직을 넣을 수 있다.





아래는 프록시를 적용한 예제 코드이다. 여기서는 트랩으로 get, deleteProperty 가 사용되었다.


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
var target = {a: 1};
 
var handler = {
  get: function(target, key) {
    // any custom logic
    console.log('GET: ' + key);
    return target[key];
  },
 
  deleteProperty: function(target, key) {
    // any custom logic
    console.log('DELETE: ' + key);
    return delete target[key];
  }
};
 
var proxiedTarget = new Proxy(target, handler);
 
console.log(proxiedTarget.a);
// GET: a
// 1
 
console.log(proxiedTarget.b);
// GET: b
// undefined
 
delete proxiedTarget.a;
// DELETE: a
cs











Reflect


ECMAScript 6 에서는 모든 트랩에 대하여 포워딩을 도와주는 Reflect 라는 객체가 추가되었다:



 handler.trap(target, arg_1, ···, arg_n)


 위와 같은 모든 trap 메서드에 대응하는


 Reflect.trap(target, arg_1, ···, arg_n)


 이 존재한다.





Reflect 를 이용한 포워딩 (Forwarding intercepted operations with Reflect):


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
var target = {a: 1};
 
var handler = {
  get: function(target, key) {
    // any custom logic
    console.log('GET: ' + key);
    return Reflect.get(target, key);
  },
 
  deleteProperty: function(target, key) {
    // any custom logic
    console.log('DELETE: ' + key);
    return Reflect.deleteProperty(target, key);
  }
};
 
var proxiedTarget = new Proxy(target, handler);
 
console.log(proxiedTarget.a);
// GET: a
// 1
 
console.log(proxiedTarget.b);
// GET: b
// undefined
 
delete proxiedTarget.a;
// DELETE: a
cs











Why Proxy? Proxy 의 강력한 활용


아래 코드를 이해하면 Proxy 의 강력함을 느낄 수 있다.


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
let normalObj = {name'CGun'};
let dfObj = makeDefensiveObject(normalObj);
 
/* [1] name */
console.log(dfObj.name);
// GET: name
// CGun
 
 
 
/* [2] marriage */
console.log(dfObj.marriage);
// GET: marriage
// Uncaught ReferenceError: marriage does not exist.
 
dfObj.marriage = 'x';
// SET: marriage, x
// Uncaught TypeError: marriage should be "기혼" or "미혼"
 
dfObj.marriage = '미혼';
// SET: marriage, 미혼
 
console.log(dfObj.marriage);
// GET: marriage
// 미혼
 
 
 
/* [3] age */
console.log(dfObj.age);
// GET: age
// Uncaught ReferenceError: age does not exist.
 
dfObj.age = 'x';
// SET: age, x
// Uncaught TypeError: The age is not an integer
 
dfObj.age = -30;
// SET: age, -30
// Uncaught RangeError: The age seems invalid
 
dfObj.age = 29;
// SET: age, 29
 
console.log(dfObj.age);
// GET: age
// 29
 
 
 
/* [4] grade */
console.log(dfObj.grade);
// GET: grade
// Uncaught ReferenceError: grade does not exist.
 
dfObj.grade = 80;
// SET: grade, 80
// Uncaught TypeError: grade should be "A" to "F"
 
dfObj.grade = 'b';
// SET: grade, b
 
console.log(dfObj.grade);
// GET: grade
// B
 
 
 
/* [5] Proxy */
function makeDefensiveObject(target) {
    if (target === undefined) {
        target = {};
    }
 
    let handler = {
        get: function(target, key) {
            console.log('GET: ' + key);
 
            if (!(key in target)) {
                throw new ReferenceError(key + ' does not exist.');
            }
 
            if (key == 'marriage') {
                return Reflect.get(target, key) === true ? '기혼' : '미혼';
            }
 
            return Reflect.get(target, key);
        },
        set: function(target, key, value) {
            console.log('SET: ' + key + ', ' + value);
 
            if (key == 'marriage') {
                if (value == '기혼') {
                    value = true;
                }
                else if (value == '미혼') {
                    value = false;
                }
                else {
                    throw new TypeError('marriage should be "기혼" or "미혼"');
                }
            }
 
            if (key == 'age') {
                if (!Number.isInteger(value)) {
                    throw new TypeError('The age is not an integer');
                }
                if (value < 0 || value > 150) {
                    throw new RangeError('The age seems invalid');
                }
            }
 
            if (key == 'grade') {
                if (!value || value.length != 1) {
                    throw new TypeError('grade should be "A" to "F"');
                }
 
                value = value.toUpperCase();
                if (value < 'A' || value > 'F') {
                    throw new RangeError('The grade seems invalid');
                }
            }
 
            return Reflect.set(target, key, value);
        }
    };
 
    return new Proxy(target, handler);
}
cs











Revocable proxy


ECMAScript 6 에서는 취소가 가능한 (스위치를 끌 수 있는) 프록시가 추가되었다:


1
var {proxy, revoke} = Proxy.revocable(target, handler);
cs




revoke 함수를 실행하고 나면 해당 proxy 가 취소되며, 사용하려고 하면 TypeError 가 발생한다:


1
2
3
4
5
6
7
8
9
10
var target = {}; // Start with an empty object
var handler = {}; // Don’t intercept anything
var {proxy, revoke} = Proxy.revocable(target, handler);
 
proxy.foo = 123;
console.log(proxy.foo); // 123
 
revoke();
 
console.log(proxy.foo); // TypeError: Revoked
cs











출처


http://exploringjs.com/es6/ch_proxies.html

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Proxy




  한 collection 에서 각각의 아이템을 순회하는 것은 매우 흔한 작업이다.


  Iterator 와 Generator 는 iteration 에 대한 직접적인 적용 및 커스터마이징 메커니즘을 제공한다.







ES6 에서의 Iterator (Iterator in ES6)


Iterator 는 새로운 문법이나 built-in 이 아니라 프로토콜(약속)이다.


이 프로토콜은 몇 가지 규칙만 준수한다면 어떠한 객체에서도 구현될 수 있다.











Iterator 프로토콜 (The iterator protocol)


Iterable 한 객체가 되려면 Symbol.iterator 를 Key 로 갖는 속성이 반드시 존재해야 한다:


Property

Value

[Symbol.iterator]

  Iterator 프로토콜을 준수하는 객체를 리턴하며 인자가 없는 함수




다음 규칙에 따라 next() 메서드를 구현한 객체를 iterator 라고 한다:


Property

Value

next

 아래의 두 속성을 가지는 객체를 리턴하며 인자가 없는 함수:


 1. done (boolean)

     * iterator 가 순회를 모두 마쳤을 경우 true

     * iterator 가 순회할 다음 value 가 존재할 경우 false

 2. value - iterator 에 의해 리턴될 값. done 이 true 일 경우 생략 가능




Iterable 하며 Iterator 프로토콜을 만족하는 예시 코드:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var someObject = {};
 
...
 
someObject[Symbol.iterator] = function () {
  var num = 1;
 
  return {
    next: function() {
      return num < 4 ?
        {value: num++, done: false} :
        {done: true};
    }
  };
};
 
...
 
for (let value of someObject) {
  console.log(value);
}
// 1
// 2
// 3
cs











Generators


커스텀 iterator 는 유용하지만, 그 내부 상태를 유지하기 위한 매우 세심한 관리를 필요로 한다.


Generator 는 이에 대한 강력한 대안이다: 내부 상태를 스스로 유지하는 하나의 함수만 작성하면 된다.



Generator 는 iterator 를 위한 factory 함수의 일종이다.


하나 이상의 yield expression 을 가지며 function* 문법을 사용하는 함수를 Generator 라고 한다.



Generator 예시 코드:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var someObject = {};
 
...
 
someObject[Symbol.iterator] = function* () {
  var num = 1;
 
  while (num < 4) {
    yield num++;
  }
};
 
...
 
for (let value of someObject) {
  console.log(value);
}
// 1
// 2
// 3
cs











특이한 예제 코드 (Examples)


무한 iterator (infinite iterator):


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function idMaker(){
    var index = 0;
    
    return {
       next: function(){
           return {value: index++, done: false};
       }
    };
}
 
var it = idMaker();
 
console.log(it.next().value); // '0'
console.log(it.next().value); // '1'
console.log(it.next().value); // '2'
// ...
cs




Generator 를 사용한 무한 iterator (Infinite iterator with a generator):


1
2
3
4
5
6
7
8
9
10
11
12
function* idMaker(){
    var index = 0;
    while(true)
        yield index++;
}
 
var gen = idMaker();
 
console.log(gen.next().value); // '0'
console.log(gen.next().value); // '1'
console.log(gen.next().value); // '2'
// ...
cs











출처


https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators




프로세스가 생성되면 Ready 상태가 된다.


Ready 상태란, cpu를 기다리는 상태이다.




그리고 곧 Running 상태로 넘어가서 cpu에게 실행된다.


Running 상태란, cpu에게 실행되어지고 있는 상태이다.


그러다가 자신에게 주어진 cpu 단위 사용시간 (cpu time quantum) 을 모두 소비하거나, 혹은 더 높은 우선순위의 작업 (예를들어 인터럽트) 에게 cpu를 선점당할 경우 다시 Ready 상태로 돌아가서 줄을 선다.




만약 Running 상태에 있다가 block I/O 등 시간이 오래 걸리는 함수 (예를들어 fopen) 를 호출한 경우 해당 함수가 리턴될 때까지 Waiting 상태가 된다.


Waiting 상태란 Sleep 상태와 같다. cpu를 기다리는 게 아니라 해당 I/O 의 종료를 기다린다. 신호 수신을 통해 Sleep 에서 깨어나면 Ready 상태가 되어 cpu에게 다시 실행되기를 기다린다.




프로세스가 종료될 때까지 위 과정이 반복된다.






출처 : 2015년 한양대학교 강수용 교수님의 수업 및 내 지식