抽象クラスとインターフェースについて、
やっと納得できた!!!(はず)
今まで調べて雰囲気理解して見様見真似で使用して、また調べて...を繰り返してた...(抽象クラスに限ったことではないけど)
なので記録として残しておく![]()
これで全然違うよって思ったら、教えてください。お願いします。
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/