dimanche 19 novembre 2017

String.intern() returning different values in a JDBC driver

Whilst I was trying to make a fake JDBC driver to test a secure classloader I found an odd behaviour with the following code:

val stringClass = java.lang.String::class.java
val intern = stringClass.getMethod("intern")
val pooledString = intern.invoke("Hello World") as String
val valueField = stringClass.getDeclaredField("value")
valueField.isAccessible = true
val pooledValue = valueField.get(pooledString) as ByteArray
println(
        """|----------------------------------------
           | String: ${System.identityHashCode(stringClass)}
           | Thread: ${Thread.currentThread()}
           | Pooled: ${System.identityHashCode(pooledString)}
           | Internal: ${System.identityHashCode(pooledValue)}
           |----------------------------------------""".trimMargin()
)
for (index in pooledValue.indices) {
    pooledValue[index] = 'X'.toByte()
}

Running the above code from a JDBC driver's companion object gives this:

String: 349885916
Thread: Thread[main,5,main]
Pooled: 718231523
Internal: 1349414238

but running the same code from a method of the test class before loading the JDBC driver (during the same execution of the program) gives this:

String: 349885916
Thread: Thread[main,5,main]
Pooled: 1635756693
Internal: 504527234

I would have thought that getting the interned version of the string should have given the same string in both cases, but it seems that even within the same run of the program the 2 locations give different values for String.intern, which conflicts with the javadoc which says:

When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.

Is this to be expected, and if so why is it that the values differ?





Aucun commentaire:

Enregistrer un commentaire