新的对象是否过时了?

Jef*_*tte 8 c# java language-design

好的,所以这里的问题是......新关键字是否过时了?

考虑在C#(和java,我相信)有类型的严格规则.类是引用类型,只能在堆上创建.POD类型在堆栈上创建; 如果要在堆上分配它们,则必须将它们装入对象类型中.在C#中,structs是例外,它们可以在堆栈或堆上创建.

鉴于这些规则,我们是否还必须使用新关键字?根据类型使用适当的分配策略,语言是否有意义?

例如,我们目前必须写:

SomeClassType x = new SomeClassType();
Run Code Online (Sandbox Code Playgroud)

代替

SomeClassType x = SomeClassType();
Run Code Online (Sandbox Code Playgroud)

甚至只是

SomeClassType x;
Run Code Online (Sandbox Code Playgroud)

编译器将根据创建的类型是引用类型,继续并在堆上为x分配内存.

这适用于其他语言,如ruby,php等.C/C++允许程序员更好地控制对象的创建位置,因此有充分的理由要求使用new关键字.

new只是60年代和我们基于C的遗产的延续吗?

Sta*_* R. 18

SomeClassType x = SomeClassType();
Run Code Online (Sandbox Code Playgroud)

在这种情况下,SomeClassType()可能是位于其他位置的方法,编译器如何知道是调用此方法还是创建新类.

SomeClassType x;
Run Code Online (Sandbox Code Playgroud)

这不是很有用,大多数人声明他们的变量是这样的,有时候他们需要时填充它们.因此,每次声明变量时在内存中创建实例都没有用.

  • @flyfish:如果你想让它成为不可变的(即Java中的`final`或其他语言的等价物),那就不行了,因为那时你不能再为它指定任何其他内容. (2认同)

Tim*_*dge 16

您的第三种方法不起作用,因为有时我们想要定义一种类型的对象并将其分配给另一种类型的变量.例如:

Stream strm = new NetworkStream();
Run Code Online (Sandbox Code Playgroud)

我想要一个流类型(可能在某处传递),但在内部我想要一个NetworkStream类型.

我也多次在调用方法时创建一个新对象:

myobj.Foo(new NetworkStream());
Run Code Online (Sandbox Code Playgroud)

这样做:

myobj.Foo(NetworkStream()); 
Run Code Online (Sandbox Code Playgroud)

非常混乱.我是在创建一个对象,还是在我说NetworkStream()时调用一个方法?

  • @tster:重点是通过强制它不依赖于NetworkStream特有的功能来使代码的其余部分变得灵活.您当然可以将其键入为NetworkStream,并且只需要在代码中仅使用Stream提供的功能,但这样您就可以从编译器获得帮助. (3认同)

Aar*_*ght 6

如果您可以编写SomeClassType x;并自动初始化它,则不允许具有任何参数的构造函数.并非每个SomeClassType人都有一个无参数构造函数; 编译器如何知道要提供什么参数?

public class Repository
{
    private IDbConnection connection;

    public Repository(IDbConnection connection)
    {
        if (connection == null)
        {
            throw new ArgumentNullException("connection");
        }
        this.connection = connection;
    }
}
Run Code Online (Sandbox Code Playgroud)

你将如何实例化这个对象Repository rep;?它需要依赖对象才能正常运行.

更不用说,您可能希望编写如下代码:

Dictionary<int, SomeClass> instances = GetInstancesFromSomewhere();
SomeClass instance;
if (instances.TryGetValue(1, out instance))
{
    // Do something
}
Run Code Online (Sandbox Code Playgroud)

你真的希望它为你自动初始化吗?

如果您刚刚编写,SomeClassType x = SomeClassType()那么这不会区分构造函数和范围内的方法.

更一般地说:

我认为对new关键字的含义存在根本性的误解.值类型在堆栈上分配并且"引用"类型在堆上分配的事实是实现细节.该new关键字是所述的部分规格.作为程序员,您不关心它是否在堆或堆栈上分配(大多数情况下),但您确实需要指定对象的初始化方式.

还有其他有效类型的初始化程序,例如:

int[] values = { 1, 2, 3, 4 };
Run Code Online (Sandbox Code Playgroud)

Voilà,初始化没有new.在这种情况下,编译器足够聪明,可以为您解决这个问题,因为您提供了一个定义整个对象的文字表达式.

所以我猜我的"回答"是,不要担心对象存在于记忆中的位置; 使用new关键字,作为需要初始化的对象的对象初始值设定项.


tst*_*ter 5

对于初学者:

SomeClassType x;
Run Code Online (Sandbox Code Playgroud)

未初始化,因此不应分配内存.

除此之外,如果存在与类同名的方法,如何避免出现问题.

假设你写了一些代码:

int World() { return 3; }

int hello = World();
Run Code Online (Sandbox Code Playgroud)

一切都很好,快乐.

现在你稍后写一个新类:

class World 
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

突然你的int hello = World()线条模棱两可.