Kotlin覚書。前回の続きです。
前回は環境構築の構築について書きました。
そして、Java -> Kotlinについては色々な人が書いてますね。
僕はググったらまずはこの方の投稿があったので参考にさせてもらいました。
KogarasiさんのAndroid開発ではじめるKotlin
しかしながら、読んだだけじゃイマイチピンとこないので、
とにかく触ってみるべしということで、
触ってみてどんなもんかを書いていきます。
※間違った解釈等があるかもしれませんのでそれについてはご指摘ください・・・。
クラスを作る
まぁまずはクラスを作ってみましょう。
- 1. AppCompatActivityを継承
- 2. View.OnClickListenerOnClickListenerを実装
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
}
open class MainActivity : AppCompatActivity() , View.OnClickListener {
}
- classの前の「open」
- extendsとimplementsの記述がなくなった
open修飾子
まず「open」について。
このopenが付いているクラスは継承できるクラスになります。
openをつけない場合、そのクラスは継承できなくなります。
今までのpublic, private, protectedの3つの可視性が、
openがあるかないかの2通りになったって覚えれば良さそうな気がします。
abstarct修飾子は?
今回は書いてないですが、abstract修飾子を付ける場合は、
abstract open class HogeClazz {
}
と、openの前につけます。
確認したところ、抽象クラスの場合はどうやらopenはつけなくても継承できるみたいです。
▼継承元の抽象クラス
abstract class AbstractSample {
abstract fun aaa() : Boolean
}
▼継承先のクラス
open class ExtendsClazz : AbstractSample() {
override fun aaa() : Boolean {
return false;
}
}
抽象クラスで作ってんだから、普通は継承するだろうって感じなんですかね?
試してみたらclassの前にprivateをつけることはできるみたいです。
ようするに可視性の設定はできるんです。
で、あればさっきのopenを可視性の3パターンの中に組み込んじゃうっていうコメントは解釈としてはよろしくなさそうです。
open -> 継承できる
open -> 継承できない
って単純に覚えておくだけにしておきます。
それにしても、privateなクラスってなんだろう。
privateなクラスのアクセスはどこまで可能なのかを見てみないといけないですね。。
それについてはまた後日・・・
interface
インターフェースはどんな感じの記述になるんでしょう。
見てみましょう。
public interface IBaseListener {
void onSuccess();
void onError(String message, Throwable e);
}
interface IBaseListener {
fun onSuccess()
fun onError(message: String, e: Throwable)
}
殆ど変わらないですね。
ちなみにinterfaceにもopen修飾子をつけることができます。
openがついてるついてないで実装ができるできないは関係ないようですが。
インナークラス
まずは特に何も継承も実装もしていないインナークラスです。
引数にコンテキストと文字列を渡して、それを保持するだけのクラスにしましょう。
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)
随分短くなりました。
パーツ毎に見れそうです。
インナークラスの定義
Javaでは、特に明示的に記載していませんでしたが、Kotlinでは
「わたくし、インナークラスを書きます!いいですか?書きますよーーーー!!!」
と言わんばかりに「inner class」と書く必要があるようです。
private inner class InnerClass
クラス名の後の()
なんか()があります。
Javaのときは特についてないこれは一体何なのか。
一旦コンバートする前のJavaとコンバートした後のKotlinを比較してみましょう。
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に値を入れるようにしてみます。
private class InnerClass {
private Context mContext;
private String mString;
public InnerClass() {
}
public void initialize(final Context context, final String str) {
mContext = context;
mString = str;
}
}
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で表示してみます。
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;
}
}
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を呼び出していて、
カッコの中でそれ以外の処理を書くみたいです。
今までと違う癖があるみたいですね。これは覚えておく必要がありそうです。
ちなみにコンストラクタが一つの場合はまた記述が違ってました。
一つの場合だと
private inner class InnerClass(private val mContext: Context) : View(mContext) {
}
コンストラクタの記述が省略できるようです。
// 追記
ちょっと気になって、調べてみましたが、これはインナークラスに限ったことじゃなかったです。。。
なので、通常のどのクラスに対してもこの記述が当てはめられます。
open class HogeClass(private val mContext: Context) : View(mContext) {
}
のように、Viewを継承したクラスを生成した場合も同様の記述になります。
さて、先程
試してみたらclassの前にprivateをつけることはできるみたいです。
と前述しましたが、おそらく、多分おそらくなんですが、このインナークラスのために用意されている可視性なのではなかろうかと。
もう少し進めていかないとここらへんは理解できないのかもしれませんが。。。
変数と定数
変数と定数について見ていきます。
private static final int TEISU_INT = 0;
private static final String TEISU_STRING = "hoge";
private Context mContext;
private View mView;
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修飾子と同じ役割です。
final String strHoge = "hoge";
strHoge = "huga"; ★代入できないからコンパイルエラー
String strHuga = "hoge";
strHuga = "huga"; ★代入できる
Kotlinだとこうです。
val strHoge: String? = "hoge";
strHoge = "huga"; ★代入できないからコンパイルエラー
var strHuga: String? = "hoge";
strHuga = "huga"; ★代入できる
わざわざ書くほどのことでもない。。
オブジェクトの定義
hoge : String ←こいつ
この部分です。
Javaの場合と指定の順番が逆なので、Kotlin書き始めは毎回
「あ・・・またやっちゃった」
ってなりますw
今まではオブジェクトの指定→変数名だったのが、変数名が先になりました。
これは何故かというと、Kotlinだとオブジェクトの指定が必須ではなくなったからです。
つまり、型推論での定義が可能になったということです。
そのため
var hoge = null
もちろんOKです。
ただ、今までJavaやってた人にとってはこれってほんときついなーと。
何入れてんのか、何に使うものかわからない。hogeなんて変数名だと余計に。
なので、今後どう使っていくのかは僕もわからないですが、普通に
- varかval
- 変数名
- オブジェクトを指定
っていう書き方でいいんじゃないかと思います。
オブジェクトの後ろの「?」
: String ? ←こいつ
これはなにか。
JavaでいうところのNonNullアノテーション、Nullableアノテーションと同じと解釈しました。
とりあえず、「?」ありなしの挙動です。
var str1: String?
str = null ★これは?つけてNullableなのでnull代入OK
var str2: String
str = null ★これは?なくてNoneNullなのでnull代入NG
この?指定はswift開発者で言わせるところの「オブショナル型」「非オプショナル型」と言われるものに相当すると思っています。
swiftやってる人にしては、もう慣れっこなのかもしれないですが、Android開発でJavaをずっとやってた人には馴染みがなさすぎるので少々受け入れるのに時間がかかるかもしれないです。
ここらへんの扱いについては、また別途記事にしてきちんと整理していきたいと思います。
定数
続いて定数です。
書き方が大幅に変わってるので、とりあえず指定の仕方さえ覚えちゃえばいいのかなと思います。
もう一度コード書いておきます。
companion object {
private val TEISU_INT = 0
private val TEISU_STRING = "hoge"
}
companionで翻訳かけちゃいました。。
「同士」って感じなんですかね??
ちなみに、privateだと他のクラスからは参照はもちろんできなくて、
privateなしだと参照可能でした。public扱いってことですね。
protectedなんて可視性はなくなってるみたいで、指定できませんでした。
companion object {
private val TEISU_INT = 0 ←他クラスからの参照不可
val TEISU_STRING = "hoge" ←他クラスからの参照可
}
とりあえず、クラスを作って、それから変数定義して・・・・っていう入り口の部分を一旦記載しました。
あ、「;(セミコロン)」を命令の最後につけるとコンパイルエラーになるので癖でつけちゃうとは思いますが、要注意です。
他のことも色々と書くことはありますが、ひとまずここまでにしておきます。
あと、kotlinについてサンプル見たい場合はここ見るといいかもです。
https://try.kotlinlang.org/