void main() {
TimesTwo tt = TimesTwo(2);
print(tt.calculate());
TimesFour tf = TimesFour(2);
print(tf.calculate());
}
class TimesTwo {
final int number;
TimesTwo(
this.number,
);
int calculate() {
return number * 2;
}
void sayHello() {
print('Hello, everyone!');
}
}
class TimesFour extends TimesTwo {
TimesFour(
int number,
) : super(number);
int calculate() {
return 4 * super.number;
}
void sayHello() {
super.sayHello();
print('Good-bye');
}
}
이 Dart 프로그램은 두 개의 클래스 TimesTwo
와 TimesFour
를 정의하고 main()
함수에서 이들을 사용하여 결과를 출력합니다.
override는 덮어쓰다, 우선시하다라는 사전적 의미를 지니고 있습니다. @override 표기가 필수는 아니나 코딩 컨벤션을 준수하기 위하여 쓰는 것이 좋습니다.
TimesTwo
클래스final int number
: 생성자를 통해 초기화되는 정수 값.calculate()
: number
에 2를 곱한 결과를 반환하는 메소드.sayHello()
: 콘솔에 "Hello, everyone!"라는 메시지를 출력하는 메소드.TimesFour
클래스TimesFour
는 TimesTwo
를 상속받습니다.calculate()
: 오버라이드된 메소드로, 부모 클래스의 number
필드에 4를 곱한 값을 반환합니다.sayHello()
: 오버라이드된 메소드로, 부모 클래스의 sayHello()
메소드를 호출한 후, 콘솔에 "Good-bye"라는 메시지를 추가로 출력합니다.main()
함수TimesTwo
객체 tt
를 생성하고 2
를 인자로 전달합니다. calculate()
메소드를 호출하면 4
를 출력합니다. (2 * 2 = 4
)TimesFour
객체 tf
를 생성하고 2
를 인자로 전달합니다. calculate()
메소드를 호출하면 8
을 출력합니다. (4 * 2 = 8
)tt.sayHello()
를 호출하면 "Hello, everyone!"가 출력됩니다.tf.sayHello()
를 호출하면 "Hello, everyone!"와 "Good-bye"가 차례로 출력됩니다. 이는 TimesFour
클래스에서 sayHello()
메소드를 오버라이딩하면서 super.sayHello()
를 호출함으로써 부모 클래스의 sayHello()
메소드도 실행되도록 했기 때문입니다.결과적으로, 이 프로그램을 실행하면 다음과 같은 출력을 볼 수 있습니다.
4
8
Hello, everyone!
Hello, everyone!
Good-bye
여기서 주목할 점은 TimesFour
클래스에서 calculate()
메소드를 오버라이딩할 때, 부모 클래스의 calculate()
메소드를 호출하는 대신 super.number
를 사용하여 부모 클래스의 number
필드에 직접 접근하고 있다는 것입니다. 이렇게 함으로써 TimesFour
클래스는 부모 클래스의 calculate()
로직을 무시하고, 자신의 로직으로 완전히 대체합니다.
calculate() {
return 4 * super.number;
}
int
calculate() {
return 4 * this.number;
}
int
calculate() {
return 4 * number;
}
int
this.number
나 단순히 number
를 사용하는 것이 가능한 이유는, 현재 인스턴스, 즉 TimesFour
클래스의 인스턴스에 number
필드가 존재하기 때문입니다. 이 필드는 TimesTwo
클래스에서 상속받은 것입니다.
this.number
: this
키워드는 현재 인스턴스를 참조합니다. 따라서 this.number
는 현재 인스턴스의 number
필드를 참조하게 됩니다. TimesFour
인스턴스에서는 number
필드가 직접 정의되어 있지 않고 상속받은 TimesTwo
의 필드를 사용하고 있기 때문에, this.number
는 상속받은 number
필드를 참조하게 됩니다.
number
: 클래스 내부에서 필드나 메소드를 참조할 때, this
키워드를 생략할 수 있습니다. 따라서 단순히 number
라고 쓰면, 이는 this.number
와 같은 의미가 됩니다. 이 경우 역시 상속받은 number
필드를 참조하게 됩니다.
super.number
와 this.number
(또는 단순히 number
)는 다른 의미를 가질 수 있습니다. super.number
는 명시적으로 부모 클래스의 number
필드를 참조하라는 것을 의미합니다. 반면, this.number
또는 number
는 현재 클래스 인스턴스의 number
필드를 참조합니다. 상속받은 필드인 경우 이 둘은 같은 필드를 참조하지만, 만약 TimesFour
클래스 안에서 number
필드를 새로 정의했다면, this.number
또는 number
는 TimesFour
클래스의 number
필드를, super.number
는 TimesTwo
클래스의 number
필드를 참조하게 됩니다.
void main() {
TimesTwo tt = TimesTwo(2);
print(tt.calculate());
TimesFour tf = TimesFour(2);
print(tf.calculate());
}
class TimesTwo {
final int number;
TimesTwo(
this.number,
);
int calculate() {
return number * 2;
}
}
class TimesFour extends TimesTwo {
TimesFour(
int number,
) : super(number);
int calculate() {
return 4 * super.calculate();
}
}
TimesFour
클래스의 calculate()
메소드는 TimesTwo
클래스의 calculate()
메소드를 호출하고, 그 결과에 4를 곱합니다.
이 프로세스는 다음과 같습니다:
TimesFour
클래스의 calculate()
메소드가 호출됩니다.super.calculate()
를 통해 TimesTwo
클래스의 calculate()
메소드가 호출되고, 입력받은 숫자 2에 2를 곱한 값인 4를 반환합니다.그러므로 tf.calculate()
의 결과는 16이 됩니다.