Mixin Classes
JavaFX supports a form of inheritance called mixin inheritance. To support this, JavaFX includes a special type of class called a mixin. A mixin class is a class that provides certain functionality to be inherited by subclasses. They cannot be instantiated on their own. A mixin class is different from a Java interface in that the mixin may provide default implementations for its functions and also may declare and initialize its own variables.
To declare a mixin class in JavaFX, you need to include the mixin keyword in the class declaration. The following code shows this.
public mixin class Positioner {
A mixin class may contain any number of function declarations. If the function declaration has a function body, then this is the default implementation for the function. For example, the following listing shows a mixin class declaration for a class that positions one node within another.
public mixin class Positioner { protected bound function centerX( node: Node, within: Node) : Number { (within.layoutBounds.width - node.layoutBounds.width)/2.0 - node.layoutBounds.minX; } protected bound function centerY(node: Node, within: Node) : Number { (within.layoutBounds.height - node.layoutBounds.height)/2.0 - node.layoutBounds.minY; } }
Subclasses that want to implement their own version of the mixin function must use the override keyword when declaring the function. For instance, the following code shows a subclass that implements its own version of the centerX() function from the Positioner mixin class.
public class My Positioner extends Positioner { public override bound function centerX(node: Node, within: Node) : Number { (within.boundsInParent.width - node.boundsInParent.width )/2.0; } }
If the mixin function does not have a default implementation, it must be declared abstract and the subclass must override this function to provide an implementation. For instance, the following code shows an abstract function added to the Positioner mixin class.
public abstract function bottomY(node: Node, within: Node, padding: Number) : Number;
The subclass must implement this function using the override keyword, as shown in the following listing.
public class My Positioner extends Positioner { public override function bottomY(node: Node, within: Node, padding: Number) : Number { within.layoutBounds.height - padding - node.layoutBounds.height; } }
If two mixins have the same function signature or variable name, the system resolves to the function or variable based on which mixin is declared first in the extends clause. To specify a specific function or variable, use the mixin class name with the function or variable name. This is shown in the following code.
public class My Positioner extends Positioner, AnotherPositioner { var offset = 10.0; public override bound function centerX(node: Node, within: Node) : Number { Positioner.centerX(node, within) + offset; } }
Mixins may also define variables, with or without default values and triggers. The subclass either inherits these variables or must override the variable declaration. The following listing demonstrates this.
public mixin class Positioner { public var offset: Number = 10.0; } public class My Positioner extends Positioner { public override var offset = 5.0 on replace { println("{offset}"); } }
If a class extends a JavaFX class and one or more mixins, the JavaFX class takes precedence over the mixin classes for variable initialization. If the variable is declared in a superclass, the default value specified in the superclass is used; if no default value is specified in the superclass, the “default value” for the type of that variable is used. For the mixin classes, precedence is based on the order they are defined in the extends clause. If a variable declared in a mixin has a default value, and the variable is overridden without a default value in the main class, the initial value specified in the mixin is used.
Mixins may also have init and postinit blocks. Mixin init and postinit blocks are run after the super class’s init and postinit blocks and before the subclass’s init and postinit blocks. Init and postinit blocks from the mixin classes are run in the order they are declared in the extends clause for the subclass.