반응형

1. 개요

 상속 관계인 두 클래스의 메서드를 오버라이딩 한 후, 다형성의 원리를 적용하여 자료형과 참조 객체를 다르게 설정하였때 어떤 결과가 나올지 알아보았다.

 

 말이 조금 어렵게 느껴지니 예로 설명하면 다음과 같다.


 Parent라는 부모 클래스와 이를 상속받는 Child 자식 클래스가 있다.

 Parent 클래스에는 hi라는 메서드가 있기때문에 Child에서도 호출이 가능하나, 메서드를 재정의하고 싶어 메서드 오버라이딩을 하였다.

 객체 생성 시점에 Child child = new Child(); 형태로 생성 후 child.hi() 메서드를 호출해도 되지만, 다형성의 원리를 사용하여 Parent child = new Child(); 형태로 생성하였다.

 만약, 이 상황에서 child.hi() 메서드를 호출하면 Parent 클래스와 Child 클래스의 hi() 중 어떤 메서드가 실행될까?


 

 Child 객체를 참조하고있으니 Child 객체의 메서드가 호출될 것 같지만 자료형을 Parent이니 Parent의 메서드가 호출될 것 같기도 하다. 다형성에 대해 알아보고 이 고민을 해소해보자.


2. 다형성(Ploymorphism)이란?

 슈퍼클래스 타입의 변수가 서브클래스 타입의 객체를 참조할 수 있다는 성질이다.

 Child 클래스가 Parent 클래스를 상속받고 있다면 슈퍼 클래스 타입의 변수인 Parent가 Child 클래스를 참조할 수 있다는 의미인데, 예제를 보면 이해가 빠를 것이다. 다형성이란 말이 어렵지 사실 되게 익숙한 개념이다.

 

 그럼 예제를 통해 상속관계, 메서드 오버라이딩, 다형성이 적용된 객체를 생성해보도록 하겠다.


3. 예제

3.1. Parent.java

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Parent {
    
    protected String name;
    protected int age;
    
    public Parent(String name, int age) {
        this.name = name;
        this.age = age;
    }
    protected void hi() {
        System.out.println("안녕하십니까 올해로 "+age+"살인 "+name+"입니다.");
    }
}
cs

 

3.2. Child.java

1
2
3
4
5
6
7
8
9
10
11
public class Child extends Parent{
 
    public Child(String name, int age) {
        super(name, age);
    }
    
    @Override
    public void hi() {
        System.out.println("안녕? 내 이름은 "+name+"이고, "+age+"살이야! 만나서반가워~");
    }
}
cs

Parent 클래스를 상속받고 있으며 부모 클래스의 hi() 메서드를 오버라이드하여 재정의하였다.

 

3.3. Main.java

1
2
3
4
5
6
7
public class Main {
 
    public static void main(String[] args) {
        Parent child = new Child("심드류 아들",10);
        child.hi();
    }
}
cs

main 메서드에서 다음과 같이 자료형이 Parent인 child 변수에 Child 객체를 생성하여 초기화해주었다.

슈퍼클래스 타입(:Parent)인 변수(:child)가 서브클래스의 객체(new Child)를 참조하고 있다. 바로 이게 다형성이다.

그럼 이 상태에서 hi() 메서드를 실행하면 어떤 결과가 나올까?


4. 결과

Child 객체의 hi 메서드가 실행됨

 결과는 바로! Child 객체의 hi 메서드가 실행된다. 즉 자료형이 아닌, 참조 객체의 메서드가 실행되는 것이다.

 다형성의 원리를 사용하여 객체를 생성하고, 오버라이드된 메서드를 호출했을 때에는 슈퍼클래스의 메서드가 아닌, 서브클래스의 메서드가 호출된다. 즉, 참조 객체가 무엇이냐에 따라 호출하는 메서드가 동적으로 바뀔 수 있다는 뜻이다.

이러한 내용을 동적 바인딩(dynamic binding) 이라고 한다.


5. 정리

 상속관계에서 서브 클래스의 메서드를 오버라이딩 하고 다형성의 원리에 입각하여 객체 생성 후 메서드를 호출하면, 해당 메서드는 동적 바인딩된다.

 

반응형
반응형

목차

1. 개요

2. __proto__

3. 정리


1. 개요

prototype에 대한 내용이 생각보다 많아 내용을 정리해나가며 공부를 하고 있다.

지금까지의 내용을 다시 정리하면

 

 1) 함수가 정의되면 prototype을 참조 가능한 prototype 프로퍼티, __proto__ 메서드가 생성된다.

 2) prototype은 constructor(생성자)를 참조 가능하다.

 3) 함수의 생성자로 생성되는 객체들이 prototype 객체를 상속받는다.

 4) prototype의 내용을 변경하면 생성자로 생성된 객체는 변경된 내용을 상속받게 된다. (당연한 얘기)

 5) prototype 객체를 참조하는 것은 생성한 객체의 __proto__ 메서드이다.

 

function - __proto__ - prototype 간의 관계


 

 그렇다면 __proto__에 대해 알아보도록 하자.


2. __proto__

 __proto__란 prototype link라고 불리며 객체가 생성될 때 조상이었던 함수의 prototype 객체를 가리킨다.

 

간단한 실험을 통해 알아보자

 

 1) function a(){} - 함수를 생성한다.

 2) a.prototype.a_val = 1; - 해당 함수의 prototype 객체에 a_val = 1이라는 값을 추가한다.

 3) b = new a(); - 생성자를 통해 b라는 객체를 생성한다.

 4) b.__proto__를 확인한다!

 5) __proto__에는 조상 함수의 prototype 객체인 a.prototype을 나타낸다.

 6) 이러한 관계를 b가 a를 상속받았다고 한다. 왜냐고? b.a_val를 출력하면 1이 나오니까!

b.__proto__ 객체

 

b를 출력하면 알 수 있겠지만 b객체 자체는 a_val를 가지고 있지 않는다.

__proto__ 객체밖에 없다. 바로 이 객체가 a_val 속성을 찾을 때까지 조상 prototype을 참조해나간다!

b 객체

최상위인 Object의 prototype 객체까지 찾지 못했을 경우 undefined를 리턴한다.

이렇게 __proto__ 속성을 통해 상위 프로토타입과 연결되어있는 형태를 prototype Chain이라고 한다.


3. 정리

 1) 함수가 정의되면 메모리에 함수와 생성자를 생성할 수 있는 prototype 객체가 생성된다.

 

 

 2) 함수에는 prototype 객체를 참조 가능한 prototype 프로퍼티__proto__ 객체가 생성된다. 

 

 3) 1)에서 생성된 prototype 객체 안에는 constructor 프로퍼티가 있고 이는 자신을 생성한 생성자 함수를 가리킨다.

 

 4) 함수의 생성자(new)로 생성되는 객체들은 __proto__ 객체를 상속받는다.

 

 5) __proto__ 객체는 자신의 조상 prototype 객체를 가리킨다.

 

 6) 상속된다.

 

 이 정리가 이해가 가지 않는다면 __proto__ 실험 과정과 맨 위의 그림을 번갈아가며 과정을 따라가다 보면 prototype, 즉 상속의 원리와 과정을 이해할 수 있을 것이다. 

 

 이로써 prototype을 마무리하도록 하겠다.

반응형
반응형

목차

1. 개요

2. prototype

3. 테스트


1. 개요

 앞선 글에 이어서 prototype과 __proto__의 정체에 대해 파악해보도록 하겠다.


2. prototype

 함수가 생성되면 prototype 프로퍼티와 __proto__라는 메소드가 생성된다.

 prototype 프로퍼티는 생성된 함수의 원형 정보를 가지고 있는 prototype 객체에 접근할 수 있고,

prototype 객체는 생성된 함수 객체를 가리킨다.

잊어버리지 않게 이들의 관계를 다시한번 그림으로 나타내면 아래와 같다.

prototype과 constructor의 관계


3. 테스트

 prototype이 정확히 무슨 역할을 하는지 알기 위해 몇 가지 테스트를 진행하였다.

 

1) 함수를 정의하고 prototype 출력

1
2
3
4
5
6
7
8
<script>
        function a(){
            val_a = 1
        }
        //a.prototype.val_a = 2
        console.log(a)
        console.log(a.prototype)
    </script>

console 화면

a를 출력했더니 a 함수를 정의가 나오고

a.prototype을 출력했더니 객체가 나오고 그 객체에는 constructor(생성자)와 __proto__가 정의되어 있다.

 

 

console 화면

prototype 객체가 원래의 함수객체에 어떤 영향을 미치는지 확인하기 위해 5번 라인의 주석을 해제하고 컴파일하였더니

a에는 정의했던 함수의 원형이, a.prototype에는 val_a = 2라는 프로퍼티가 추가되어 출력되었다.

 

여기에서 얻은 결론은 prototype이 함수의 원형에는 영향을 미치지 못한다는 것이었다.

원형의 의미를 가진 prototype이 원형에 영향을 못미치는게 아이러니하다. 더 파고들어 이 의미를 이해해야겠다.

 

2) 생성자 호출

1
2
3
4
5
6
7
8
9
10
11
    <script>
        function a(){
            val_a = 1
        }
        a.prototype.val_a = 2
        console.log(a)
        console.log(a.prototype)
 
        b = new a()
        console.log(b)
    </script>

 b라는 변수에 a 생성자를 생성하여 대입하고 b를 출력하였다.

 

console.log(b)

 b를 출력했더니 생성자인 a가 출력되었고, 그 안에는 __proto__가, 그 안에는

val_a : 2, constructor : f a(), __proto__: Object 가 있었다.

그리고 이 내용은 위에서 출력한 a.prototype의 내용과 동일했다.

 

이로써 prototype에 대한 정보를 얻었다.

1. 함수에 대한 prototype은 생성자를 통해 정의된 객체가 상속받는 정보이다.

2. __proto__는 해당 객체가 상속받은 prototype의 정보를 갖고 있다.

 

정확한 확인을 위해 b.__proto__ === a.prototype 라는 코드를 넣어보았더니

true가 출력되는 것을 확인할 수 있었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    <script>
        function a(){
            val_a = 1
        }
        a.prototype.val_a = 2
        console.log(a)
        console.log(a.prototype)
 
        b = new a()
        console.log(b)
        console.log(b.val_a)
 
        console.log(b.__proto__ === a.prototype)
    </script>
 

b.__proto__ === a.prototype

 

공부한 내용을 정리하면

1) 함수가 정의되면 prototype을 참조 가능한 prototype 프로퍼티, __proto__ 메소드가 생성된다.

2) prototype은 constructor(생성자)를 참조 가능하다. 이를 통해 해당 함수의 생성자로 생성되는 객체들이 prototype 객체를 상속받게 되며, prototype의 내용을 변경하면 객체들은 변경된 내용을 상속받게 된다.

3) 이 prototype 객체를 참조하는 것은 생성한 객체의 __proto__ 메소드이다.

 

function - __proto__ - prototype 간의 관계

 

공부하다보니 이해가 안가는 부분이 계속 나타나고 있다. 다음 게시글로 이어가도록 하겠다.

반응형
반응형

목차

1. 개요

2. 함수 생성

3. prototype과 __proto__


1. 개요

 OOP(객체 지향 프로그래밍)에서는 객체간의 상속을 프로토타입이라는 메커니즘을 통해 구현한다.

 prototype의 사전적 의미는 원본, 초본이며, 이처럼 수정하지 않은 메소드나 생성자의 '원본'을 상속시키는 역할을 한다.

굉장히 생소해보이지만 프로그래밍 언어를 조금이라도 다뤄본 사람이라면 쉽게 이해가 가능하다.


2. 함수 생성

함수 생성 및 확인

 

F12를 눌러 관리자모드로 들어간 후 a(name)이라는 함수를 정의한다.

a를 출력해보니 위처럼

arguments, caller, length, name, prototype, __proto__가 나오는걸 볼수있다.

 

위의 용어를 하나하나 살펴보자.

용어 의미
arguments(인수) 함수가 호출될 때 함수로 값을 전달해주는 값
parameter(매개변수, 없지만 헷갈릴까봐) 전달받은 argument를 함수 내부로 전달하기위해 사용하는 변수 
caller 현재 함수를 호출한 함수
length 인수의 개수(길이)
name 함수의 이름
prototype 상속시킬 객체의 원형
__proto__ 상속받은 객체

 이 중에서 오늘의 주제인 prototype과 __proto__에 대해 알아보도록 하자.


3. Prototype

 prototype의 사전적 의미는 '원형, 원본'이다. 상속을 받을 때 해당 함수의 원형을 받아야 하기 때문에 prototype이라는 단어를 사용하는 것 같다. 그리고 prototype 객체는 함수를 생성할때 동시에 생성된다. 왜? 언제든 상속시켜줄수있도록 원본을 보존해야하니까.

 

function - prototype 구조

 

function은 prototype이라는 프로퍼티를 사용해 prototype에 새로운 프로퍼티나 메소드를 추가할 수 있고,

prototype은 constructor(생성자)를 사용해 function에 접근할 수 있다.

 

 

 

매개변수(parameter)란 함수의 정의에서 전달받은 인수를 함수 내부로 전달하기 위해 사용하는 변수를 의미합니

 

반응형

+ Recent posts