Почему C# и Java беспокоятся о «новом» операторе?
-
10-07-2019 - |
Вопрос
Почему новый оператор существуют в современных языках, таких как C# и Java?Это просто самодокументируемая функция кода или она служит какой-то реальной цели?
Например, следующий пример:
Class1 obj = new Class1();
Class1 foo()
{
return new Class1();
}
Читается так же легко, как и более питонский способ написания:
Class1 obj = Class1();
Class1 foo()
{
return Class1();
}
РЕДАКТИРОВАТЬ: Коуэн попал в точку с уточнением вопроса:Почему они выбрали этот синтаксис?
Решение
Другие советы
Class1 obj = Class1();
В C # и Java вам нужен " новый " ключевое слово, потому что без него оно обрабатывает " Class1 () " как вызов метода с именем «Class1».
Полезность документации - проще отличить создание объекта от вызова метода, чем в 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' был бы разрешен, и было бы непоследовательным допускать наличие другого синтаксиса.
Оператор new в C # отображается непосредственно в инструкцию IL с именем newobj
, которая фактически выделяет пространство для переменных нового объекта, а затем выполняет конструктор (в IL называется .ctor). При выполнении конструктора - во многом как в C ++ - ссылка на инициализированный объект передается как невидимый первый параметр (например, thiscall ).
Соглашение, подобное thiscall, позволяет среде выполнения загружать и JIT весь код в памяти для определенного класса только один раз и повторно использовать его для каждого экземпляра класса.
Java может иметь похожий код операции на своем промежуточном языке, хотя я не достаточно знаком, чтобы это сказать.
C++ предлагает программистам выбор: размещать объекты в куче или в стеке.
Распределение на основе стека более эффективным:выделение дешевле, затраты на освобождение действительно равны нулю, а язык помогает разграничить жизненные циклы объектов, снижая риск забыть об освобождении объекта.
С другой стороны, в C++ нужно быть очень осторожным при публикации или совместном использовании ссылок на объекты на основе стека, поскольку объекты на основе стека автоматически освобождаются при размотке кадра стека, что приводит к висячим указателям.
С new
оператор, все объекты размещаются в куче в Java или C#.
Класс1 объект = Класс1();
На самом деле компилятор попытается найти метод с именем 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, например анализ побега использует распределение стека.
Этот анализ, выполняемый компилятором среды выполнения, может, например, прийти к выводу, что на объект в куче ссылаются только локально в методе, и ни одна ссылка не может выйти за пределы этой области.Если это так, Hotspot может применить оптимизацию времени выполнения.Он может размещать объект в стеке или в регистрах, а не в куче.
Однако такая оптимизация не всегда обдуманный решающий...
Причина, по которой Java выбрала это, была в том, что синтаксис был знаком разработчикам C ++. Причина, по которой C # выбрал его, заключалась в том, что он был знаком разработчикам Java.
Причина, по которой оператор new
используется в C ++, возможно, заключается в том, что при ручном управлении памятью очень важно прояснить, когда выделяется память. Хотя синтаксис pythonesque может работать, он делает менее очевидным, что память выделяется. Р>
Оператор new выделяет память для объекта (объектов), что является его целью; как вы говорите, он также сам документирует какие экземпляры (т. е. новый), с которыми вы работаете
В дополнение к замечаниям выше AFAIK они планировали удалить новое ключевое слово для Java 7 в ранних версиях. Но позже они отменили это.
Рассматривали ли вы использование статических методов?
class Class1
{
public static Class1 Instance() { return new Class1(); }
}
Class1 obj = Class1.Instance();
Class1 foo()
{
return Class1.Instance();
}