Пул Java String и приведение типов - PullRequest
10 голосов
/ 26 марта 2012

Мой вопрос касается того, как Java обрабатывает строковые литералы.Из спецификаций языка Java (JLS) совершенно ясно, что литералы String неявно интернируются - иными словами, объекты, которые создаются в части пула констант String, в отличие от объектов на основе кучи, создаваемых при вызове new String("whatever").

То, что не согласуется с тем, что говорит JLS, заключается в том, что при создании новой строки с использованием конкатенации строк с приведенным константным типом строки, который следует рассматривать как постоянную строку согласно JLSочевидно, JVM создает новый объект String, а не скрывает его.Я ценю любые объяснения относительно этого конкретного поведения и того, является ли это поведением, специфичным для платформы.Я работаю на Mac OSX Snow Leopard.

public class Test
{
    public static void main(String args[])
    {
        /*
            Create a String object on the String constant pool
            using a String literal
        */
        String hello = "hello";
        final String lo = "lo"; // this will be created in the String pool as well
        /*
            Compare the hello variable to a String constant expression
            , that should cause the JVM to implicitly call String.intern()
        */
        System.out.println(hello == ("hel" + lo));// This should print true
        /*
            Here we need to create a String by casting an Object back
            into a String, this will be used later to create a constant
            expression to be compared with the hello variable
        */
        Object object = "lo";
        final String stringObject = (String) object;// as per the JLS, casted String types can be used to form constant expressions
        /*
            Compare with the hello variable
        */
        System.out.println(hello == "hel" + stringObject);// This should print true, but it doesn't :(

    }
}

Ответы [ 2 ]

6 голосов
/ 26 марта 2012

Приведение к Object не допускается в выражении постоянной времени компиляции. Разрешены только приведения к String и примитивам. JLS (Java SE 7 edition) раздел 15.28:

> - Приведение к примитивным типам и приведение к типу String

(На самом деле есть вторая причина. object не final, поэтому не может рассматриваться как константная переменная . "Переменная примитивного типа или типа String, то есть final и инициализируется константным выражением во время компиляции (§15.28), называется постоянной переменной. "- раздел 4.12.4.)

3 голосов
/ 26 марта 2012

Похоже, что здесь вы ссылаетесь на объект final String stringObject = (String) object;, это больше не константа времени компиляции, а константа времени выполнения.Первый пример из здесь ускользает от него с частью:

String s = "lo";
String str7 = "Hel"+ s;  
String str8 = "He" + "llo"; 
System.out.println("str7 is computed at runtime.");     
System.out.println("str8 is created by using string constant expression.");    
System.out.println("    str7 == str8 is " + (str7 == str8));  
System.out.println("    str7.equals(str8) is " + str7.equals(str8));

Строка str7 вычисляется во время выполнения, потому что она ссылается на другую строку, которая не является литералом, поэтому по этой логикеЯ предполагаю, что, несмотря на то, что вы делаете stringObject final, он все еще ссылается на объект, поэтому не может быть вычислен во время компиляции.

А из спецификации java lang здесь он заявляет:

"Оператор конкатенации строк + (§15.18.1) неявно создает новый объект String, когда результат не является константным выражением времени компиляции (§15.28)."

Я не могу найтилюбые примеры, где можно использовать приведение, за исключением этого ужасного, ужасного примера:

System.out.println(hello == "hel" + ( String ) "lo");

, который вряд ли имеет какое-либо логическое применение, но, возможно, часть о приведении строки была включена из-за вышеприведенного случая.

...