为什么 C# 和 Java 费心于“新”的东西? 操作员?

发布于 2024-07-11 10:21:27 字数 491 浏览 9 评论 0原文

为什么 C# 和 Java 等现代语言中存在 new 运算符 ? 它纯粹是一个自记录代码功能,还是有任何实际目的?

例如下面的例子:

Class1 obj = new Class1();

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

与Python风格的编写方式一样容易阅读:

Class1 obj = Class1();

Class1 foo()
{
    return Class1();
}

编辑: Cowan 击中要害澄清问题:为什么他们选择这种语法?

Why does the new operator exist in modern languages such as C# and Java? Is it purely a self documenting code feature, or does it serve any actual purpose?

For instance the following example:

Class1 obj = new Class1();

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

Is as easy to read as the more Pythonesque way of writing it:

Class1 obj = Class1();

Class1 foo()
{
    return Class1();
}

EDIT: Cowan hit the nail on the head with the clarification of the question: Why did they choose this syntax?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

_蜘蛛 2024-07-18 10:21:27
  1. 这是一个自我记录功能。
  2. 这是一种可以在其他类中命名方法“Class1”的方法
  1. It's a self documenting feature.
  2. It's a way to make it possible to name a method "Class1" in some other class
渔村楼浪 2024-07-18 10:21:27
Class1 obj = Class1();

在 C# 和 Java 中,您需要“new”关键字,因为如果没有它,它将“Class1()”视为对名称为“Class1”的方法的调用。

Class1 obj = Class1();

In C# and Java, you need the "new" keyword because without it, it treats "Class1()" as a call to a method whose name is "Class1".

空心空情空意 2024-07-18 10:21:27

有用之处在于文档 - 与 Python 相比,它更容易区分对象创建和方法调用。

原因是历史性的,并且直接来自 C++ 语法。
在 C++ 中,“Class1()”是在堆栈上创建 Class1 实例的表达式。 例如:
向量 a = 向量();
在这种情况下,创建一个向量并将其复制到向量 a(优化器在某些情况下可以删除冗余副本)。

相反,“new Class1()”在堆上创建一个 Class1 实例,就像在 Java 和 C# 中一样,并使用不同的访问语法返回一个指向它的指针,这与 Java 和 C# 不同Java 和 C++。 实际上,new 的含义可以重新定义为使用任何特殊用途的分配器,但它仍然必须引用某种堆,以便可以通过引用返回获得的对象。

而且,在Java/C#/C++中,Class1()本身可以引用任何方法/函数,这会令人困惑。 Java 编码约定实际上会避免这种情况,因为它们要求类名以大写字母开头,方法名称以小写字母开头,这可能就是 Python 在这种情况下避免混淆的方式。 读者期望“Class1()”创建一个对象,“class1()”是函数调用,“x.class1()”是方法调用(其中“x”可以是“self”)。

最后,由于在 Python 中,他们选择使类成为对象,特别是可调用对象,因此允许不带“new”的语法,并且允许使用另一种语法是不一致的。

The usefulness is of documentation - it's easier to distinguish object creations from method invocations than in Python.

The reason is historic, and comes straight from the C++ syntax.
In C++, "Class1()" is an expression creating a Class1 instance on the stack. For instance:
vector a = vector();
In this case, a vector is created and copied to the vector a (an optimizer can remove the redundant copy in some cases).

Instead, "new Class1()" creates a Class1 instance on the heap, like in Java and C#, and returns a pointer to it, with a different access syntax, unlike Java and C++. Actually, the meaning of new can be redefined to use any special-purpose allocator, which still must refer to some kind of heap, so that the obtained object can be returned by reference.

Moreover, in Java/C#/C++, Class1() by itself could refer to any method/function, and it would be confusing. Java coding convention actually would avoid that, since they require class names to start with a upper case letter and method names to start with a lower case one, and probably that's the way Python avoids confusion in this case. A reader expects "Class1()" to create an object, "class1()" to be a function invocation, and "x.class1()" to be a method invocation (where 'x' can be 'self').

Finally, since in Python they chose to make classes be objects, and callable objects in particular, the syntax without 'new' would be allowed, and it would be inconsistent to allow having also another syntax.

凡间太子 2024-07-18 10:21:27

C# 中的 new 运算符直接映射到名为 newobj 的 IL 指令,该指令实际上为新对象的变量分配空间,然后执行构造函数(在 IL 中称为 .ctor)。 执行构造函数时——与 C++ 非常相似——对初始化对象的引用作为不可见的第一个参数传入(如 此调用)。

类似 thiscall 的约定允许运行时为特定类加载和 JIT 内存中的所有代码一次,然后为该类的每个实例重用它。

Java 在其中间语言中可能有类似的操作码,尽管我还不够熟悉。

The new operator in C# maps directly to the IL instruction called newobj which actually allocates the space for the new object's variables and then executes the constructor (called .ctor in IL). When executing the constructor -- much like C++ -- a reference to the initialized object is passed in as an invisible first parameter (like thiscall).

The thiscall-like convention allows the runtime to load and JIT all of the code in memory for a specific class only one time and reuse it for every instance of the class.

Java may have a similar opcode in its intermediate language, though I am not familiar enough to say.

醉南桥 2024-07-18 10:21:27

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 可以应用运行时优化。 它可以在堆栈或寄存器中而不是在堆上分配对象。

但这种优化并不总是被考虑 果断...

C++ offers programmers a choice of allocating objects on the heap or on the stack.

Stack-based allocation is more efficient: allocation is cheaper, deallocation costs are truly zero, and the language provides assistance in demarcating object lifecycles, reducing the risk of forgetting to free the object.
On the other hand, in C++, you need to be very careful when publishing or sharing references to stack-based objects because stack-based objects are automatically freed when the stack frame is unwound, leading to dangling pointers.

With the new operator, all objects are allocated on the heap in Java or C#.

Class1 obj = Class1();

Actually, the compiler would try to find a method called Class1().

E.g. the following is a common Java bug:

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()
  {
     ...
  }
} 

Note: "all objects are allocated on the heap" does not mean stack allocation is not used under the hood occasionally.

For instance, in Java, Hotspot optimization like escape analysis uses stack allocation.

This analysis performed by the runtime compiler can conclude for example that an object on the heap is referenced only locally in a method and no reference can escape from this scope. If so, Hotspot can apply runtime optimizations. It can allocate the object on the stack or in registers instead of on the heap.

Such optimization though is not always considered decisive...

天气好吗我好吗 2024-07-18 10:21:27

Java 选择它的原因是因为 C++ 开发人员熟悉其语法。 C#选择它的原因是因为Java开发人员熟悉它。

在 C++ 中使用 new 运算符的原因可能是因为在手动内存管理中,明确何时分配内存非常重要。 虽然 pythonesque 语法可以工作,但它使得内存分配不太明显。

The reason Java chose it was because the syntax was familiar to C++ developers. The reason C# chose it was because it was familiar to Java developers.

The reason the new operator is used in C++ is probably because with manual memory management it is very important to make it clear when memory is allocated. While the pythonesque syntax could work, it makes is less obvious that memory is allocated.

恍梦境° 2024-07-18 10:21:27

new 运算符为对象分配内存,这就是它的目的; 正如您所说,它还自我记录您正在使用的实例(即新实例)

The new operator allocates the memory for the object(s), which is it's purpose; as you say it also self documents which instance(s) (i.e. a new one) you're working with

情域 2024-07-18 10:21:27

正如其他人所指出的,Java 和 C# 提供了新语法,就像 C++ 提供的那样。 C++ 需要某种方法来区分在堆栈上创建对象、在堆上创建对象或调用返回对象指针的函数或方法。

C++ 使用这种特定语法,因为早期的面向对象语言 Simula 使用了它。 Bjarne Stroustrup 受到 Simula 的启发,并试图向 C 添加类似 Simula 的功能。C 有一个分配内存的函数,但不保证也会调用构造函数。

摘自 Bjarne Stroustrup 1994 年的“C++ 的设计和演变”,第 57 页:

因此,我引入了一个运算符来确保分配和初始化都完成:

监视器* p = 新监视器;

该运算符被称为 new,因为这是相应 Simula 运算符的名称。 new 运算符调用一些分配函数来获取内存,然后调用构造函数来初始化该内存。 组合操作通常称为实例化或简称为对象创建:它从原始内存中创建一个对象。

运算符new 提供的符号便利性非常重要。 ...”

As others have noted, Java and C# provide the new syntax because C++ did. And C++ needed some way to distinguish between creating an object on the stack, creating an object on the heap, or calling a function or method that returned a pointer to an object.

C++ used this particular syntax because the early object-oriented language Simula used it. Bjarne Stroustrup was inspired by Simula, and sought to add Simula-like features to C. C had a function for allocating memory, but didn't guarantee that a constructor was also called.

From "The Design and Evolution of C++," 1994, by Bjarne Stroustrup, page 57:

Consequently, I introduced an operator to ensure that both allocation and initialization was done:

monitor* p = new monitor;

The operator was called new because that was the name of the corresponding Simula operator. The new operator invokes some allocation function to obtain memory and then invokes a constructor to initialize that memory. The combined operation is often called instantiation or simply object creation: it creates an object out of raw memory.

The notational convenience offered by operator new is significant. ..."

萌梦深 2024-07-18 10:21:27

除了上面的评论之外,据我所知,他们还计划在早期草案中删除 Java 7 的新关键字。 但后来他们取消了。

In addition to remarks above AFAIK they were planning to remove new keyword for Java 7 in early drafts. But later they cancelled it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文