記事ディレクトリ
序文
Kotlin の継承は Java の継承と同じですが、違いは Kotlin:
を使用してextends
1. クラス継承
Kotlin はこれを使用して:
継承を表し、Java はそれを使用してexteds
継承を表します。
// 父类Person
open class Person()
// 子类Man
class Man() : Person()
上記は、最も単純な Kotlin 継承の例です。ここで、Kotlin のクラスはデフォルトで final (クラスの継承が許可されていないことを意味します) であり、クラスが他のクラスに継承できることを示すためにキーワードの前に追加する必要があることにも注意してくださいclass
。open
Java と同様に、Kotlin にも単一継承があります。
Java 継承と同様に、サブクラスは親クラスのプロパティとメソッドを使用できます。
open class Person {
var name: String = ""
var age: Int = -1
fun eat(){
println("eat food!")
}
}
class Man() : Person()
fun main() {
val man = Man()
man.age = 22
man.name = "Tom"
println("age is ${
man.age}")
println("name is ${
man.name}")
man.eat()
}
出力結果:
age is 22
name is Tom
eat food!
上記のコードからわかるように、サブクラスは親クラスのプロパティとメソッドをMan
使用できます。Person
2.継承のコンストラクタ
Kotlin での継承の場合、コンストラクタの構文は何ですか? まず、Java がそれを処理する方法を見てみましょう。
2.1 継承における Java コンストラクター
Java は、super
次のコードのように、親クラスのコンストラクターへのアクセスと値の受け渡しを実装します。
// Person类(父类)
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
// Man类(子类)
public class Man extends Person{
public Man(String name, int age) {
super(name, age);
}
}
パラメーターはキーワードを介してsuper
親クラスに渡すことができ、Create constructor matching super
コンストラクターは AndroidStudio をクリックすることで自動的に生成できます。Kotlin がこの問題をどのように処理するかを見てみましょう。
2.2 継承における Kotlin コンストラクター
Kotlin でこの関数を実装するには、ごく少量のコードしか必要ありません。
// Person
open class Person(var name:String, var age:Int) {
// Empty Code
}
// Man类
class Man(name: String, age: Int): Person(name, age) {
// Empty Code
}
fun main() {
val man = Man("Tom", 22)
println("name is ${
man.name} age is ${
man.age}")
}
印刷結果:
name is Tom age is 22
パラメータは Man クラスのコンストラクタを介して渡されname
、親クラスに渡されますage
。後者を追加せずに実行可能ですか?と尋ねる人もいるかもしれません。明らかにそうではありません。クラス コンストラクター はありません。クラス コンストラクターの単なるパラメーターであり、クラスのメンバー変数ではありません。クラスが追加された場合、それは可能ですか?答えはノーなので、親クラスとサブクラスには 2 つのメンバー変数セットがあり、間違いなくエラーが報告されます。ただし、後で詳しく説明する親クラスのメンバー変数をオーバーライドできます。: Person(name, age)
: Person(name, age)
Man
var
Man
Man
var
2.3 Kotlin における複数のコンストラクターの場合
Kotlin には 1 次コンストラクターと 2 次コンストラクターがありますが、親クラスに複数のコンストラクターがある場合、サブクラスはそれをどのように継承しますか?
最初の書き方:
// Person类,这里有三个构造函数
open class Person(var name: String, var age: Int) {
constructor(name: String): this(name, -1)
constructor(age: Int): this("", age)
}
// Man类
class Man(name: String, age: Int) : Person(name, age) {
// Empty Code
}
親クラスが複数のコンストラクタを持つ場合も上記と同様に記述できます。ただし、これにより、オブジェクトが 2 次コンストラクターとして作成されなくなります。
fun main(){
val man = Man("Tom") // 报错!
println("name is ${
man.name} age is ${
man.age}")
}
この理由は、親クラスのプライマリ コンストラクターのみを書き換え、親クラスのセカンダリ コンストラクターを書き換えないためです。この場合、このように書くことができます。上記の例と同じで、コードは次のとおりです。
// Person类,这里有三个构造函数
open class Person(var name: String, var age: Int) {
constructor(name: String): this(name, -1) // 次构造函数
constructor(age: Int): this("", age) // 次构造函数
}
// Man类
class Man: Person {
constructor(name: String, age: Int) : super(name, age) // 对应Person类的主构造函数
constructor(name: String) : super(name) // 对应Person类的constructor(name: String)
constructor(age: Int) : super(age) // 对应Person类的constructor(age: Int)
}
親クラスの 3 つのサブコンストラクターを直接書き換えて、super
親クラスを指すコンストラクターを使用するだけです。
簡単かつ迅速に構築するために、AndroidStudio のショートカット作成方法を使用できます。
まず、クラス内でマウスの右ボタンをクリックすると、次のメニューがポップアップします。
ポップアップ メニューの[生成]ボタンをクリックし、次に次のメニューがポップアップします。
最後に、[セカンダリ コンストラクター]ボタンをクリックして、書き換える必要があるコンストラクターを選択します。
このショートカットを使用すると、親クラスのすべてのプライマリ コンストラクターとセカンダリ コンストラクターをすばやく書き換えることができます。
3. 書き換えとオーバーロード
この章では書き換えに焦点を当てています.オーバーロードについては、以前の記事Kotlin Learning Road (3):
1.3 Summary in Functions を参照してください。
3.1 メソッドの書き換え
コードは上記の例のままですが、親クラスにはもう 1 つのテスト メソッドがあります。
// Person
open class Person(var name:String, var age:Int) {
open fun testMethod(){
// 注意这里加上了open,表示可以被重写。默认情况下是fina
println("父类test!")
}
}
// Man类
class Man(name: String, age: Int): Person(name, age) {
override fun testMethod(){
// 类似Java的override重写标志
println("子类test!")
}
}
fun main(){
val man = Man("Tom", 22)
man.testMethod()
}
出力結果:
子类test!
public final
ここで強調する必要があるのは、特に、修飾子を追加する前の Kotlin のメソッドは常に同じであるため、final
オーバーライドする必要があるメソッドにopen
修飾子を追加することです。
書き換え方法は、同じ2 つ。
- 2 つの同じ: 同じメソッド名、同じパラメーター型
// Person
open class Person(var name:String, var age:Int) {
open fun testMethod(str: String){
println("父类test! $str")
}
}
// Man类
class Man(name: String, age: Int): Person(name, age) {
override fun testMethod(str: String){
println("子类test! $str")
}
}
fun main(){
val man = Man("Tom", 22)
man.testMethod("aaa")
}
- 2 つの小さい: サブクラスの戻り値の型が親クラスの戻り値の型 (戻り値の型の範囲) より小さいか等しい、およびサブクラスによってスローされる例外の型が親クラスのそれより小さいか等しい
// Person
open class Person(var name:String, var age:Int) {
open fun testMethod(): Any?{
println("父类test!")
return null
}
}
// Man类
class Man(name: String, age: Int): Person(name, age) {
override fun testMethod(): String{
println("子类test!")
return "test"
}
}
上記の例では、親クラスのメソッドの戻り値の型はAny?
、サブクラスのメソッドの戻り値の型は となっていますがString
、継承関係から考えると、String
継承の範囲Any?
は当然Any?
より大きくなりますString
。ただし、これは一般的にあまり使用されません。
- 1 つの大きな問題: サブクラスの修飾子のアクセス許可が、親クラスの修飾子のアクセス許可以上であること
// Person
open class Person(var name:String, var age:Int) {
protected open fun testMethod(): Any?{
println("父类test!")
return null
}
}
// Man类
class Man(name: String, age: Int): Person(name, age) {
override fun testMethod(): String {
// 如果这里改为private就会报错
println("子类test!")
return "test"
}
}
3.2 属性の書き換え
プロパティの書き換えは、メソッドの書き換えに似ています。
// Person
open class Person(var name:String, var age:Int) {
open var test = -1 // 和方法一样,加上了open
}
// Man类
class Man(name: String, age: Int): Person(name, age) {
override var test = 0 // 这里加上了override标志
}
fun main(){
val man = Man("Tom", 22)
println("test value is ${
man.test}")
}
出力結果:
test value is 0
test
結果から、親クラスのメンバー変数がサブクラスによって上書きされていることがわかります。一般に、この関数はめったに使用されず、属性を書き換えるとLiskov 置換の原則が破られる可能性があります (サブクラスは親クラスの関数を拡張できますが、親クラスの元の関数を変更することはできません)。
4.スーパーキーワード
Java と同様に、Kotlin にも super キーワードがあります。使用法は Java に似ており、どちらも親クラスを参照し、使用法は Java に似ています。
4.1 簡単な使い方
// Person
open class Person(var name:String, var age:Int) {
// Empty Code
}
// Man类
class Man(name: String, age: Int): Person(name, age) {
fun test(){
println("name is ${
super.name}")
}
}
fun main(){
val man = Man("Tom", 22)
man.test()
}
出力結果:
name is Tom
上記の例は、ズボンを脱いでおならをするようなものですが、実際には取り除くことができますsuper
。その主な機能は、メソッドの書き換えに引き続き使用されます。
4.2 複雑な状況での使用
ここでは、比較的複雑な状況でのsuper
使用法を示します。
4.2.1 サブクラスオーバーライドメソッドでの super の使用
書き換え方法で使用する方法は、super
基本的に Java と同じです。
// Person
open class Person(var name:String, var age:Int) {
open var test = -1
open fun testMethod(){
println("父类test!")
}
}
// Man类
class Man(name: String, age: Int): Person(name, age) {
override var test = 0
override fun testMethod() {
super.testMethod() // 和Java的用法一样,调用父类Person的方法testMethod
println("test value is ${
super.test}") // 调用的是父类Person的test
}
}
fun main(){
val man = Man("Tom", 22)
man.testMethod()
}
出力結果:
父类test!
test value is -1
4.2.2 サブクラスは親インターフェース・親クラスのメソッドを選択的に呼び出す
Kotlin クラスが親クラスと複数のインターフェースを継承する場合、super
親クラスのどのメソッドが呼び出されるかを区別する必要があります。Kotlinでは、super<父类/父接口>.方法
親クラス/インターフェースのメソッドを経由で呼び出す
// Australopithecus接口,写法和Java类似
interface Australopithecus{
fun testMethod(){
println("接口test!")
}
}
// Person
open class Person {
open fun testMethod(){
println("父类test!")
}
}
// Man类,既继承了父类Man,也实现了接口Australopithecus
class Man: Person(), Australopithecus {
override fun testMethod() {
super<Australopithecus>.testMethod()
super<Person>.testMethod()
}
}
fun main(){
val man = Man()
man.testMethod()
}
出力結果:
接口test!
父类test!
4.2.3 サブクラスの内部クラスが親クラスのメソッドを呼び出す
この状況は、サブクラスの内部クラスが親クラスのメソッドを呼び出すというもので、次のように記述されています。super@子类.方法
// Person
open class Person {
open fun testMethod(){
println("父类test!")
}
}
// Man类
class Man: Person() {
// 被inner修饰的内部类是非静态内部类,静态内部类显然不能访问非静态内部类的成员方法
inner class Heart{
fun testMethod(){
super@Man.testMethod()
}
}
}
fun main(){
Man().Heart().testMethod()
}
出力結果:
父类test!
実際、this
内部クラスにも同様の使用法があります。
// Man类
class Man {
fun eat(){
println("eat!")
}
inner class Heart{
fun testMethod(){
this@Man.eat() // 调用外部类的方法,这种操作更加常见
}
}
}
fun main(){
Man().Heart().testMethod()
}
出力結果:
eat!
それがサブクラスでなければならないsuper
かどうかを覚えておいてください!this
@