Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
24
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

@mura40424

JavaとKotlinにおける変性

前から気になっていたJavaの変性について、調べたことを自分の中で簡単にまとめて置きたくて。
プラスして、最近好きな言語であるKotlinと比較してみようかなと。
まだまだ勉強中の身であるため、間違いがあったら申し訳ありません。

不変

同じ型でなければなりません。

Java

Javaにおける不変はList<T>

List<String> strList = new ArrayList<String>();
List<Object> objList = strList; //コンパイルエラー  不変のため代入できない

Javaでの配列は次項の共変になります。

Kotlin

Javaとは異なり、配列がこれになります。
また、KotlinではlistOfarrayListOf,mutableListOfでJavaにおけるリストを用意することができます。

//配列
val intArray: Array<Int> = arrayOf(1,2)
val numArray: Array<Any?> = intArray //コンパイルエラー 共変ではないため

//リスト
val strList: java.util.ArrayList<String> = arrayListOf("1st", "2nd")

因みに余談ですが、Array<Int>型を定義したが、Kotlinでは型ごとの配列も用意できるみたいです。

val intArray: IntArray = intArrayOf(3,4)

共変

広い定義に狭い定義のものを入れることが出来ます。

Java

Javaでの共変は配列上限付き境界ワイルドカードがあります。
String型はObject型のサブクラスであるため、それぞれ以下の様に書くことが出来ます。

//配列
String[] strArray = {"hoge", "foo"};
Object[] objArray = strArray;

//上限付き境界ワイルドカード
List<String> strList = new ArrayList<String>();
List<? extends Object> objList = strList;

しかし、上記の様に全てのスーパークラスであるObject型で定義するとJavaの配列では、

objArray[0] = 1; //ランタイムエラー

このようにString型配列の中に、それ以外を入れてもコンパイルは通り、ランタイムエラーとなります。
リストの方は、String型であろうとObject型であろうとaddメソッドで加えることは出来ませんが、getメソッドでString型やObject型を取得することはできます。
(nulladdすることはできます)

Kotlin

Kotlinではout修飾子によって共変を実現しています。
そしてJavaの配列のときと異なり、出力のみ可能とすることで安全に扱うことができます。

val intArray: Array<Int> = arrayOf(1,2)
val numArray: Array<out Any?> = intArray
numArray[0] = 1 //コンパイルエラー

反変

共変の逆になります。

Java

Javaでの反変には下限付き境界ワイルドカードがあります。
Object型はString型のサブクラスを持っているので、以下の様に書くことが出来ます。

//下限付き境界ワイルドカード
List<Object> objList = new ArrayList<Object>();
List<? super String> strList = objList;

下限付きになることで、この場合String型とそのサブクラスをaddメソッドで加えることが可能となります。nulladd出来ます。
逆にgetメソッドで取得出来るのは全てのスーパークラスであるObject型のみになります。

kotlin

Kotlinではin修飾子によって反変を実現しています。
共変とは逆に入力のみ可能となっており、出力はできません。

fun main(args: Array<String>) {
    var hoge = Hoge(1) 
    val hogeList: java.util.ArrayList<Hoge> = arrayListOf(hoge)
    val fooList: java.util.ArrayList<in Foo> = hogeList  //反変だから代入できる

    val foo = fooList[0]

    println(hoge == foo) // true
    println(hoge.a)  //1が出力される
    println(foo.a)  //コンパイルエラー
}
open class Hoge(val a: Int)
class Foo: Hoge(0)
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
24
Help us understand the problem. What are the problem?