Search code examples
stringkotlincollectionsany

Any vs Nested Concrete type in Kotlin Collections


is using Any as collection type consume less memory than using concrete type?

suppose

val list1 = listOf<Any>("ABC", "DEF", "GHI", "JKL", "MNO")
val list2 = listOf<String>("ABC", "DEF", "GHI", "JKL", "MNO")

i wonder if list1 consume less memory than list2 since String type allocates memory to store its properties (e.g size)

So, is it better to use list1 if i dont use any String type function?


EDIT

what if i want to use other type in the collection?

list = listOf<Any>("ABC", 123, 12.34)

is it more efficient than

list = listOf<String>("ABC", "123", "12.34")



EDIT 2
thanks to @João Dias and @gidds

as @gidds says :

the list does not directly contain String objects, or Any objects — it contains references.

And a String reference is exactly the same size as an Any reference or a reference of any other type. 

So, The List<String> and List<Any> are the exactly the same because of the Type Erasure --which pointed out by @João Dias-- with a difference of compile-time & runtime type

but, does it mean that

val list1 = listOf<Any>("ABC", "DEF", "GHI")

and

val list2 = listOf<String>("ABC", "DEF", "GHI")

is consuming the same memory as

val list3 = listOf<List<List<List<String>>>>(
listOf(listOf(ListOf("ABC"))), 
listOf(listOf(ListOf("DEF"))), 
listOf(listOf(ListOf("GHI")))
)

AFAIK, String is basically collections of Char. A String contains a reference to the Char. And since everything is an object in Kotlin, then every Char inside the String should contain a reference to the value in the heap, am i correct up to here?

if thats the case, doesnt it make sense that List<String> consume more memory than List<Any> because List<String> is having more than 1 reference.


Solution

  • A point not addressed so far is that the list does not directly contain String objects, or Any objects — it contains references.

    And a String reference is exactly the same size as an Any reference or a reference of any other type. (That size depends on the internals of the JVM running the code; it might be 4 or 8 bytes. See these questions.)

    Of course, the objects being referred to will also take up their own space in the heap; but that will be the same in both cases.


    EDITED TO ADD:

    The internal details of how List and String are implemented is irrelevant to the original question. (Which is good, coz they vary between implementations.) JVM languages (such as Kotlin) have only two kinds of value: primitives (Int, Short, Long, Byte, Char, Double, Float, Boolean), and references (to an object or an array).

    So any collection, if it's not a collection of primitives, is a collection of references. That applies to all List implementations. So your list1 and list2 objects will be exactly the same size, depending only on the number of references they hold (or can hold), not on what's in those references.

    If you want a deeper picture, list1 is a reference, pointing to an object which implements the List interface. There are many different implementations, and I don't know off-hand which one Kotlin will pick (and again, that might change between versions), but say for example it's an ArrayList. That has at least two properties: a size (which is probably an Int), and a reference to an array which holds the references to the items in the list. (The array will usually be bigger than the current size of the list, so that you can add some more items without having to re-allocate the array each time; the current size of the array is known as the list's capacity.) If those items are Strings, then the exact internal representation depends on the JVM version, but it might be an object with at least three properties: an array of Char, an Int giving the start index of the string within the array, and another Int giving either the length.

    But as I said, the details change over time and between JVM versions. What doesn't change is that List is a collection of references, and the size of a reference doesn't depend on its type. So a list of String references will (all other things being equal) take exactly the same space as a list of Any references to those same strings.

    (And, as has been mentioned elsewhere, due to type erasure at runtime the JVM has no concept of type parameters, and so the objects will in fact be identical.)

    Of course, the ‘deep size’ (the overall heap space taken up by the list and the objects it contains) will depend upon the size of those objects — but in the case we're discussing, those are the exact same String objects, so there's no difference in size there either.