Более эффективно использовать ключевое слово this при доступе к переменным экземпляра? - PullRequest
0 голосов
/ 02 марта 2011

Ключевое слово this является необязательным при доступе к полям экземпляра, свойствам и методам в таких языках, как C # и Java.

В последнее время я проводил исследования лучших практик по различным языкам и заметил, что многие места рекомендуют создавать локальные ссылки на поля экземпляров в методах, потому что это более эффективно.Последнее упоминание было в учебнике по Android.

Мне кажется, что если вы укажете this._obj, он должен быть таким же эффективным, как и локальная переменная.Это правильно или это так же «дорого», как не использовать this?

Меняется ли ответ с Android Dalvik VM на стандартную Java на C #?

public class test {
    private Object[] _obj;

    protected void myMethod() {
        Object[] obj = _obj;

        // Is there an appreciable differnce between
        for(int i = 0; i < obj.length; i++) { 
            // do stuff
        }

        // and this?
        for(int i = 0; i < this._obj.length; i++) { 
            // do stuff
        }
    }
}

Ответы [ 7 ]

3 голосов
/ 02 марта 2011

По крайней мере для стандартной Java есть небольшая небольшая разница.

Я немного изменил ваш пример так:

public class test {
    private Object[] _obj;

    protected void myMethodLocal() {
        Object[] obj = _obj;

        // Is there an appreciable differnce between
        for(int i = 0; i < obj.length; i++) { 
            // do stuff
        }
    }

   protected void myMethodMember() {
        // and this?
        for(int i = 0; i < this._obj.length; i++) { 
            // do stuff
        }
   }
}

Так что myMethodLocal() будет кешировать _objв локальную переменную, в то время как myMethodMember() использует член класса _obj.

Теперь, давайте декомпилируем это (используя javap ):

protected void myMethodLocal();
  Code:
   0:   aload_0
   1:   getfield    #2; //Field _obj:[Ljava/lang/Object;
   4:   astore_1
   5:   iconst_0
   6:   istore_2
   7:   iload_2
   8:   aload_1
   9:   arraylength
   10:  if_icmpge   19
   13:  iinc    2, 1
   16:  goto    7
   19:  return

protected void myMethodMember();
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   aload_0
   4:   getfield    #2; //Field _obj:[Ljava/lang/Object;
   7:   arraylength
   8:   if_icmpge   17
   11:  iinc    1, 1
   14:  goto    2
   17:  return

Без переходав деталях, последний пример должен обращаться к полю _obj при каждой итерации цикла, в то время как в первом примере он уже кэшируется в локальной ссылке и ему просто необходим доступ к локальной ссылке.

Что это означаетв разнице в скорости?

Не очень.

В то время как разница между доступом к локальной ссылке и ссылкой на класс означает намного больше в таком языке, как Python, для Java вам действительно не нужно беспокоиться.Гораздо важнее, чтобы ваш код читался и обслуживался, чем беспокоиться о таких деталях.

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

Если вы получите поле экземпляра с помощью функции , например, getObj(), я вставлю это в переменную, чтобы вам не нужно было каждый раз вызывать getObj()хотите использовать одно и то же поле.


Кроме того, просто как небольшую заметку, вы, вероятно, должны назвать свой класс Test вместо test. Java имеет тенденцию отдавать предпочтение Upper Camel Case для имен классов.

2 голосов
/ 02 марта 2011

Нет, абсолютно никаких изменений в эффективности.Помните, что во многих языках несколько эквивалентных выражений будут сокращены до идентичных выражений в базовом байт-коде или сборке или в любом другом языке более высокого уровня.

Ответ одинаков для всех языков и ВМ, которые вы упомянули.

Используйте его при необходимости, например, когда параметр метода имеет то же имя, что и переменная экземпляра.

Если только циклы ЦП (или память и т. Д.) Не являются высшим приоритетом, ясность значения выше менее выразительной, ноболее эффективный синтаксис языка.

1 голос
/ 02 марта 2011

Ключевое слово this используется для удобства чтения и, что наиболее важно, делает имена переменных однозначными. Это никак не влияет на производительность.

0 голосов
/ 02 марта 2011

Некоторые из этих ответов не ответили на реальный вопрос, а другие неверны.Доступ к переменной-члену через this.obj требует разыменования элемента в стеке.Доступ к локальной копии этой ссылки устраняет шаг разыменования.Таким образом, в теории и отсутствии HotSpot последний должен быть более эффективным.Однако, если вы не планируете ядерные реакции или что-то в этом роде, разница будет минимальной, и я бы не одобрял эту практику всякий раз, когда видел ее в своем магазине.

0 голосов
/ 02 марта 2011

В теории нет. Доступ к this._obj.Length приводит к генерации кода вроде:

mov eax, [ecx + offset_of_obj]
mov eax, [eax + offset_of_length]

где "obj.length" генерирует такой код:

mov eax, [esp + offset_of_obj]
mov eax, [eax + offset_of_length]

На практике, может быть, но, вероятно, нет. Практически в каждом соглашении о вызовах x86 есть только 3 чистых регистра: «eax», «ecx» и «edx». Все остальные регистры должны быть сохранены в стеке, прежде чем они могут быть обновлены. Если у вас есть длинная функция, и вам не нужно обращаться к «this», то регистр ecx может быть переназначен для хранения временных переменных и, таким образом, может уменьшить количество разливов стека, которое должно произойти. Но вы должны поместить новые значения в стек, чтобы создать локальные объекты, поэтому сценарии, в которых это может быть улучшено, ограничены. Я бы проигнорировал, кто вам это сказал.

0 голосов
/ 02 марта 2011

Я подозреваю, что использование локальной переменной - это только одна ссылка (значение в стеке), в то время как использование переменной-члена - это 2 ссылки (ссылка на this , которая находится в стеке, затем ссылка насама переменная, которая находится в куче)

В зависимости от системы доступ к куче или стеку может быть более быстрым.

Но, как сказал Джонатон , если скорость неочень важно, не заморачивайся этим.Это только уменьшит читабельность при незначительной производительности.

0 голосов
/ 02 марта 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...