Help us understand the problem. What is going on with this article?

JavaとKotlinにおける変性

More than 3 years have passed since last update.

前から気になっていた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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした