Edited at

Kotlin覚書 - コード編(その1)

More than 1 year has passed since last update.

Kotlin覚書。前回の続きです。

前回は環境構築の構築について書きました。

そして、Java -> Kotlinについては色々な人が書いてますね。

僕はググったらまずはこの方の投稿があったので参考にさせてもらいました。

KogarasiさんのAndroid開発ではじめるKotlin

しかしながら、読んだだけじゃイマイチピンとこないので、

とにかく触ってみるべしということで、

触ってみてどんなもんかを書いていきます。

※間違った解釈等があるかもしれませんのでそれについてはご指摘ください・・・。


クラスを作る

まぁまずはクラスを作ってみましょう。

- 1. AppCompatActivityを継承

- 2. View.OnClickListenerOnClickListenerを実装

 


Java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

}



kotlin

open class MainActivity : AppCompatActivity() , View.OnClickListener {

}



  • classの前の「open」

  • extendsとimplementsの記述がなくなった


open修飾子

まず「open」について。

このopenが付いているクラスは継承できるクラスになります。

openをつけない場合、そのクラスは継承できなくなります。

今までのpublic, private, protectedの3つの可視性が、

openがあるかないかの2通りになったって覚えれば良さそうな気がします。


abstarct修飾子は?

今回は書いてないですが、abstract修飾子を付ける場合は、


kotlin

abstract open class HogeClazz {

}


と、openの前につけます。

確認したところ、抽象クラスの場合はどうやらopenはつけなくても継承できるみたいです。

▼継承元の抽象クラス


kotlin

abstract class AbstractSample {

abstract fun aaa() : Boolean
}

▼継承先のクラス


kotlin

open class ExtendsClazz : AbstractSample() {

override fun aaa() : Boolean {
return false;
}
}

抽象クラスで作ってんだから、普通は継承するだろうって感じなんですかね?

試してみたらclassの前にprivateをつけることはできるみたいです。

ようするに可視性の設定はできるんです。

で、あればさっきのopenを可視性の3パターンの中に組み込んじゃうっていうコメントは解釈としてはよろしくなさそうです。

open -> 継承できる

open -> 継承できない

って単純に覚えておくだけにしておきます。

それにしても、privateなクラスってなんだろう。

privateなクラスのアクセスはどこまで可能なのかを見てみないといけないですね。。

それについてはまた後日・・・


interface

 インターフェースはどんな感じの記述になるんでしょう。

見てみましょう。


java

public interface IBaseListener {

void onSuccess();
void onError(String message, Throwable e);
}


kotlin

interface IBaseListener {

fun onSuccess()
fun onError(message: String, e: Throwable)
}

殆ど変わらないですね。

ちなみにinterfaceにもopen修飾子をつけることができます。

openがついてるついてないで実装ができるできないは関係ないようですが。


インナークラス

まずは特に何も継承も実装もしていないインナークラスです。

引数にコンテキストと文字列を渡して、それを保持するだけのクラスにしましょう。


java

    private class InnerClass {

private Context mContext;
private String mString;

public InnerClass(final Context context, final String str) {
mContext = context;
mString = str;
}
}



kotlin

    private inner class InnerClass(private val mContext: Context, private val mString: String)


随分短くなりました。

パーツ毎に見れそうです。


インナークラスの定義

Javaでは、特に明示的に記載していませんでしたが、Kotlinでは

「わたくし、インナークラスを書きます!いいですか?書きますよーーーー!!!」

と言わんばかりに「inner class」と書く必要があるようです。

private inner class InnerClass


クラス名の後の()

なんか()があります。

Javaのときは特についてないこれは一体何なのか。

一旦コンバートする前のJavaとコンバートした後のKotlinを比較してみましょう。


Java

    private class InnerClass {

private Context mContext;
private String mString;

public InnerClass(final Context context, final String str) {
mContext = context;
mString = str;
}
}


private inner class InnerClass(private val mContext: Context, private 

val mString: String)

二回も載せちゃいましたがw、要するにコンストラクタを省略できるようです。

が、これってコンストラクタでmContextとmStringに値を入れてるからこういう記述になるんじゃなかろうか?

試してみましょう。

コンストラクタでは特に何もやらずに、initializeメソッドを追加してそこでmContextとmStringに値を入れるようにしてみます。


java

    private class InnerClass {

private Context mContext;
private String mString;

public InnerClass() {
}

public void initialize(final Context context, final String str) {
mContext = context;
mString = str;
}
}



kotlin

    private inner class InnerClass {

private var mContext: Context? = null
private var mString: String? = null

fun initialize(context: Context, str: String) {
mContext = context
mString = str
}
}


なるほど。

ようするに、コンストラクタを使う場合はこんな感じで()で処理できるんですね!

・・・もしコンストラクタでsuperとか呼ぶ場合はどうなるんでしょう????

試してみましょう。

インナークラスに、Viewを継承させて、コンストラクタを2つ用意したものをKotlinで表示してみます。


java

    private class InnerClass extends View {

private Context mContext;
private AttributeSet mAttr;

public InnerClass(Context context) {
super(context);
mContext = context;
}

public InnerClass(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mContext = context;
mAttr = attrs;
}
}



kotlin

   private inner class InnerClass : View {

private var mContext: Context? = null
private val mAttr: AttributeSet

constructor(context: Context) : super(context) {
mContext = context
}

constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
mContext = context
mAttr = attrs
}
}


おお!!!

「constructor」って書くんですね。「:」の後ろにsuperを呼び出していて、

カッコの中でそれ以外の処理を書くみたいです。

今までと違う癖があるみたいですね。これは覚えておく必要がありそうです。

ちなみにコンストラクタが一つの場合はまた記述が違ってました。

一つの場合だと


kotlin

private inner class InnerClass(private val mContext: Context) : View(mContext) {

}

コンストラクタの記述が省略できるようです。

// 追記

ちょっと気になって、調べてみましたが、これはインナークラスに限ったことじゃなかったです。。。

なので、通常のどのクラスに対してもこの記述が当てはめられます。


kotlin

open class HogeClass(private val mContext: Context) : View(mContext) {

}

のように、Viewを継承したクラスを生成した場合も同様の記述になります。

さて、先程


試してみたらclassの前にprivateをつけることはできるみたいです。


と前述しましたが、おそらく、多分おそらくなんですが、このインナークラスのために用意されている可視性なのではなかろうかと。

もう少し進めていかないとここらへんは理解できないのかもしれませんが。。。


変数と定数

変数と定数について見ていきます。


java

    private static final int TEISU_INT = 0;

private static final String TEISU_STRING = "hoge";
private Context mContext;
private View mView;


kotlin

    private val mContext: Context? = null

private val mView: View? = null

companion object {
private val TEISU_INT = 0
private val TEISU_STRING = "hoge"
}



変数

まずは変数の解説をしていきましょう。

private val hoge: String? = null


valとvar


private val ←こいつ


これはJavaでいうところのfinal修飾子と同じ役割です。


java

final String strHoge = "hoge";

strHoge = "huga";     ★代入できないからコンパイルエラー

String strHuga = "hoge";
strHuga = "huga";    ★代入できる


Kotlinだとこうです。


kotlin

val strHoge: String? = "hoge";

strHoge = "huga";     ★代入できないからコンパイルエラー

var strHuga: String? = "hoge";
strHuga = "huga";    ★代入できる


わざわざ書くほどのことでもない。。


オブジェクトの定義


hoge : String ←こいつ


この部分です。

Javaの場合と指定の順番が逆なので、Kotlin書き始めは毎回

「あ・・・またやっちゃった」

ってなりますw

今まではオブジェクトの指定→変数名だったのが、変数名が先になりました。

これは何故かというと、Kotlinだとオブジェクトの指定が必須ではなくなったからです。

つまり、型推論での定義が可能になったということです。

そのため


kotlin

var hoge = null


もちろんOKです。

ただ、今までJavaやってた人にとってはこれってほんときついなーと。

何入れてんのか、何に使うものかわからない。hogeなんて変数名だと余計に。

なので、今後どう使っていくのかは僕もわからないですが、普通に

1. varかval

2. 変数名

3. オブジェクトを指定

っていう書き方でいいんじゃないかと思います。


オブジェクトの後ろの「?」


: String  ←こいつ


これはなにか。

JavaでいうところのNonNullアノテーション、Nullableアノテーションと同じと解釈しました。

とりあえず、「?」ありなしの挙動です。


kotlin

var str1: String?

str = null     ★これは?つけてNullableなのでnull代入OK

var str2: String
str = null     ★これは?なくてNoneNullなのでnull代入NG


この?指定はswift開発者で言わせるところの「オブショナル型」「非オプショナル型」と言われるものに相当すると思っています。

swiftやってる人にしては、もう慣れっこなのかもしれないですが、Android開発でJavaをずっとやってた人には馴染みがなさすぎるので少々受け入れるのに時間がかかるかもしれないです。

ここらへんの扱いについては、また別途記事にしてきちんと整理していきたいと思います。


定数

続いて定数です。

書き方が大幅に変わってるので、とりあえず指定の仕方さえ覚えちゃえばいいのかなと思います。

もう一度コード書いておきます。


kotlinでの定数定義

    companion object {

private val TEISU_INT = 0
private val TEISU_STRING = "hoge"
}

companionで翻訳かけちゃいました。。

「同士」って感じなんですかね??

image.png

ちなみに、privateだと他のクラスからは参照はもちろんできなくて、

privateなしだと参照可能でした。public扱いってことですね。

protectedなんて可視性はなくなってるみたいで、指定できませんでした。


kotlinでの定数定義

    companion object {

private val TEISU_INT = 0  ←他クラスからの参照不可
val TEISU_STRING = "hoge" ←他クラスからの参照可
}

とりあえず、クラスを作って、それから変数定義して・・・・っていう入り口の部分を一旦記載しました。

あ、「;(セミコロン)」を命令の最後につけるとコンパイルエラーになるので癖でつけちゃうとは思いますが、要注意です。

他のことも色々と書くことはありますが、ひとまずここまでにしておきます。

あと、kotlinについてサンプル見たい場合はここ見るといいかもです。

https://try.kotlinlang.org/