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

StackOverflow https://stackoverflow.com/questions/433591

  •  10-07-2019
  •  | 
  •  

Вопрос

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

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

Class1 obj = new Class1();

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

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

Class1 obj = Class1();

Class1 foo()
{
    return Class1();
}

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

Это было полезно?

Решение

<Ол>
  • Это функция самодокументирования.
  • Это способ сделать возможным присвоение имени методу " 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();
    }
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top