当前位置:网站首页>[flutter 1-11] dart language -- class, member variable and method of class, construction of class

[flutter 1-11] dart language -- class, member variable and method of class, construction of class

2020-12-06 10:28:29 osc_ rezr8v4k

author | Vlad
source | Vlad ( official account :fulade_me)

class

Dart It's an object-oriented language , All objects are instances of a class , And all classes inherit from Object class . Every one except Object Classes other than classes have only one superclass , The code of one class can be reused in the inheritance of other classes .

Class instance variables

Here is an example of declaring an instance variable :

class Point {
  double x; //  Statement  double  Variable  x  And initialize to  null.
  double y; //  Statement  double  Variable  y  And initialize to  null
  double z = 0; //  Statement  double  Variable  z  And initialize to  0.
}

All uninitialized instance variables have values of null.

All instance variables implicitly declare a Getter Method , Not final An instance variable of type also implicitly declares a Setter Method

class Point {
  double x;
  double y;
}

void main() {
  var point = Point();
  point.x = 4; //  Use  x  Of  Setter  Method .
  assert(point.x == 4); //  Use  x  Of  Getter  Method .
  assert(point.y == null); //  The default value is  null.
}

If you initialize an instance variable when you declare it ( Not in constructors or other methods ), Then the value of the instance variable will be set when the object instance is created , This procedure is done before the constructor and its initializer list are executed .

Accessing members of a class

Objects are composed of functions and data ( Methods and instance variables ) form . Methods are called through objects , In this way, you can access the functions and data of objects .
Use . To access an instance variable or method of an object :

var p = Point(2, 2);
//  obtain  y  value 
assert(p.y == 2);
//  Call variables  p  Of  distanceTo()  Method .
double distance = p.distanceTo(Point(4, 4));

Use ?. Instead of . You can avoid that because the expression on the left is null And the resulting problems :

// If p is non-null, set a variable equal to its y value.
var a = p?.y;
Method

Methods are functions of objects that provide behavior .

Object can access instance variables and this. Below distanceTo() Method is an example of an instance method :

import 'dart:math';

class Point {
  double x, y;

  Point(this.x, this.y);

  double distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx * dx + dy * dy);
  }
}
Override class members

Subclasses can override instance methods of the parent class ( Including operators )、 Getter as well as Setter Method . You can use @override Comments to indicate that you have rewritten a member :

class SmartTelevision extends Television {
  @override
  void turnOn() {...}
  // ···
}
noSuchMethod Method

If a method or instance variable that does not exist in the object is called, it will trigger noSuchMethod Method , You can rewrite noSuchMethod Methods to track and record this behavior :

class A {
  //  Unless you rewrite  noSuchMethod, Otherwise, calling a nonexistent member will result in  NoSuchMethodError.
  @override
  void noSuchMethod(Invocation invocation) {
    print(' You try to use a member that doesn't exist :' + '${invocation.memberName}');
  }
}

You cannot call an unimplemented method unless one of the following conditions is met :

  • The receiver is static dynamic type .
  • The receiver has a static type , Defines an unimplemented method , And the dynamic type of the receiver implements noSuchMethod Method and the concrete realization and Object Different in .

Class static variables and static methods

Use keywords static You can declare class variables or class methods .

Static variables

Static variables ( The class variables ) It is often used to declare state variables and constants within the scope of a class :

class Queue {
  static const initialCapacity = 16;
  // ···
}
void main() {
  assert(Queue.initialCapacity == 16);
}

Static variables are initialized when they are first used .

Static methods

Static methods ( That is, class method ) Cannot be accessed by an instance of a class , similarly , Keywords are not allowed in static methods this

import 'dart:math';
class Point {
  double x, y;
  Point(this.x, this.y);
  static double distanceBetween(Point a, Point b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
  }
}

void main() {
  var a = Point(2, 2);
  var b = Point(4, 4);
  var distance = Point.distanceBetween(a, b);
  assert(2.8 < distance && distance < 2.9);
  print(distance);
}

Use constructors to build objects

You can use the constructor to create an object . Constructors can be named by class name or class name . The form of the identifier . For example, the following code uses Point() and Point.fromJson() Two constructors to create Point object :

var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});

The following code has the same effect , Before the constructor name new Keywords are optional :

var p1 = new Point(2, 2);
var p2 = new Point.fromJson({'x': 1, 'y': 2});

Some classes provide constant constructors . Use constant constructors , Add... Before the constructor name const keyword , To create compile time constants :

var p = const ImmutablePoint(2, 2);

Two compile time constants constructed with the same constructor and the same parameter value are the same object :

var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);

assert(identical(a, b)); //  They are the same example  (They are the same instance!)

Depending on the scenario where constant context is used , You can omit before constructors or literals const keyword . For example, in the following example, we create a constant Map

//  There's a lot of  const  keyword 
const pointAndLine = const {
  'point': const [const ImmutablePoint(0, 0)],
  'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
};

According to context , You can just keep the first one const keyword , Leave out the rest :

//  Just one  const  keyword , Others are implicitly related according to context .
const pointAndLine = {
  'point': [ImmutablePoint(0, 0)],
  'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
};

But if you can't judge whether it can be omitted according to the context const, You can't omit const keyword , Otherwise it will create a Not Constant object for example :

var a = const ImmutablePoint(1, 1); //  Create a constant  (Creates a constant)
var b = ImmutablePoint(1, 1); //  It doesn't create a constant 
assert(!identical(a, b)); //  These two variables are not the same  

Get the type of object

have access to Object Object's runtimeType Property gets the type of an object at run time , The object type is Type Example .

var = Point(2, 2);
print('The type of a is ${a.runtimeType}');

Constructors

You can declare a constructor by declaring a function that is the same as the class name ( For named constructors You can also add additional identifiers ). Most constructors take the form of generative constructors , It is used to create an instance of a class :

class Point {
  double x, y;
  Point(double x, double y) {
    //  There will be better ways to implement this logic , Coming soon .
    this.x = x;
    this.y = y;
  }
}

Use this Keyword references the current instance .
For most programming languages, the process of assigning an instance variable in a constructor is similar , and Dart A special grammar sugar is provided to simplify the procedure :

class Point {
  double x, y;
  //  Used to set before the constructor body is executed  x  and  y  The grammar sugar of .
  Point(this.x, this.y);
}
Default constructor

If you don't declare a constructor , that Dart The constructor without a parameter is automatically generated by the constructor of the method .

Constructors are not inherited

Subclasses do not inherit the constructor of the parent class , If the subclass does not declare a constructor , Then there will only be a default parameterless constructor .

Named constructors

You can declare multiple named constructors for a class to express a more explicit intent :

class Point {
  double x, y;

  Point(this.x, this.y);

  //  Named constructors 
  Point.origin() {
    x = 0;
    y = 0;
  }
}

Constructors cannot be inherited , This means that subclasses cannot inherit the named constructor of the parent class , If you want to provide a named constructor in a subclass with the same name as the parent named constructor , You need to explicitly declare .

Call the non default constructor of the parent class

By default , The constructor of the subclass will call the anonymous parameterless constructor of the parent class , And the call will be made before the function body code of the subclass constructor is executed , If the subclass constructor also has an initialization list , Then the initialization list will be executed before calling the constructor of the parent class , in general , The order of these three calls is as follows :

  1. Initialization list
  2. The parameterless constructor of the parent class
  3. The constructor of the current class

If the parent class does not have an anonymous parameterless constructor , Then the subclass must call one of the constructors of the parent class , To specify a parent class constructor for a subclass constructor, just use it in front of the constructor body : Appoint .

Because parameters are passed to the constructor of the parent class before the subclass constructor is executed , So the parameter can also be an expression , Like a function :

class Employee extends Person {
  Employee() : super.fromJson(defaultData);
  // ···
}
Initialization list

In addition to calling the parent constructor , You can also initialize instance variables before the constructor body is executed . Each instance variable is separated by a comma .

//  Use the initialization list to set instance variables before the constructor body is executed .
Point.fromJson(Map<String, double> json)
    : x = json['x'],
      y = json['y'] {
  print('In Point.fromJson(): ($x, $y)');
}

In development mode , You can use... In the initialization list assert To verify the input data :

Point.withAssert(this.x, this.y) : assert(x >= 0) {
  print('In Point.withAssert(): ($x, $y)');
}
Redirect constructor

Sometimes constructors in a class call other constructors in the class , The function has no constructor for redirecting body , Just use... After the function signature : Specify other constructors that need to be redirected to :

class Point {
  double x, y;

  //  Primary constructor of this class .
  Point(this.x, this.y);

  //  Delegate to the main constructor .
  Point.alongXAxis(double x) : this(x, 0);
}
Constant constructors

If the objects generated by the class will not change , You can make these objects compile time constants when they are generated . You can add const Keyword and make sure that all instance variables are final To achieve this function .

class ImmutablePoint {
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);

  final double x, y;

  const ImmutablePoint(this.x, this.y);
}

An instance created by a constant constructor is not always a constant .

Factory constructor

Use factory Keyword identifies the constructor of a class, which makes it a factory constructor , This means that using this constructor to construct an instance of a class does not always return a new instance object . for example , The factory constructor may return an instance from the cache , Or return an instance of a subtype .

In the following example ,Logger The factory constructor for returns the object from the cache , and Logger.fromJson Factory constructors are derived from JSON Object to initialize a final variable .

class Logger {
  final String name;
  bool mute = false;

  // _cache  Variables are library private , Because there is an underline in front of its name .
  static final Map<String, Logger> _cache =
      <String, Logger>{};

  factory Logger(String name) {
    return _cache.putIfAbsent(
        name, () => Logger._internal(name));
  }

  factory Logger.fromJson(Map<String, Object> json) {
    return Logger(json['name'].toString());
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}

Factory constructors are called in the same way as other constructors :

var logger = Logger('UI');
logger.log('Button clicked');

var logMap = {'name': 'UI'};
var loggerJson = Logger.fromJson(logMap);

abstract class

Use keywords abstract Identifying a class can make it an abstract class , Abstract classes will not be instantiated . Abstract classes are often used to declare interface methods 、 Sometimes there are specific ways to implement . If you want an abstract class to be instantiated at the same time , You can define a factory constructor for it .

Abstract classes often contain abstract methods . Here is an example of an abstract class that declares that it has abstract methods :

//  The class is declared abstract , So it can't be instantiated .
abstract class AbstractContainer {
  //  Define the constructor 、 Field 、 Such method ……
  void updateChildren(); //  Abstract method .
}

Implicit interface

Each class implicitly defines an interface and implements it , This interface contains all instance members of this class and other interfaces implemented by this class . If you want to create a A Class supports calling B Class API And don't want to inherit B class , Then you can achieve B Class interface .

A class can be used by keyword implements To implement one or more interfaces and implement the defined API:

// Person  Class contains  greet()  Method .
class Person {
  // _name  Variables are also contained in the interface , But it's only visible in the library .
  final _name;

  //  The constructor is not in the interface .
  Person(this._name);

  // greet()  Methods in the interface .
  String greet(String who) => ' Hello ,$who. I am a $_name.';
}

// Person  An implementation of the interface .
class Impostor implements Person {
  get _name => '';

  String greet(String who) => ' Hello $who. Do you know who I am? ?';
}

String greetBob(Person person) => person.greet(' Xiaofang ');

void main() {
  print(greetBob(Person(' Rue  ')));
  print(greetBob(Impostor()));
}

If you need to implement multiple class interfaces , You can use commas to separate each interface class :

class Point implements Comparable, Location {

}

Extend a class

Use extends Keyword to create a subclass , And can use super Keyword refers to a parent class :

class Television {
  void turnOn() {
    _illuminateDisplay();
    _activateIrSensor();
  }
}
class SmartTelevision extends Television {
  void turnOn() {
    super.turnOn();
    _bootNetworkInterface();
    _initializeMemory();
    _upgradeApps();
  }
}

Use Mixin Add functionality to the class

Mixin It is a method pattern of reusing code in a class in multiple inheritance .
Use with Keywords and keep up with Mixin Class name to use Mixin Pattern :

class Musician extends Performer with Musical {
  // ···
}

class Maestro extends Person
    with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}

Define a class to inherit from Object And no constructors are defined for this class , This class is Mixin class , Unless you want it to be used as normal as a normal class , Otherwise, you can use keywords mixin replace class Let it be a simple Mixin class :

mixin Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}

Keywords can be used on To specify which classes can use this Mixin class , Such as the Mixin class A, however A Can only be B Class uses , You can define `A:

class Musician {
  // ...
}
mixin MusicalPerformer on Musician {
  // ...
}
class SingerDancer extends Musician with MusicalPerformer {
  // ...
}

Extension Method

Dart 2.7 Introduced in Extension Method is a way to add functionality to an existing library .
Here's the one in String Use in extension Examples of methods , We call it parseInt(), It's in string_apis.dart In the definition of :

extension NumberParsing on String {
  int parseInt() {
    return int.parse(this);
  }

  double parseDouble() {
    return double.parse(this);
  }
}

And then use string_apis.dart Inside parseInt() Method

import 'string_apis.dart';
print('42'.padLeft(5)); // Use a String method.
print('42'.parseInt()); // Use an extension method.

 official account

版权声明
本文为[osc_ rezr8v4k]所创,转载请带上原文链接,感谢
https://chowdera.com/2020/12/20201206102803625i.html