제어 구조

언어의 8가지 주요 분류

  • 언어의 모든 구성요소를 포함하고 구문은 다르지만 모든 언어에 공통적으로 포함된다.
  • 언어를 배울 때 쉽게 접근할 수 있다.
  • 언어 독립적인 방식으로 알고리즘을 설계할 수 있다.

순차(sequencing)

수행될 문장이나 수식은 일정한 순서에 따라 수행된다. 가장 일반적인 것이 프로그램 텍스트 상에 나타난 순서대로 수행하는 것이다.

선택(selection)

어떤 실행 시간 조건에 의해 선택이 두 개 또는 그 이상의 문장이나 수식 부분을 선택할 수 있다. 가장 일반적인 선택 구조(constructs)는 if나 case(switch) 문이다. 선택은 다중택일(alternation)이라고 불리기도 한다.

반복(iteration)

주어진 코드 부분이 반복적으로(repeatedly) 수행되는 것인데, 이 때 일정 회수를 반복하거나 실행시간 조건이 만족할 때까지 반복할 수 있다. 반복 구조는 while, do, repeat 루프가 있다.

프로시져 추상화 (procedural abstraction)

복잡한 제어 구조가 모인 부분을 서브루틴이라고 부르는데, 이것은 하나의 단위처럼 취급하면서 캡슐화된다. 흔히 매개변수를 이용할 수 있다(parameterized).

재귀 (recursion)

수식은 그 자신을 직접 또는 간접으로 이용하여 정의될 수 있다. 그 경우 계산 모델은 스택을 이용하여 수식의 중간까지 계산된 인스턴스에 대한 정보를 유지해야 한다. 재귀는 자기참조 서브루틴에 의해서 많이 정의된다.

동시성 (Concurrency)

두 개 또는 그 이상의 프로그램 부분이 동시에 실행되거나 계산될 때 그것을 동시성이라고 한다. 동시성은 별개의 프로세서에 의해 병렬로 수행되거나 하나의 프로세서에서 병렬과 마찬가지 효과가 나도록 인터리브되는 것도 가능하다.

+예외처리 (Exception handling)

비결정성 (Nondeterminacy)

문장이나 수식의 순서나 선택이 일부러 정하지 않고 남겨두어서 어떻게 수행되든 상관없이 올바른 결과가 되는 것이 비결정성이다. 일부 언어에서는 선택이 랜덤 또는 공평하게 되도록 요구하고 있다.

제어 흐름의 다른 범주는 상대적인 중요도가 프로그래밍 언어의 부류에 따라 조금씩 다르다. 순차를 예로 들면, 순차는 명령형 언어(폰 뉴만 및 객체지향)에서 중심적인 역할을 하지만 함수 언어에서는 그리 중요하지 않다. 함수 언어는 수식의 계산을 위주로 하고 결과값이 아닌 방식으로 프로그램의 결과에 영향을 미치는 문장(특히 지정문)을 없애거나 중요하지 않게 취급한다. 비슷하게 함수 언어에서는 재귀를 매우 중시하고 자주 사용하는 반면 명령형 언어는 반복을 강조하는 경향이 있다. 로직 언어는 제어 흐름 자체를 그리 중요하게 보지 않는다. 로직 언어의 프로그래머는 추론 규칙의 집합을 정하고 언어 구현에서는 그 규칙들을 적용하여 원하는 성질을 만족하는 값의 집합을 얻어내기 위하여 규칙을 어떤 순서로 적용할지 계산해야 한다.

초기화

  • 변수의 메모리가 할당될 때 초기화
  • 별도의 지정에 의한 값 설정보다 성능 상 유리(로드 과정을 없애기 때문)
  • 초기화 오류 방지(초기화되지 않은 변수 사용 방지

언어에 따른 초기화

  • c: 정적 변수는 0으로 초기화
  • java: 참조 객체(static, 동적 할당)의 모든 필드는 0으로 초기화된다. (지역변수(스택)는 초기화되지 않음)

스택 객체는 초기화되지 않는 이유는?

스택 객체는 실행 시에 메모리가 할당되고, 언제 메모리가 할당될지 미리 알 수 없기 때문에 정적 객체와 다르게 자동으로 초기화되지 않는다.

초기화의 동적 검사

  • 실행 시 쓰레기값이 참조되면 동적 오류 발생
  • 초기화되지 않은 값을 정해두고 그 값으로 초기화
  • floating point number의 NAN
  • 하드웨어적 지원이 있으면 쉽게 판단 가능
  • 정수 32비트는 모두 유효한 값을 나타내는데 쓰이는 문제가 있어, 초기화 여부를 나타내는 flag 비트를 두고 사용시마다 검사해야되는데, 비용이 커서 불가능
  • 자바는 불필요한 초기화 강요 (스캐너 try catch), 확실한 지정

확실한 지정

  • 초기화되지 않은 변수를 금지하는 것
  • 프로그램의 제어 흐름을 분석하여 초기화 여부를 컴파일러가 정적으로 검사
  • 컴파일러의 관점에서 모든 제어 경로에서 모든 변수가 반드시 사용되기 전에 값이 지정되어야 함

복사생성자와 지정연산자

MyClass y, z;
MyClass x = y; // 복사생성자 호출
z = x; // 지정연산자 호출

얕은 복사(Shallow copy)와 깊은 복사(Deep copy)

Immutable 객체(수정불가능한 값을 가진 객체)는 얕은 복사가 문제가 되지 않지만, 나머지는 댕글링 포인터나 메모리 누수 문제 가능성이 있다.

부수효과

  • 프로그래머가 수행 순서를 알아야 부수효과의 결과를 예측할 수 있다.
  • 최적화를 위해서는 컴파일러가 계산 순서를 바꿀 수(부수 효과를 컴파일러가 다룰 수) 있어야 한다. (더 나은 최적화를 위해 부수 효과의 주도권을 컴파일러에 주어줌)

자바의 안정성

  • 배열 범위, 타입 오류를 실행 시에 반드시 체크
  • 모든 메소드 호출을 동적으로 바인딩

컴파일러에 의한 수식 처리

// f(c)를 먼저 하면 모든 레지스터 사용 가능
a*b + f(c)
// d*3을 a*2보다 먼저 하면 a 로드를 기다리는 동안 곱하기 계산 가능
a = B[i]
c = a*2 + d*3
//수학적 동치 사용
a = b + c
d = c + e + b
=> d = a + e
//오버플로우와 언더플로우 가능성, 변경된 식으로부터의 부수효과 가능성이 있으면 재구조화를 하지 않음
b - c + d
//오버플로우 동적 검사= 자바에서는 정밀도가 명확해서 검사 가능, C/C++는 컴파일러 구현 시 결정
//단축 계산, 조건문1이 거짓일경우 그대로 실행종료
(조건문1) and (조건문2)
//단축 계산, 조건문1이 참일 경우 그대로 실행
(조건문1) or (조건문2)
//만약 단축 계산이 부수효과가 있을 경우 하지않음
if(f(x) and g(x))

Check your understanding (6.1.3~6.1.5)

12.변수에 값을 지정할 수 있음에도 초기화 기능이 중요한 이유는 무엇인가?

초기화를 통해 메모리 Load 연산을 줄일 수 있고, 이는 프로그램 실행 속도의 향상을 가져오기 때문이다.

13.복합값(aggregates)은 무엇인가? 왜 필요한가?

구조체와 같이 단순 데이터 타입들의 집합을 말한다. 이는 좀 저 편리한 데이터의 관리를 위해 필요하다.

14.자바와 C#에서 사용하는 절대적 지정의 개념을 설명하시오.

절대적 지정은 어떤 변수가 사용되기 전에 반드시 초기화되어야 함을 의미한다.

15.실행시에 초기화되지 않은 변수의 사용을 모두 검출하는 것이 왜 일 반적으로 비용이 많이 소요되는지 설명하시오.

int 자료형의 경우 32비트 전부 유효한 int 자료형 표현에 쓰이기 때문에 모두 검출하기 위해서는 flag 비트를 설정하여 각각 모두 비교해야하기 때문에 비용이 많이 든다.

16.컴파일 시 초기화되지 않은 변수의 사용을 모두 검출하는 것이 왜 불가능한지 설명하시오.

객체를 동적으로 할당할 경우, 객체가 어떤 용도로 쓰일지 모르기 때문에 할당이 안될 경우 자바와 같이 NullPointerException이 발생할 가능성이 있다.

17.왜 대부분의 언어가 매개변수들의 계산순서를 명시하지 않고 컴파일러의 재량에 맡기는지 이유를 설명하시오.

매개변수들의 계산 순서가 명시되면 컴파일러가 최적화가 가능한 계산들에 대해 부수효과를 고려해야 되기 때문에 코드의 최적화에 방해가 된다.

18.단축진위계산이란 무엇인가? 왜 유용한가?

단축진위계산은 두 개의 진위계산에 대하여 앞의 진위 계산으로 진위를 판별할 수 있을 경우 뒤의 진위 계산을 생략하는 것이며, 이를 통해 프로그램의 실행 속도를 개선할 수 있다.

계산 순서

중위 표기법에서만 문제가 된다.

x = a%2!=x»2 ? *q : *p++;

x = (((a%2)!=x)»2) ? (q) : ((p++));

Lvalue와 Rvalue

  • 참조 모델에서 모든 변수는 Lvalue
  • Rvalue가 기대되는 곳에 나타나면 값을 간접 참조
  • 간접 참조는 묵시적이고 자동으로 이루어짐

  • 순수 참조 모델 언어: 파이썬
  • 파이썬의 참조 모델 특징: 모든 이름은 참조
  • 유사 참조 모델: c언어 포인터, 자바의 객체 참조 변수

박싱과 언박싱

(내용무)

Check your understanding

1.제어흐름구조의 주요한 여덟가지 분류는 무엇인가?

순차, 선택, 반복, 프로시저 추상화, 재귀, 동시성, 예외처리, 비결정성

2.연산자와 함수는 어떻게 구별되는가?

함수는 연산자와 다르게 스택호출과정이 존재한다.

3.전위, 중위, 후위 표기법의 차이를 설명하시오.

전위는 앞에붙는거 +ab

중위는 가운데붙는거 a+b

후위는 뒤에 붙는거 ab+ 캠브리지폴란드식 표기법은 무엇인가? 후위표기법을 쓰는 두가지 프로그래밍 언어를 쓰시오. pdf 참조

4.결합 및 우선순위 규칙이 왜 Postscript나 Forth에서는 필요하지 않은가?

5.수식이 투명하게 참조될 수 있다는 것은 무슨 뜻인가?

수식에 부수효과가 발생하지 않는다는 것이다.(?)

6.변수의 값 모델과 참조모델의 차이점은 무엇인가? 그 구별은 왜 중요한가?

값 모델은 좌변값과 우변값에 오는 변수에 따라 의미가 달라진다. 좌변에 오는것은 변수의 주소, 우변에 오는것은 변수의 값이 된다. 그 반면에 참조 모델은 좌변값과 우변값이 의미하는 바가 서로 참조하고 있는 것을 가리키는것이다. 그러므로 좌변값이 우변값이 참조하고 있는 것을 참조하겠다는 의미가 되므로 중요한 차이점이라 할 수 있다.

7.좌변값(L-value)과 우변값(r-value)이 무엇인지 설명하시오.

좌변값은 좌변에 오는 값, 우변값은 우변에 오는 값이다.

8.변경되는(mutable)과 변하지 않는(Immutable) 값의 차이가 변수의 참조모델을 구현하는데 왜 중요한가?

변경되는 값은 ~~ 변하지 않는 값은 ~~????

언어별 차이점

C는 수식을 문장으로 인식가능
a+b;
자바는 Invalid AssignmentOperator 오류
a+b;

if(a = b)
c-> 허용
c++ -> 진위형으로 자동 형전환되나 허용
java -> 자동 형전환은 불가, 둘다 진위형일 경우 허용
python -> int, String, list가 진위형 자동 형전환, 0, "", []은 거짓

복합 지정 연산자

+=, -=, *=, /=, %=

A[fn(i)] = A[fn(i)] + 1; 의 경우 중복 부수효과 발생 가능하지만 복합 지정 연산자를 사용하면 완화됨

다중지정

a = b = c (c는 우결합)

a, b = c, d; (파이썬)

Check your understanding

9.직교성(orthogonality)을 프로그래밍언어의 설계 관점에서 정의하시오.

10.수직 중심 언어란 무엇을 뜻하는가?

11.산술지정연산자를 사용하는 것이 변수와 좌변과 우변에 모두 나오는 일반지정연산자를 사용하는 것과 비교하여 어떤 장점을 가지는지 설명하시오.

슈도 어셈블리 표기법

		r1 := a
    	r2 := b
    	r3 := 0 -- sum
L1:	if r1 >= r2 goto L2
		r3 := r3 + r1
    	r1 := r1 + 1
    	goto L1
L2:	print(r3)
		sum = r3

// 자동 형변환 사용
// 정수 레지스터 r~, 실수 레지스터 f~
// 전역변수 0으로 초기화

구조적 흐름 및 비구조적 흐름

Goto / 문장 레이블(statement label)의 사용

  • 어셈블리 중요한 흐름 제어 방법
  • Fortran 90, C++ 하위 호완성을 위하여 허용
  • 최근 언어는 금지하고, 순차, 선택, 반복 이용
//라벨을 이용한 break 예시
	Label1:
    	~~~~
        break Label1;

댕글링 else

if condition
	if condition
    	~~~
    else
    	~~~
  • switch문은 순차적 jump table 생성하여 컴파일 시간 상수로 비교하여 빠르게 이동.
  • (다른 구현 방법들: n개의값에대해값을찾는다른방법}순차적검사}해시테이블}넓은범위값의이진트리검색)
  • 수식의 타입: 비연속 타입, 형전환 불가

Check your understanding6장Control Flow (4) -2019학년도7주차1819.Goto가하는주요한역할은무엇인가? 구조적으로goto를대신할수있는프로그래밍언어의요소(키워드)는어떤것이있는가?20.다단계리턴과예외처리의차이점을설명하시오.21.왜함수형언어인리스프에서는나열이상대적으로덜중요한흐름제어형태가될까?22.함수가부수효과를가지는것이좋은예를들어보시오.23.단축계산에대한점프코드구현방법을설명하시오.24.대부분의언어에서if … then … else 이외에case 문을별도로지원하는이유는무엇일까?25.Case문의구현에사용될수있는검색방식세가지를설명하시오. 각각어떤경우에적합한것인지설명하시오.

?? 파스칼의 with문

반복문

  • 반복부의 문장은 부수효과를 반복하는 것이 주 목적이다.
  • 순차나열 제어 루프
  • 주어진 집합의 모든 값에 대해서 한번씩(for each)
  • 반복의 횟수는 시작 전에 결정됨
  • 논리적으로 제어되는 루프
  • 진위 조건식의 값이 바뀔 때까지 반복
  • 루프 안에서 값을 바꾸어 조건식의 값이 바뀌게 됨
  • if (r1–= 0) gotoLn 식으로 한 사이클의 효율적인 반복문 생성
  • 선테스트 루프(while), 중간 검사 루프(중간에서 검사), 후테스트 루프(do while)
  • 이터레이터(Iterator)
  • 파이썬, 자바의 for each

코드 생성의 효율성 향상

  1. Load 최소화
  2. 분기 최소화 (불가피한 분기는 예측실행)
//자바 이터레이터
class TreeNode<T> implements iterable<T> {
	TreeNode<T> left;
    TreeNode<T> right;
    T val;
    ...
    public Iterator<T> iterator() {
    	return new TreeIterator(this);
    }
    private class TreeIterator implements Iterator<T> {
    	private Stack<TreeNode<T>> s = new Stack<TreeNode<T>>();
        TreeIterator(TreeNode<T> n){
        	s.push(n);
        }
        public boolean hasNext(){
        	return !s.empty();
        }
        public T next(){
        	if(!hasNext()) throw new NoSuchElementException();
            TreeNode<T> n = s.pop();
            if(n.right != null) s.push(n.right);
            if(n.left != null) s.push(n.left);
            return n.val;
        }
    }
}
//인터페이스
interface Iterable<T> {
	Iterator<T> iterator();
}
interface Iterator<T> {
	boolean hasNext();
    T next();
    void remove();
}

//파이썬 yield 이터레이터 //파이썬 lazy evaluation, 제너레이터 수식

Check Your Understanding6장Control Flow (5) -2019학년도9주차2927.나열값으로제어되는for 루프의구현에서모호한점을설명하시오.28.왜대부분의언어에서는실수를for 루프범위나증감값으로허용하지않는지그이유를설명하시오.29.루프구현에서반복회수는무엇인가?그것을이용하는루프구현의장점은무엇인가?30.인덱스변수를제어하는루프의범위안에서선언하는것이어떤장점을가지는가?

32.컨테이너란무엇인가? 33.참이터레이터와이터레이터객체의차이를설명하시오.34.지연계산(lazy evaluation)이란무엇인가?35.지연계산이좀더바람직한두가지이유를쓰시오.

재귀

  • 부수효과가 없는 함수형 언어에서 자연스러움
  • 함수를 계속 호출
  • 꼬리 재귀
  • 서브루틴 호출과 스택 관리 때문에 보통 반복이 재귀보다 효율적
  • 재귀 이전에 필요한 계산을 모두 마치고 재귀 호출에서 리턴된 값을 그대로 반환
//재귀 -> 꼬리재귀
int summation(f, low, high){
	if(low == high)
    	return f(low);
    else return f(low) + summation(f, (low+1), high);
}

int summation(f, low, high, subtotal){
	if(low == high)
    	return (subtotal + f(low));
    else return summation(f, (low+1), high, subtotal+f(low));
}

//재귀(꼬리재귀) -> 반복

int gcb(int a, int b){
	/* assume a, b > 0 */
    if(a == b) return a;
    else if (a>b) return gcd(a-b, b);
    else return gcd(a, b-a);
}

int gcd(int a, int b){
start:
	if(a == b) return a;
    else if(a>b){
    	a = a-b; goto start;
    } else {
    	b = b-a; goto start;
    }
}

** 메모이제이션 **

꼬리재귀가 대표적인 메모이제이션의 예이다.

Check your understanding6장Control Flow (5) -2019학년도9주차6338.꼬리재귀함수란무엇인가? 왜꼬리재귀가중요한가?39.인자먼저계산하는방식과정의대로계산하는방식의차이를설명하시오. 각각이어떤경우에더적합한가?


C++

//배열 객체 할당과 해제

int * Array = new int[100]; delete[] Array;

//string의 길이

string.length

//C++의구조체

•메소드도가질수있고멤버를상속할수도있다. •클래스와차이: 구조체에서모든멤버는디폴트로public 클래스에서는디폴트로private

복사생성자란•새로객체를생성하면서같은클래스의기존객체값으로초기화하는생성자•언제불려지는가?•선언에서객체를생성자매개변수로준경우•매개변수로객체를넘긴경우•반환값으로객체를주는경우•복사생성자는항상정의되어야한다•없으면컴파일러가디폴트복사생성자(아무일도안함)

선언부: •CClass(constCClass&) •여기서const는전달된매개변수객체의값을바꿀수없음을의미

•복사생성자가없으면 •CContactnewby(templateA); // address 주소복사 •newby.address->city = Seoul; // Address* address; •// templateA의city도바뀜… •// 복사생성자에서Address 새로할당해야함

foo& operator=(constfoo& oth

//캡슐화위배•friend 함수나friend 클래스는private 접근가능

클래스와 상속?

모든 클래스는 public 멤버의 접근권한 default는 private 다중상속 가능(여러 개의 슈퍼클래스를 가짐) (구조체는 다중상속불가능)

?? @Override 어노테이션의 역할

//메소드 오버라이딩
class A {
	void test(){
    	print("A");
    }
}
class B extends A{
	void test(){
    	print("B");
    }
}

A a = new B();
a.test(); // B 출력

//정적 메소드는 해당 클래스의 것이 불려짐

class A{
	static void stest(){
    	print("A");
    }
}
class B extends A{
	static void stest(){
    	print("B");
    }
}

A a = new B();
A.stest(); // A
B.stest(); // B
a.stest(); ??

//다형성 Bike 예제

//동일한 이름의 필드가 부모 클래스와 자식 클래스에 존재하면 부모 클래스거는 숨겨지고 super.x로 호출 가능

super은 보통 숨겨진 필드, 오버라이드된 함수, 생성자에서 호출함

============= final 키워드

  • 클래스 멤버 필드: 선언 또는 생성자에서 초기화
  • 지역 변수: 선언부에서 초기화
  • 인터페이스: final 변수만 선언 가능
  • Anonymous 클래스: final만 접근 가능
  • 내부 클래스: 포함된 함수의 final 지역변수만 접근 가능(복제)
  • 컴파일시간상수인경우 all 대문자
  • final 메소드: 상속한 클래스에서 오버라이드할 수 없음을 표시
  • final 클래스: 상속할 수 없는 클래스, String과 같은 immutable 클래스 => 최적화, 멀티스래딩시 공유에 유리

추상 메소드와 추상 클래스

Abstract 메소드

  • 몸체부 없이 시그니처만 잇음_인터페이스에서 쓰임 Abstreact 클래스
  • 객체 생성할 수 없는 클래스
  • Abstract 메소드를 포함하면 반드시 클래스도 abstract여야 함 Abstract 클래스 용도
  • 공통 코드를 가지는 슈퍼클래스를 만들 때 - 구체 클래스는 아님
  • 인터페이스를 구현하는데 공통으로 쓸 일부만 구현할 때

** 공통 필드나 공통 코드가 있을 때는 추상 클래스, 메소드 선언만으로 충분한 경우는 인터페이스 **

인터페이스 다른용도 메소드 전달(이벤트핸들러)이나 스트림 API에서 람다 대신 쓰이는 경우 사용 코드 부분을 전달하는 역할 @FunctionalInterface

파이썬

리스트 클래스 main, init, args

클래스, 인스턴스, 함수의 속성(f.counter)

x.name=“Marvin” x.build_year=1979 y.name=“Caliban” y.build_year =1993

getattr(x, ‘build’, 100)

def hi(obj):
    print("Hi, I am " + obj.name)
class Robot:
	say_hi = hi
x = Robot()
x.name = "Marvin"
Robot.say_hi(x)
//hi(x)
//x.say_hi()

//만약 name이 없으면 AttributeError 발생

class Robot:
	def __init__(self, name=None):
    	self.name = name
    def say_hi(self):
        if self.name:
            print("Hi, I am " + self.name)
        else
            print("Hi, I am a robot without a name")
x = Robot()
x.say_hi()
y = Robot("Marvin")
y.say_hi()

__ = 던던

__init__처럼 직접 호출되지 않고 내부에 장착되어 있는 메소드 : 정해진 상황에서 자동으로 불려짐

str : 문자열화함수, 객체를 문자열로 바꿔주는 메소드: 자바의 toString

str(mylist)

  • 리스트 클래스의 __str__을 찾는다.
  • 없으면 __repr__을 찾는다
  • 둘다 없으면 디폴트로 인스턴스의 기본 출력

__repr : 쉘에서 인스턴스 값을 직접 출력할 때 호출

x

이 경우는 __str__이 있어도 불려지지 않음

__repr__만 있고 __str__이 없을 때 출력이나 str(x)가 불려지면 __repr__을 사용

출력 및 사용자에게 보여줄 문자열: str 객체의 데이터 표현으로 사용하는 경우: repr

__repr__은 파이썬 인터프리터에 의해 파싱 가능한 문자열이여야 한다.

  1. o == eval(repr(o))를 만족
  2. 17쪽 리스트와 datetime 예제
  3. eval(repr_s)는 객체를 돌려줌
  4. eval(str_s)는 syntax error

정보은닉

이름 타입 의미
name Public 이 속성들은 클래스 정의부 안과 밖에서 자유롭게 사용될 수 있다.
_name Protected protected 속성은 상속 클래스 정의부가 아니면 클래스 정의부 밖에서 사용될 수 없다.
__name Private 이 속성들은 접근할 수도 없고 보이지도 않는다. 이런 속성은 자신의 클래스 정의부 내부가 아니면 읽을 수도 없고 쓸 수도 없다.
class A():
	def __init__(self):
    	self.__priv = "private"
        self._prot = "protected"
        self.pub = "public"

*** 클래스 속성 = 클래스의 모든 인스턴스가 하나의 값을 가짐, 클래스 헤더 바로 아래 선언. 지정하려면 클래스 이름.속성명을 사용해야됨 ex)

class A:
	a = "I am a class attribute!"

*** 인스턴스 속성: 각 인스턴스가 가지는 속성으로, 다른 값을 가질 수 있다. 인스턴스.속성명 = 인스턴스 속성을 추가

??? 28쪽 dict

정적 메소드

클래스 속성을 변경하거나 계산하는 코드

Self를 필요로 하지 않는 경우

  • Self 매개변수를 받지 않는 메소드
  • Self 없이 호출가능
  • 메소드 헤더 앞에 @staticmethod를 붙임

호출 방법

  • 인스턴스.정적메소드
  • 클래스이름.정적메소드

클래스 메소드

클래스에 바인딩되는 메소드

호출방법

  • 클래스 이름.메소드이름
  • 인스턴스.메소드이름

** 정적 메소드는 상속하는 모든 클래스가 물려받지만 클래스 메소드는 그 클래스에만 바인딩됨. **

자바

//클래스와 상속

접근지정자 public protected default private

static과 final

클래스의 정적 변수 생성 후 초기화

  • 정적 변수는 클래스 로드 시 생성되는데, 초기화를 위해서 별도의 함수를 호출하기 어려움
  • 초기화할 수 있는 생성자의 역할을 하고, 정적 변수가 할당될 때 실행된다.
class Main {
	static{
    
    }
}

상속과 다중상속

같은 이름의 필드가 동시에 상속될 , 같은 시그니처의 메소드가 동시에 상속될 ..

 - 자바는 하나의 클래스만 물려받음 (슈퍼클래스가 인터페이스보다 우선)
 - 인터페이스는 필드를 갖지 않고 메소드의 선언부만 가짐
 - 충돌이 있으면 앞의 것이 우선


*** 이름 충돌 ***

 - 동일한 변수 이름을 서브클래스에서 선언
 - 동일한 메소드 이름을 서브클래스에서 선언
 - Static 변수를 동일한 이름으로  선언


// 클래스 상속과 슈퍼클래스, 서브클래스

슈퍼클래스: 공통메소드를 가짐
오버라이딩: 슈퍼클래스는 공통부만 가짐, 서브클래스는 달라지는 부분만

업캐스팅: 슈퍼클래스 참조변수로 Took Tbook 모두 가리킴, 같은 ArrayList 섞여서 들어감
오버라이딩: read compare 호출로 TBook 기능도 호출 가능

```java
for(Book book: bookList){
	if(book.compare(keyword))
    System.out.println(book.getTitle());
}
/* */
Book book = null;
while(fileIn.hasNext()){
	n = fileIn.nextInt();
    switch(n){
    case 1:book = new Book(); break;
    case 2:book = new TransBook(); break;
    default: break;
    }
    book.read(fileIn)
    bookList.add(book)
}

인터페이스

  • 부분시스템 또는 상호작용할 시스템들 사이의 약속
  • 참조타입으로 상수, 메소드선언부, 정적메소드 등만을 가질 수 있는 클래스
  • 모든 변수는 public static final ~(생략가능)
  • 메소드 바디는 정적메소드만 가질 수 있음.
  • implemented by classes or extended by other interfaces
  • 중복 기능의 제거로 코드의 재사용성을 늘림
  • 메소드의 표준만 정의
  • 사용하는 쪽에서 필요한 메소드를 선언ㅇ
  • 공통 코드가 없는 클래스들도 인터페이스를 통해 같이 취급될 수 있다.

** 클래스 vs 인터페이스 **

  • 클래스
    • 필드와 메소드 바디를 가짐
    • 상속할 때 필드와 메소드를 상속(메소드 오버라이드 가능)
    • 객체 생성 가능
  • 인터페이스
    • 메소드 선언부만 가짐
    • 정적 필드와 메소드 가질 수 있음
    • 객체 생성 불가능
    • 상속(implements)할 때 메소드를 모두 구현해야 함

공통적으로 업캐스팅이 가능하다.

자바의 패턴

  • Factory
    • create(): 필요한 타입의 객체를 생성하여 반환
    • 상위 타입의 사용부에서 어떤 상속 클래스 객체를 생성할지 알지 못할 때
  • Iterator
    • 컬렉션에서 요소를 하나씩 접근하기 위한 인터페이스 제공
    • hasNext(), next(), remove()
  • 싱글톤 패턴
    • 프로그램 전체에서 단 하나의 객체 인스턴스만 가지도록 보장
    • 처음 한번 new 한 뒤부터는 그 객체를 반환
    • 프로그램 어디서나 MyClass.GetInstance()로 접근 가능
  • 파사드 패턴
    • 다른 서브시스템 부분을 이용하기 위한 관문
    • 실제 구현 클래스가 아니라 접근하기 위한 메소드의 원형만 제공하는 인터페이스/클래스
    • 구현 클래스는 알 필요 없음
  • 마커 패턴
    • 클래스를 접근하기 위한 매개 역할
    • 실제 그 클래스는 임포트되지 않음(필드나 메소드는 필요하지 않은 경우)
    • C++ 의 클래스 전방 선언과 같은 역할

인터페이스의 한계

  • 용도: 공통되는 기능을 표준으로 정의
    • 그것을 이용하는 클래스 작성
    • 여러가지 클래스에 적용 가능
  • 한계
    • 타입 안전하지 않다.
    • 컴파일러가 어떤 타입인지 정확히 알지 못한 채 참조 변수를 사용하고 있다.
    • 다운캐스팅의 위험성
    • 여러가지 타입이 섞일 수 있음.
//danger1
Manageable it = find(kwd);
Book bk = (Book)it //TypeCastException

//danger2
ArrayList<Manageable> mList = new ArrayList<>();
Student st = (Student)mList.get(i);

제너릭

  • 다형성을 제공하는 다른 방법
    • 다른 타입에 대해 중복되는 코드를 재사용
    • 상속을 이용한 다형성을 보완
    • 상속 다형성은 타입안전하지 않음
//두 코드의 차이는?
//code 1
public class Box{
	private Object object;

    public void set(Object object){
    	this.object = object;
    }
    public Object get(){return object;}
}

//code 2
public class Box<T>{
	// T stands for "Type"
    private T t;

    public void set(T t){this.t = t;}
    publilc T get() {return t;}
}

제네릭의 타입 매개변수 이름 컨벤션 E - Element( used extensively by the java Collections Framework) K - Key N - Number T - Type V - Value S,U,V ets - 2nd, 3rd, 4th types

제너릭의 이명: 파라메터화타입 T는 타입 파라매터

//제너릭의 상속 //제너릭 이용한 객체 생성, 중첩 제너릭(제너릭안의 제너릭)

Obj<Styring, Box<Integer>> p = new Obj<>("he", new Box<Integer>());

** Bounded Type Parameters ** Parameterized Type에 올 수 있는 타입을 제한하는 방법 T 타입을 확정지어주게 된다. 타입 파라메터 뒤에 extends 절 추가 클래스나 인터페이스 둘다 extends로 사용 <T extends ~~~~>

제너릭을 써야 하는 이유?

  • 컴파일러에 의해 구체 타입으로 바뀐다.
  • 컴파일러가 정적 타입 검사를 할 수 있다.

제너릭의 한계

  • 제너릭을 기본 타입으로 객체 생성할 수 없음
  • 타입 파라매터에 해당하는 객체를 생성할 수 없음
  • 팩토리 패턴 이용해야됨
  • 타입 파라매터의 정적 필드를 생성할 수 없음
  • 타입 파라매터를 이용하여 캐스팅이나 instanceof를 사용할 수 없음
//아래와같이 사용한다면
Pair<Integer, Character> p = new Pair<>(8, 'a')
//아래와 같이 자동박싱을 해준다.
Pair<Integer, Character> p = new Pair<>(Integer.valueOf(8), new Character('a'));
//팩토리 패턴
interface Factory<E> {
	E create();
}
class SomeContainer<E> {
	private final Factory<E> factory;
    SomeContainer(Factory<E> factory){
    	this.factory = factory;
    }
    E createContents(){
    	E e = factory.create();
    	e.init();
    	return e;
    }
}

Q. 객체지향에서 접근권한을 굳이 구별하는 이유는?

클래스를 default public private으로 선언하는것의 차이점

private 메소드는 어디에 사용하는가

is-a 관계와 Reflection

자바 업캐스팅 및 다운캐스팅 구현 방법 자바 객체는 메모리에 객체의 필드를 위한 영역을 할당받는다. 이 때 상속 클래스의 제 일 꼭대기에 있는 Object 클래스의 필드부터 차례로 상속한 클래스의 필드가 추가된다. 그 결과 모든 객체는 앞부분만 보면 슈퍼클래스의 객체로 취급될 수 있다. 이것이 자바 언어 에서 “is-a” 관계를 가능하게 하는 핵심이다. 위의 예에서 클래스 A의 객체는 앞쪽에 Object 영역이 있고 그 다음에 A의 필드가 잡히므 로 이 객체는 제일 앞의 주소 영역을 Object 참조가 가리키는 경우 그 영역을 Object 객체 라고 볼 수 있다. 마찬가지로 세번째로 생성된 클래스 C의 객체는 A 클래스의 참조 z에 지 정되었고 이 때 z는 그 객체의 앞부분만 보고 이 객체가 A 타입이라고 생각한다. 다운캐스팅은 프로그래머가 “is-a” 관계가 만족하지 않는 서브클래스 방향으로 강제형변 환을 요구하는 것이다. 위의 예에서 z가 가리키고 있는 객체가 C 클래스이므로 C 타입으 로 다운캐스팅을 요청하고 이에 따라 w는 z가 가리키고 있던 주소로부터 C의 객체 크기만 큼을 자신의 객체 영역이라고 생각하게 된다.

동적바인딩과 타입캐스팅 오류 Is-a 관계에 의한 업캐스팅은 프로그램에 아무런 부담이 없는 연산이지만 반대방향의 다 운캐스팅은 그렇지 않다. 즉 슈퍼클래스의 참조변수가 가리키고 있는 객체는 컴파일러 입 장에서는 슈퍼클래스라고 알고 있으므로 그 객체의 원래 타입이 무엇인지는 알지 못한다. 그것은 실행시점이 되어서 실제 new된 객체가 가진 Object 영역의 제일 앞자리에 있는 Class 객체의 내용을 봐야 알 수 있다. (동적바인딩) 예를 들어 Object를 상속한 Mammal이 있고 Mammal을 상속한 Cat과 Dog 클래스가 있다 고할때 “is-a” 관계에 의해 Cat이나 Dog 객체는 Mammal이 될 수 있고 당연히 Object도 될 수 있다. 그러나 Mammal이 가리키고 있는 어떤 객체는 Cat일 수도 있고 Dog일 수도 있으 며 컴파일러는 그것을 실행하기 전에는 알지 못한다. 이 때 프로그래머가 “이것은 확실히 Dog이니 그냥 Dog로 바꿔줘”라고 요청하는 것이 다운캐스팅이다. 이 경우 컴파일러는 Object 객체 영역에 있는 Class 필드를 이용해 실제 그 객체가 Dog 타입이 맞는지 검사하 고 아닌 경우TypeCastException을 일으킨다. Mammal m = new Cat(); … Dog d = (Dog)m; // 예외 발생

자바 가상함수의 동적바인딩 각 클래스는 슈퍼클래스의 메소드를 오버라이드할 수 있다. 그 경우 슈퍼클래스가 가리 키고 있는 객체에서 해당 메소드를 호출할 때 실제 객체의 클래스의 메소드가 불려져야 한 다. 그러나 앞에서 보았듯이 참조 변수는 슈퍼클래스 타입이므로 이 객체가 실제 어떤 클래 스인지는 컴파일러는 알지 못한다. 그러므로 해당 메소드가 불려졌을 때 자바 런타임은 어 떤 메소드를 불러야 할지(어느 명령문 주소로 점프해야 할지) 결정해야 한다. 각 클래스별로 메소드 호출에 대해 실제 불러야 할 메소드는 가상메소드테이블(virtual method table(VMT) 도는 dispatch table이라고도 함)에 들어있다. VMT는 클래스마다 하나씩 있으면 되고 실제로 앞에서 살펴본 Class 객체도VMT의 앞쪽에 들어간다. 앞의 예에서는 A 클래스의 foo를 C 클래스에서 오버라이드하고 B 클래스의 m도 C 클래 스에서 오버라이드한다. 그 결과 A와 B 클래스는 A.foo를 공유하고 B와 C 클래스는 각각 자 신이 정의한 m과 foo를 가리키는 vtable을 가지고 있다.

vtable

  • 클래스마다 메모리에 하나의 vtable 존재
    • 각 클래스마다 Class 객체도 하나씩 존재
    • 컴파일 시점에 해당하는 vtable의 주소를 객체의 제일 앞 영역에 넣어둠
  • 객체 메모리 영역의 구성
    • 제일 앞에 Object 객체의 필드
    • 그중 제일 앞이 vtable 주소
    • vtable 제일 앞에 Class 객체 주소
    • vtable에는 그 클래스에서 호출될 메소드의 코드 주소