클래스명과 동일한 이름의 함수로 생성자를 선언합니다. this 키워드는 현재 인스턴스를 나타냅니다. this 키워드는 이름 충돌이 발생하는 경우에만 사용하고 그렇지 않으면 Dart 스타일에서는 생략합니다.
classPoint {double x =0;double y =0;Point(double x, double y) { this.x = x; this.y = y; }}
인스턴스 변수에 생성자 인수를 할당하는 패턴은 매우 일반적이며, Dart는 이를 쉽게해주는 Syntactic sugar를 제공합니다.
classPoint {double x =0;double y =0;// 생성자 바디가 실행되기 전에 x, y변수를 설정해 주는 Syntactic sugar입니다.Point(this.x, this.y);}
기본 생성자
생성자를 선언하지 않으면 암시적으로 기본 생성자(Default constructors)가 제공됩니다. 기본 생성자는 인수가 없으며 슈퍼 클래스의 인수가 없는 생성자를 자동으로 호출합니다. 생성자를 별도로 선언할 경우 기본 생성자는 제공되지 않습니다.
생성자는 상속되지 않습니다.
서브 클래스는 슈퍼 클래스에서 생성자를 상속하지 않습니다. 생자를 선언하지 않는 서브 클래스에는 기본 생성자만 있습니다.
명명된 생성자
명명된 생성자(Named constructors)를 이용해 여러 생성자를 구현하거나 추가적인 명확성을 제공합니다.
constdouble xOrigin =0;constdouble yOrigin =0;classPoint {double x =0;double y =0;Point(this.x, this.y);// 명명된 생성자Point.origin(): x = xOrigin, y = yOrigin;}
생성자는 상속되지 않기 때문에 슈퍼 클래스에 정의된 명명된 생성자로 서브 클래스를 생성하려면 서브 클래스에서 해당 생성자를 구현해야 합니다.
기본이 아닌 슈퍼 클래스 생성자 호출
기본적으로 서브 클래스의 생성자는 슈퍼 클래스의 기본 생성자를 자동으로 호출합니다. 슈퍼 클래스의 생성자는 생성자 본문의 시작 부분에서 호출됩다. 초기화 목록(Initializer list)을 사용하는 경우에는 슈퍼 클래스의 생성자가 호출되기 전 에 초기화 목록이 실행됩니다.
초기화 목록 실행
슈퍼 클래스의 인수가 없는 생성자 실행
기본 클래스의 인수가 없는 생성자 실행
슈퍼 클래스에 기본 생성자가 없는 경우 슈퍼 클래스의 생성자 중 하나를 수동으로 호출해야 합니다. 생성자 선언 뒤에 :을 입력하고 슈퍼 클래스 생성자를 지정할 수 있습니다.
classPerson {String? firstName;Person.fromJson(Map data) {print('in Person'); }}classEmployeeextendsPerson {// Person 클래스는 기본 생성자가 없으므로 반드시 super.fromJson(data)를 호출해야 합니다.Employee.fromJson(Map data) : super.fromJson(data) {print('in Employee'); }// 생성자 바디에서 슈퍼 클래스 생성자를 호출하는 방법은 지원하지 않습니다.// Employee.fromJson(Map data) {// super.fromJson(data);// }}voidmain() {var employee =Employee.fromJson({});print(employee);}<출력결과>inPersoninEmployeeInstance of 'Employee'
슈퍼 클래스 생성자에 대한 인수는 생성자를 호출하기 전에 평가되기 때문에 슈퍼 클래스 생성자의 인수는 함수 호출과 같은 표현식도 가능합니다.
import'dart:math';classPoint {finaldouble x;finaldouble y;finaldouble distanceFromOrigin;// 초기화 목록을 사용해 3개의 final 인스턴스 변수를 초기화 합니다.Point(double x, double y): x = x, y = y, distanceFromOrigin =sqrt(x * x + y * y);}voidmain() {var p =Point(2, 3);print(p.distanceFromOrigin);}
생성자 리디렉션
가끔은 생성자의 목적이 같은 클래스의 다른 생성자를 호출하는 것일수 있습니다. 생성자 리디렉션은 생성자 선언 뒤에 :을 붙이고 this 키워드를 이용해 인자를 넘기는 형태로 다른 생성자를 호출합니다.
classPoint {double x, y;// 메인 생성자입니다.Point(this.x, this.y);// 메인 생성자에 위임합니다.Point.alongXAxis(double x) : this(x, 0);}
상수 생성자
클래스가 불변(Immutability) 객체를 생성하는 경우 이 객체를 컴파일 타임 상수로 만들 수 있습니다. 생성자 선언 앞에 const를 붙이고 모든 인스턴스 변수를 final로 만들면 객체를 만들 수 있습니다.
생성자 사용에서 살펴본 것처럼 상수 생성자를 사용해도 인스턴스 생성 시 변수로 생성했다면 컴파일 타임 상수가 아닙니다.
팩터리 생성자
객체를 재사용 하는 등 항상 새 인스턴스가 필요하지 않은 상황에서는 factory 키워드를 사용하세요. 예를 들어 캐시에서 인스턴스를 반환하거나 하위 타입의 인스턴스를 반환할 수 있습니다. 팩터리 생성자의 다른 사용 사례로 초기화 목록에서 처리할 수 없는 로직을 이용해 final 변수를 초기화 할 수도 있습니다.
아래 코드의 Logger 팩터리 생성자는 캐시에서 객체를 반환하고 Logger.fromJson 팩터리 생성자는 final 변수를 초기화 합니다.
classLogger {finalString name;bool mute =false;// _cache is library-private, thanks to// the _ in front of its name.staticfinalMap<String, Logger> _cache =<String, Logger>{};factoryLogger(String name) {return _cache.putIfAbsent(name, () =>Logger._internal(name)); }factoryLogger.fromJson(Map<String, Object> json) {returnLogger(json['name'].toString()); }Logger._internal(this.name);voidlog(String msg) {if (!mute) print(msg); }}voidmain() {var logger =Logger('UI'); logger.log('Button clicked');var logMap = {'name':'UI'};var loggerJson =Logger.fromJson(logMap);print("logger == loggerJson ? ${identical(logger, loggerJson)}");}