简体   繁体   中英

why this java code can work but kotlin code can't

public class Generics2 {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        List<Integer> list = new ArrayList<>();

        list.add(12);
//这里直接添加会报错
        Class<? extends List> clazz = list.getClass();
        Method add = clazz.getDeclaredMethod("add", Object.class);
//但是通过反射添加是可以的
//这就说明在运行期间所有的泛型信息都会被擦掉
        add.invoke(list, "kl");
        System.out.println(list);
        System.out.println(list.get(0));
        System.out.println(list.get(1));
    }
}

This code can work. but when I convert this to kotlin. It can't work and throw Exception.Why? I just konw kotlin code has CHECKCAST java/lang/Number , but why java code doesn't have? Is this a special strategy of kotlin?

object Generics {
    @Throws(NoSuchMethodException::class, InvocationTargetException::class, IllegalAccessException::class)
    @JvmStatic
    fun main(args: Array<String>) {
        val list: MutableList<Int> = ArrayList()
        list.add(12)
        //这里直接添加会报错
//        list.add("a");
        val clazz: Class<out MutableList<*>?> = list.javaClass
        val add = clazz.getDeclaredMethod("add", Any::class.java)
        //但是通过反射添加是可以的
//这就说明在运行期间所有的泛型信息都会被擦掉
        add.invoke(list, "kl")
        println(list)
        println(list[0])
        println(list[1])
        println(list.get(1))
    }
}
[12, kl]
12
Exception in thread "main" java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')
    at Generics.main(Generics.kt:22)

from https://www.baeldung.com/kotlin/generics

6.1. Type Erasure As with Java, Kotlin's generics are erased at runtime. That is, an instance of a generic class doesn't preserve its type parameters at runtime. For example, if we create a Set and put a few strings into it, at runtime we're only able to see it as a Set. Let's create two Sets with two different type parameters: val books: Set<String> = setOf("1984", "Brave new world") val primes: Set<Int> = setOf(2, 3, 11) At runtime, the type information for Set and Set will be erased and we see both of them as plain Sets. So, even though it's perfectly possible to find out at runtime that value is a Set, we can't tell whether it's a Set of strings, integers, or something else: that information has been erased.

So, how does Kotlin's compiler prevent us from adding a Non-String into a Set? Or, when we get an element from a Set, how does it know the element is a String? The answer is simple. The compiler is the one responsible for erasing the type information but before that, it actually knows the books variable contains String elements. So, every time we get an element from it, the compiler would cast it to a String or when we're gonna add an element into it, the compiler would type check the input.

so, it is additional security feature introduced by kotlin compiler

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM