Ответ 1
- Это самостоятельная документация.
- Это способ, позволяющий назвать метод "Class1" в каком-то другом классе
Почему новый оператор существует в современных языках, таких как С# и Java? Является ли это исключительно функцией самодокументирующегося кода или выполняет какую-либо фактическую цель?
Например, следующий пример:
Class1 obj = new Class1();
Class1 foo()
{
return new Class1();
}
Легко читается как более питонезский способ его написания:
Class1 obj = Class1();
Class1 foo()
{
return Class1();
}
EDIT: Cowan ударил ноготь по голове с разъяснением вопроса: почему они выбрали этот синтаксис?
Class1 obj = Class1();
В С# и Java вам нужно "новое" ключевое слово, потому что без него он обрабатывает "Class1()" как вызов метода, чье имя "Class1".
Полезность документа - легче отличить создание объектов от вызовов метода, чем в Python.
Причина историческая, и она исходит из синтаксиса С++. В С++ "Class1()" - это выражение, создающее экземпляр Class1 в стеке. Например: вектор a = вектор(); В этом случае вектор создается и копируется в вектор a (в некоторых случаях оптимизатор может удалить избыточную копию).
Вместо этого "new Class1()" создает экземпляр Class1 в куче, как в Java и С#, и возвращает указатель на него с другим синтаксисом доступа, в отличие от Java и С++. Фактически, значение new может быть переопределено для использования любого специализированного распределителя, который все еще должен ссылаться на какую-то кучу, так что полученный объект может быть возвращен ссылкой.
Кроме того, в Java/С#/С++, Class1() сам по себе может ссылаться на любой метод/функцию, и это будет путать. Соглашение о кодировании на Java фактически избежало бы этого, так как они требуют, чтобы имена классов начинались с имени письма в верхнем регистре и имени метода, чтобы начать с нижнего регистра, и, вероятно, из-за того, что Python избегает путаницы в этом случае. Читатель ожидает, что "Class1()" создает объект "class1()" для вызова функции, а "x.class1()" - это вызов метода (где "x" может быть "self" ).
Наконец, поскольку в Python они решили сделать классы объектами и, в частности, вызываемыми объектами, синтаксис без "нового" будет разрешен, и было бы несовместимо допускать наличие другого синтаксиса.
Оператор new в С# отображается непосредственно в инструкцию IL, называемую newobj
которая фактически выделяет пространство для переменных нового объекта, а затем выполняет конструктор (называемый .ctor в IL). При выполнении конструктора - очень похоже на C++ - ссылка на инициализированный объект передается как невидимый первый параметр (как thiscall).
Соглашение, подобное thiscall, позволяет среде выполнения загружать и JIT весь код в памяти для определенного класса только один раз и повторно использовать его для каждого экземпляра класса.
Java может иметь аналогичный код операции на своем промежуточном языке, хотя я недостаточно знаком, чтобы сказать.
С++ предлагает программистам выбор размещения объектов в куче или в стеке.
Распределение на основе стека более эффективное: распределение дешевле, затраты на освобождение действительно равны нулю, а язык предоставляет помощь в демаркации жизненных циклов объектов, снижая риск забывания для освобождения объекта.
С другой стороны, в С++ вы должны быть очень осторожны при публикации или обмене ссылками на объекты на основе стека, потому что объекты на основе стека автоматически освобождаются, когда фрейм стека разматывается, что приводит к оборванным указателям.
С помощью оператора 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...
Причина, по которой Java выбрала это, состояла в том, что синтаксис был знаком с разработчиками на С++. Причина, по которой С# выбрала, была потому, что она была знакома разработчикам Java.
Причина, по которой оператор new
используется в С++, вероятно, объясняется тем, что при ручном управлении памятью очень важно очистить выделение памяти. Хотя синтаксис pythonesque может работать, он делает менее очевидным, что выделена память.
Новый оператор выделяет память для объекта (ов), который является целью; как вы говорите, это также собственные документы, экземпляры (например, новые), с которыми вы работаете с
В дополнение к замечаниям выше AFAIK они планировали удалить новое ключевое слово для Java 7 в ранних черновиках. Но позже они отменили его.
Как уже отмечали другие, Java и С# предоставляют new
синтаксис, потому что C++ сделал. И C++ нужен был какой-то способ отличить создание объекта в стеке, создание объекта в куче или вызов функции или метода, который возвращал указатель на объект.
C++ использовал этот конкретный синтаксис, потому что ранний объектно-ориентированный язык Simula использовал его. Bjarne Stroustrup был вдохновлен Simula и стремился добавить Simula-подобные функции в C. C имел функцию для выделения памяти, но не гарантировал, что конструктор также был вызван.
Из "Проекта и эволюции C++", 1994, Бьярн Страуструп, стр. 57:
Следовательно, я ввел оператор, чтобы гарантировать, что и распределение и инициализация были выполнены:
monitor* p = new monitor;
Оператор был назван
new
потому что это было имя соответствующего оператора Simula. Операторnew
вызывает некоторую функцию выделения для получения памяти, а затем вызывает конструктор для инициализации этой памяти. Объединенная операция часто называется созданием экземпляра или просто созданием объекта: она создает объект из необработанной памяти.Удобство обозначений, предлагаемое оператором
new
, значительно...."
Считаете ли вы использование статических методов?
class Class1
{
public static Class1 Instance() { return new Class1(); }
}
Class1 obj = Class1.Instance();
Class1 foo()
{
return Class1.Instance();
}