Подтвердить что ты не робот

Почему С# и Java беспокоятся о "новом" операторе?

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

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

Class1 obj = new Class1();

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

Легко читается как более питонезский способ его написания:

Class1 obj = Class1();

Class1 foo()
{
    return Class1();
}

EDIT: Cowan ударил ноготь по голове с разъяснением вопроса: почему они выбрали этот синтаксис?

4b9b3361

Ответ 1

  • Это самостоятельная документация.
  • Это способ, позволяющий назвать метод "Class1" в каком-то другом классе

Ответ 2

Class1 obj = Class1();

В С# и Java вам нужно "новое" ключевое слово, потому что без него он обрабатывает "Class1()" как вызов метода, чье имя "Class1".

Ответ 3

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

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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

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

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

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 может применять оптимизацию во время выполнения. Он может выделять объект в стеке или в регистре, а не в куче.

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

Ответ 6

Причина, по которой Java выбрала это, состояла в том, что синтаксис был знаком с разработчиками на С++. Причина, по которой С# выбрала, была потому, что она была знакома разработчикам Java.

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

Ответ 7

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

Ответ 8

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

Ответ 9

Как уже отмечали другие, Java и С# предоставляют new синтаксис, потому что C++ сделал. И C++ нужен был какой-то способ отличить создание объекта в стеке, создание объекта в куче или вызов функции или метода, который возвращал указатель на объект.

C++ использовал этот конкретный синтаксис, потому что ранний объектно-ориентированный язык Simula использовал его. Bjarne Stroustrup был вдохновлен Simula и стремился добавить Simula-подобные функции в C. C имел функцию для выделения памяти, но не гарантировал, что конструктор также был вызван.

Из "Проекта и эволюции C++", 1994, Бьярн Страуструп, стр. 57:

Следовательно, я ввел оператор, чтобы гарантировать, что и распределение и инициализация были выполнены:

monitor* p = new monitor;

Оператор был назван new потому что это было имя соответствующего оператора Simula. Оператор new вызывает некоторую функцию выделения для получения памяти, а затем вызывает конструктор для инициализации этой памяти. Объединенная операция часто называется созданием экземпляра или просто созданием объекта: она создает объект из необработанной памяти.

Удобство обозначений, предлагаемое оператором new, значительно...."

Ответ 10

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

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

Class1 obj = Class1.Instance();

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