Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > изменение класс-мембера во время проверки


Автор: CompWorm 4.12.2014, 03:09
привет. 
всё же с трудом у меня после c++ перевариваются java поинтеры...
Код

public class AAA
{
    private String aaa;
    
    public AAA(String aaa)
    {
        this.aaa=aaa;
    }
    public String getModd()
    {
        aaa = "hello";
        return aaa;
    }
    
    public boolean compr()
    {
        return aaa.equals(getModd());
    }
    
    public boolean compr2()
    {
        String bbb = getModd();
        return aaa.equals(bbb);
    }
}

    public static void main(String[] args)
    {
        AAA a = new AAA("world");
        System.out.println(a.compr());
        
        AAA b = new AAA("world");
        System.out.println(b.compr2());
    }

почему на выходе
Код

false
true

?
на всякий случай код стрингового иквела:
Код

    public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
        char v1[] = value;
        char v2[] = anotherString.value;
        int i = offset;
        int j = anotherString.offset;
        while (n-- != 0) {
            if (v1[i++] != v2[j++])
            return false;
        }
        return true;
        }
    }
    return false;
    }


я думал, что перед входом в функцию (в данном случае, в equals() ) сперва разрешаются параметры, а потом выполняется код функции, а не "on-demand" (см строки 9 и 10 в equals) 

Автор: LSD 4.12.2014, 12:02
Тут указатели вообще не причем, просто особенности байткода. Запускаем javap и смотрим что там компилятор сгенерировал:
Код

  public boolean compr();                                                                             
    Code:                                                                                             
       0: aload_0                                                                                     
       1: getfield      #2                  // Field aaa:Ljava/lang/String;                           
       4: aload_0                                                                                     
       5: invokevirtual #4                  // Method getModd:()Ljava/lang/String;                    
       8: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z   
      11: ireturn                                                                                     

0 - положили this на вершину стека (стек: this)
1 - получили у объекта с вершины стека поле aaa и положили его на вершину стека (стек: "world")
4 - положили this на вершину стека (стек: "world", this)
5 - вызвали у объекта с вершины стека getModd() (стек до: "world", this / после: "world", "hello")
7 - вызываем String.equals() у объекта с вершина стека - 1, с аргументом с вершины стека

Т.е. компилятору было проще вытащить старое значение, положить его на стек и только потом уже вызывать getModd().

Автор: CompWorm 5.12.2014, 00:32
прикольно, а спека что-нибудь говорит про чудеса оптимизации? 
я так понимаю, что в Java оптимизацию незя отключить и результат будет разный на разных JVM, осях и процах? smile 

Автор: AlexeyVorotnikov 5.12.2014, 10:53
Компилятор скомпилировал метод compr строго в соответствии со спецификацией языка Java, и результат будет одинаковый на любой JVM, оси и проце.

Автор: LSD 5.12.2014, 17:27
Цитата(CompWorm @  5.12.2014,  01:32 Найти цитируемый пост)
прикольно, а спека что-нибудь говорит про чудеса оптимизации?

https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html
Если я правильно понимаю первый пример, то это как раз твой случай.


Цитата(CompWorm @  5.12.2014,  01:32 Найти цитируемый пост)
я так понимаю, что в Java оптимизацию незя отключить и результат будет разный на разных JVM, осях и процах?

Тут два момента: первый это получивщийся байткод - тут можно развлечь себя http://jasmin.sourceforge.net/.
Второй это как байткод будет выполняться. Оракловые JVM умеют работать в режими интерпретатора и будут выполнять ровно так как в байткоде написано. А вот в режми JIT уже могут быть нюансы. По идее конечно он должен работать так же как интерпретатор и написано в спеке, но сам понимаешь могут быть нюансы smile

Автор: CompWorm 5.12.2014, 21:22
Цитата(AlexeyVorotnikov @  5.12.2014,  10:53 Найти цитируемый пост)
Компилятор скомпилировал метод compr строго в соответствии со спецификацией языка Java

пустая фраза.
Цитата(AlexeyVorotnikov @  5.12.2014,  10:53 Найти цитируемый пост)
и результат будет одинаковый на любой JVM, оси и проце.

а с этим http://stackoverflow.com/questions/1514949/quick-java-optimization-question#1514982

LSD, спасибо! 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)