Почему C # и Java беспокоятся о «новом» операторе? - PullRequest
17 голосов
/ 11 января 2009

Почему новый оператор существует в современных языках, таких как C # и Java? Это чисто самодокументируемая функция кода или она служит какой-либо реальной цели?

Например, следующий пример:

Class1 obj = new Class1();

Class1 foo()
{
    return new Class1();
}

Так же легко читать, как и более питонский способ написания:

Class1 obj = Class1();

Class1 foo()
{
    return Class1();
}

РЕДАКТИРОВАТЬ: Cowan ударил ногтем по голове с разъяснением вопроса: почему они выбрали этот синтаксис?

Ответы [ 9 ]

24 голосов
/ 11 января 2009
  1. Это функция самодокументирования.
  2. Это способ сделать возможным назвать метод "Class1" в каком-то другом классе
9 голосов
/ 12 января 2009

Полезность документации - легче отличить создание объекта от вызова метода, чем в Python.

Причина историческая и вытекает из синтаксиса C ++. В C ++ «Class1 ()» - это выражение, создающее экземпляр Class1 в стеке . Например: вектор а = вектор (); В этом случае вектор создается и копируется в вектор a (в некоторых случаях оптимизатор может удалить избыточную копию).

Вместо этого «new Class1 ()» создает экземпляр Class1 в куче , как в Java и C #, и возвращает на него указатель с другим синтаксисом доступа, в отличие от Java и C ++. На самом деле значение new можно переопределить, чтобы использовать любой распределитель специального назначения, который все еще должен ссылаться на какую-то кучу, чтобы полученный объект мог быть возвращен по ссылке.

Более того, в Java / C # / C ++ Class1 () сам по себе может ссылаться на любой метод / функцию, и это может привести к путанице. Соглашения о кодировании Java фактически избегают этого, так как они требуют, чтобы имена классов начинались с заглавной буквы, а имена методов начинались со строчной, и, вероятно, именно так Python избегает путаницы в этом случае. Читатель ожидает, что «Class1 ()» создаст объект, «class1 ()» будет вызовом функции, а «x.class1 ()» будет вызовом метода (где «x» может быть «self»).

Наконец, поскольку в Python они решили сделать классы объектами и, в частности, вызываемыми объектами, синтаксис без 'new' будет разрешен, и будет непоследовательным допускать наличие другого синтаксиса.

9 голосов
/ 11 января 2009
Class1 obj = Class1();

В C # и Java вам нужно ключевое слово «new», потому что без него оно обрабатывает «Class1 ()» как вызов метода с именем «Class1».

5 голосов
/ 11 января 2009

Новый оператор в C # отображается непосредственно в инструкцию IL с именем newobj, которая фактически выделяет пространство для переменных нового объекта, а затем выполняет конструктор (называемый .ctor в IL). При выполнении конструктора - во многом как в C ++ - ссылка на инициализированный объект передается как невидимый первый параметр (например, thiscall ).

Соглашение, подобное thiscall, позволяет среде выполнения загружать и JIT весь код в памяти для определенного класса только один раз и повторно использовать его для каждого экземпляра класса.

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

2 голосов
/ 14 января 2009

Причина, по которой Java выбрала это, была в том, что синтаксис был знаком разработчикам на C ++. Причина, по которой C # выбрал его, заключалась в том, что он был знаком разработчикам Java.

Причина использования оператора new в C ++, вероятно, заключается в том, что при ручном управлении памятью очень важно прояснить, когда выделяется память. Хотя синтаксис pythonesque может работать, он делает менее очевидным, что память выделяется.

2 голосов
/ 12 января 2009

C ++ предлагает программистам выбор размещения объектов в куче или в стеке.

Распределение на основе стека более эффективно : выделение дешевле, затраты на освобождение действительно равны нулю, а язык помогает разграничивать жизненные циклы объекта, снижая риск забывания освободить объект.
С другой стороны, в C ++ вы должны быть очень осторожны при публикации или совместном использовании ссылок на объекты, основанные на стеке, поскольку объекты, основанные на стеке, автоматически освобождаются, когда кадр стека разматывается, что приводит к висящим указателям.

С помощью оператора new все объекты размещаются в куче в Java или C #.

Class1 obj = Class1 ();

На самом деле, компилятор попытается найти метод с именем Class1().

например. Ниже приведена распространенная ошибка Java:

public class MyClass
{
  //Oops, this has a return type, so its a method not a constructor!
  //Because no constructor is defined, Java will add a default one.
  //init() will not get called if you do new MyClass();
  public void MyClass()
  {
     init();
  }
  public void init()
  {
     ...
  }
} 

Примечание: «все объекты размещаются в куче» не означает, что выделение стека не используется время от времени под капотом.

Например, в Java для оптимизации Hotspot, например, escape-анализ использует распределение стека.

Этот анализ, выполненный компилятором времени выполнения, может заключить, например, что на объект в куче ссылаются только локально в методе, и никакая ссылка не может выйти из этой области. Если это так, Hotspot может применять оптимизации во время выполнения. Он может размещать объект в стеке или в регистрах вместо кучи.

Такая оптимизация, хотя и не всегда считается решающим ...

1 голос
/ 11 января 2009

Новый оператор выделяет память для объекта (ов), что является его целью; как вы говорите, он также сам документирует какие экземпляры (ы) (т.е. новый), с которыми вы работаете

0 голосов
/ 12 января 2009

Помимо замечаний выше AFAIK, они планировали удалить новое ключевое слово для Java 7 в ранних версиях. Но позже они отменили это.

0 голосов
/ 11 января 2009

Рассматривали ли вы использование статических методов?

class Class1 
{
   public static Class1 Instance() { return new Class1(); }
}

Class1 obj = Class1.Instance();

Class1 foo()
{
    return Class1.Instance();
}
...