抽象クラスとインターフェースについて、
やっと納得できた!!!(はず)
今まで調べて雰囲気理解して見様見真似で使用して、また調べて...を繰り返してた...(抽象クラスに限ったことではないけど)
なので記録として残しておく
これで全然違うよって思ったら、教えてください。お願いします。
1.抽象クラスと抽象メソッド
抽象クラスとは
・継承されることを目的としたクラス
・インスタンス化できないクラス(抽象的であるので具体化は無理)
抽象メソッドとは
・中身の実装ができないメソッド
・抽象クラスを使用したクラスは、強制的に使うことになる
定義方法
abstract class Engine(name:String){
var engineName = name
abstract fun speed():Int
fun breake(){
}
}
・"abstract"を先頭に付ける("open"は不要)
・コンストラクタを設定できる
・プロパティに値を持てる
・抽象的なものには先頭に"abstract"を付ける
・通常のメソッドも、抽象メソッドも定義可能
・抽象メソッドはパラメータと戻り値の型の指定はできるが中身の実装はできない
抽象クラスを継承する方法
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Car().speed()
}
//抽象クラスと抽象関数
abstract class Engine(name:String){
var engineName = name
abstract fun speed():Int
}
//エンジン抽象クラスを継承するクラス
class Car():Engine("ferrari"){
var speedResult = 0
override fun speed(): Int {
if ( engineName== "ferrari" ){
speedResult = 100
Log.d("speed",speedResult.toString())
return speedResult
}
speedResult = 30
Log.d("speed",speedResult.toString())
return speedResult
}
}
結果:100
・クラス名の後に":抽象クラス名()"
・抽象的なもの(abstractつけたやつ)は、overrideして使用
・抽象メソッドの中身はここで具体的に使いたいように記述
注意点
class Car():Engine("ferrari"){
val engineClass = Engine("a")
}
・抽象クラスはインスタンス化できない
(エラー:Cannot create an instance of an abstract class)
abstract class Engine(name:String){
abstract fun speed():Int
}
abstract class Brake(){
}
Class Car():Engine("ferrari"),brake(){
}
・多重継承はできない
(エラー:Only one class may appear in a supertype list)
class Car():Engine("ferrari"){
//抽象クラスで定義した抽象関数をコメントアウト
//override fun speed(): Int {
// if ( engineName== "ferrari" ){
// speedResult = 100
// return speedResult
// }
// speedResult = 30
// return 30
// }
}
・抽象メソッドは必ずoverrideする
(エラー:Class 'Car' is not abstract and does not implement abstract base class member)
2.インターフェース
インターフェースとは
・異なる種類のクラス同士に共通した処理がある時、共通項として定義しておける
・継承して使われるものではあるけど、異なる種類のクラスでも継承が許される
定義方法
interface Write{
val helloString:String
fun print(){
val hello = helloString
Log.d("inter",hello)
}
}
・"interface"をインターフェースの前につける
・"open"や"abstract"は不要
・プロパティの定義はできるが、ゲッターなしでは値を持てない
val helloString:String
get() = "Hello"
インターフェースを継承する方法
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Job().print()
}
}
interface Write{
val helloString:String
fun print(){
val hello = helloString
Log.d("printer",hello)
}
}
class Job():Write{
override val helloString: String
get() = "ハロー"
override fun print() {
super.print()
}
}
結果:ハロー
・クラス名の後に":インターフェース名"
・抽象的なものはoverride(プロパティやメソッド)
注意点
interface Write(string:String){}
・コンストラクタはもてない
(エラー:An interface may not have a constructor)
3.抽象クラスとインターフェースの違い
まずは私自身が一番納得できた違いについて。
抽象クラスは、
継承されることを目的に作られたクラス。
インターフェースは、
異なる種類のクラスでも継承が許された定義的なやつ。
私は継承って部分についても知識があいまいなので、記録
・スーパークラス(継承元)を拡張したクラスが継承先のクラスである
・サブクラス(継承先)はスーパークラスの一部である
などと書いてあるのでそんな関係性なんだと思う。
炭酸クラスと紅茶クラスはどちらも飲料クラスを継承しています。的な...
じゃあ異なる種類のサブクラスたちが同じ機能を持ちたい!
ってなったときは?ってなると思うんだけど、
そんなときにはインターフェース。
炭酸クラスと車クラスは全く関係のないクラス同士ではあるけど、
”量をはかる”という共通点があったらそれはインターフェースを利用して
一部分だけ共有しようね。的な..?
違い
・抽象クラスはabstractが必要だが、インターフェースは不要
・抽象クラスは多重継承不可、インターフェースは可
・抽象クラスはプロパティに値をもてる、インターフェースはゲッターが必要
・抽象クラスはコンストラクタを持てる、インターフェースは持てない
・抽象クラスは継承先が同系統のクラス、インターフェースは異なる系統でも可
(抽象クラスは継承のためのクラスだと考えると、継承とは継承先は継承元の一部であるとなるから)
共通点
・インスタンス化できない
・openが不要
・抽象的なものは継承先クラスでオーバーライド
まとめ
抽象クラスインターフェースの前に継承について、
あんまりよくわかってなかった(今も怪しいかもしれないけど、前よりはマシと願う)
だから書き方の違いはいろいろ記事見たらわかるけど、腑に落ちなかったのかも。
使い分けどうしたら良いんだろう...?
こんな時はみんなインターフェース使ってるっぽいから真似しとこ...とかってなってた。
他にもなあなあにしてることあるから、潰していきたいです。
というかこの記事も正しいかは分からないけど、とりあえず今の自分の解釈ということで
参考記事
①https://pouhon.net/kotlin-interface/3357/
②https://kotlin-study.com/abstractclass-interface/