Classes and Inheritance
class
Declaring a class using the keyword class in Kotlin
Class Invoice {
}
A class declaration consists of a class name, a class header (specifying its type parameter, a main constructor, and so on) and a class body surrounded by curly braces. Both the class head and the class body are optional, and if a class does not have a class body, the curly braces can be omitted.
Class Empty
constructor Function
A class in Kotlin can have one primary constructor and one or more secondary constructors. The main constructor is part of the class header: It follows the class name (and optionally the type parameter).
Class person Constructor (firstname:string) {
}
If the primary constructor does not have any annotations or visibility modifiers, you can omit the constructor keyword.
Class Person (firstname:string) {
}
The main constructor cannot contain any code. The initialized code can be placed in an initialization block (initializer blocks) prefixed with the INIT keyword:
Class Customer (name:string) {
init {
logger.info ("Customer initialized with value ${name}")
}
}
Note that the parameters of the main construct can be used in the initialization block. They can also be used in a property initializer declared within a class:
Class Customer (name:string) {
val customerkey = Name.touppercase ()
}
In fact, Kotlin has a concise syntax for declaring properties and initializing properties from the main constructor:
Class Person (Val firstname:string, Val lastname:string, var age:int) {
//...
}
As with normal properties, the attributes declared in the main constructor can be variable (VAR) or read-only (Val).
If the constructor has annotations or visibility modifiers, this constructor keyword is required, and these modifiers precede it:
Class Customer public @Inject constructor (name:string) {...}
Secondary constructor
The constructor class can also declare a secondary constructor with a prefix:
Class Person {
Constructor (Parent:person) {
Parent.children.add (this)
}
}
If a class has a primary constructor, each secondary constructor needs to be delegated to the main constructor, either directly or indirectly through another secondary constructor. Another constructor that delegates to the same class is used with the This keyword:
Class Person (Val name:string) {
constructor (name:string, Parent:person): This (name) {
Parent.children.add ( This)
}
}
If a non-abstract class does not declare any (primary or secondary) constructors, it will have a generated primary constructor without parameters. The visibility of the constructor is public. If you do not want your class to have a public constructor, you need to declare an empty primary constructor with non-default visibility:
Class Dontcreateme Private Constructor () {
}
Note: On the JVM, if all parameters of the primary constructor have default values, the compiler generates an additional parameterless constructor that will use the default values. This makes it easier for Kotlin to use libraries such as Jackson or JPA to create instances of classes through the parameterless constructor.
Class Customer (val customername:string = "")
to create an instance of a class
To create an instance of a class, we call the constructor like a normal function:
Val invoice = Invoice ()
val customer = Customer ("Joe Smith")
Note that Kotlin does not have the new keyword.
Nested classes
Classes can be nested within other classes
Class Outer {
private val bar:int = 1
class Nested {fun
foo () = 2
}
}
val demo = outer.nested (). Foo ()//= = 2
Inner class
A class can be marked as inner to be able to access members of an external class. The inner class will have a reference to an object of the external category:
Class Outer {
private val bar:int = 1
inner class Inner {fun
foo () = Bar
}
}
val demo = Outer ( ). Inner (). Foo ()//= = 1
See the qualified this expression for the disambiguation usage of this in the inner class.
Anonymous inner class
To create an anonymous inner class instance using an object expression:
Window.addmouselistener (Object:mouseadapter () {
override fun mouseclicked (e:mouseevent) {
//...
}
Override Fun Mouseentered (e:mouseevent) {
//...
}
})
If the object is an instance of a functional Java interface (that is, a Java interface with a single abstract method), you can create it using a lambda expression with an interface-type prefix:
Val Listener = actionlistener {println ("clicked")}
Class Member
Classes can contain constructors and initialization block function properties nested classes and Inner class object declaration inheritance
In Kotlin, all classes have a common superclass of any, which is the default superclass for classes that do not have a super-type declaration:
Class Example//implicitly inherit from any
Any is not a java.lang.Object; In particular, it has no members except Equals (), Hashcode (), and ToString (). Refer to the Java Interoperability section for more details.
To declare an explicit super-type, we put the type after the colon of the class header:
Open Class Base (P:int)
class Derived (p:int): Base (P)
If the class has a primary constructor, its base type can (and must) be initialized in-place with the main constructor parameter (the base type).
If the class does not have a primary constructor, each secondary constructor must initialize its base type with the Super keyword, or delegate to another constructor to do so. Note that in this case, different secondary constructors can call different constructors of the base type:
Class Myview:view {
constructor (Ctx:context): Super (CTX)
Constructor (Ctx:context, Attrs:attributeset): Supe R (CTX, Attrs)
}
The open callout on the class is opposite to final in Java, which allows other classes to inherit from this class. By default, all of the classes in Kotlin are final.
Override method
As we have mentioned before, Kotlin strives for clarity and explicit expression. Unlike Java, Kotlin needs to explicitly label the members that can be overwritten (which we call Open) and the members after they are overwritten:
Open Class Base {
Open Fun V () {} ' Fun
NV () {}
} '
class Derived (): Base () {
override Fun V () {}
}}
The override callout must be added to the DERIVED.V () function. If not written, the compiler will error. If the function does not label open such as BASE.NV (), a function that defines the same signature is not allowed in the subclass, regardless of the addition of override. Open members are forbidden in a final class (classes that are not labeled with open).
The member marked as override is itself open, that is, it can be overridden in a subclass. If you want to prohibit overwriting again, use the final keyword:
Open Class anotherderived (): Base () {
final override fun V () {}
}
overriding properties
Property overrides are similar to method overrides, and properties that are declared in a superclass and then re-declared in a derived class must start with override, and they must have compatible types. The properties of each claim can be overridden by properties that have initializers or properties that have getter methods.
Open Class Foo {
open val x:int get {...}
}
Class Bar1:foo () {
override Val X:int = ...
}
You can also overwrite a Val attribute with a var attribute, but not vice versa. This is allowed because a Val attribute essentially declares a getter method, and overwriting it as Var simply declares an additional setter method in the subclass.
Note that you can use the Override keyword in the main constructor as part of the property declaration.
interface Foo {
val count:int
}
class Bar1 (override Val count:int): Foo
class Bar2:foo {
override var count:int = 0
}
Override Rule
In Kotlin, implementation inheritance is governed by the following rules: If a class inherits multiple implementations of the same member from its immediate superclass, it must override this member and provide its own implementation (perhaps one of them with inheritance). In order to represent the implementation from which the superclass inherits, we use the super, which is qualified by the superclass name in angle brackets, such as super:
Open Class A {
open fun f () {print ("a")} Fun
A () {print ("a")}
}
interface B {fun
f () {print ("B" }///interface member default is "open" fun
B () {print ("B")}
}
class C (): A (), B {
//compiler requires override F ():
override Fun F () {
super<a>.f ()//Call A.F ()
super<b>.f ()//Call B.F ()
}
}
Inheriting A and b at the same time is not a problem, and a () and B () are also not problematic because C inherits only one implementation of each function. But F () inherits two implementations from C, so we have to cover F () in C and provide our own implementations to disambiguate.
Abstract class
A class and some of its members can be declared abstract. Abstract members may not be implemented in this class. It is important to note that we do not need to annotate an abstract class or function with open.
We can overwrite a non-abstract open member with an abstract member.
Open Class Base {
open fun F () {}
}
abstract class Derived:base () {
override abstract fun F ()
}
Interface
The Kotlin interface is similar to Java 8, containing both the declaration of the abstract method and the implementation. Unlike an abstract class, an interface cannot hold a state. It can have properties but must be declared as abstract or provide an accessor implementation.
Use keyword interface to define interfaces
Interface MyInterface {fun
bar () Fun
foo () {
//optional method Body
}
}
Implementing interfaces
A class or object can implement one or more interfaces.
Class Child:myinterface {
override Fun bar () {
//method body
}
}
Properties in the interface
You can define properties in the interface. Properties declared in an interface are either abstract or provide an implementation of accessors. Properties declared in an interface cannot have behind-the-scenes fields (backing field), so accessors declared in an interface cannot reference them.
Interface MyInterface {
val prop:int//abstract
val propertywithimplementation:string
get () = "foo" Fun
foo () {
print (prop)
}
}
class Child:myinterface {
override val Prop:int = $
}
Resolve Overwrite Conflicts
When you implement multiple interfaces, you may encounter an issue in which the same method inherits multiple implementations. For example
Interface A {fun
foo () {print ("A")} Fun
bar ()
}
interface B {fun
foo () {print ("B")}
Fu N Bar () {print ("Bar")}
}
class C:a {
override Fun bar () {print ("Bar")}
}
class D:a, B {
override Fun foo () {
super<a>.foo ()
Super<b>.foo ()
}
override Fun Bar () {
Super<b>.bar ()
}
}
In the example above, interfaces A and B both define the method foo () and bar (). Both implement Foo (), but only B implements Bar () (bar () is not marked abstract in A, because the default is abstract when there is no method body. Because C is a concrete class that implements a, you must rewrite bar () and implement this abstract method.
However, if we derive d from A and B, we need to implement all of the methods we inherit from multiple interfaces and indicate how D should implement them. This rule applies both to methods that inherit a single implementation (bar ()) and to methods that inherit multiple implementations (foo ()).
generic type
Similar to Java, classes in Kotlin can have type parameters:
Class Box<t> (t:t) {
var value = T
}
In general, to create an instance of such a class, we need to provide the type parameter:
Val box:box<int> = box<int> (1)
However, if the type parameter can be inferred, such as from the arguments of the constructor or from other means, the omitted type parameter is allowed:
Val box = box (1)//1 has type Int, so the compiler knows we're talking about box<int>.
More Introduction to Generics
Enum class
The most basic use of enum classes is to implement type-safe enumeration
Enum class Direction {North
, South, WEST, EAST
}
Each enumeration constant is an object. Enumeration constants are separated by commas.
Initialization
Because each enumeration is an instance of an enumeration class, they can be initialized.
Enum Class Color (Val rgb:int) {
RED (0xFF0000),
GREEN (0x00FF00),
BLUE (0x0000FF)
}
Anonymous class
Enumeration constants can also declare their own anonymous classes
Enum class Protocolstate {
waiting {
override fun signal () = Talking
},
talking {
override fun signal () = Waiting
};
Abstract Fun Signal (): Protocolstate
}
and corresponding methods, as well as methods to cover the base class. Note that if the enumeration class defines any members, use semicolons to separate the enumeration constant definitions in the member definition, as in Java.
Using enumeration constants
As in Java, the enumeration classes in Kotlin also have synthetic methods that allow you to list the enumerated constants you define and get enumerated constants by name. The signatures of these methods are as follows (assuming the name of the enumeration class is Enumclass):
Enumclass.valueof (value:string): Enumclass
enumclass.values (): array<enumclass>
If the specified name does not match any of the enumeration constants defined in the class, The ValueOf () method throws a IllegalArgumentException exception.
From Kotlin 1.1, you can use the EnumValues () and enumvalueof () functions to access constants in the enumeration class in a generic manner:
Enum class RGB {RED, GREEN, BLUE}
inline Fun <reified t:enum<t>> printallvalues () {
print (Enumvalu Es<t> (). jointostring {it.name})
}
printallvalues<rgb> ()//Output RED, GREEN, BLUE
Each enumeration constant has a property that gets its name and location in the enumeration class declaration:
Val name:string
Val ordinal:int
Enumeration constants also implement the comparable interface, in which the natural order is the order in which they are defined in the enumeration class.