我在网上搜索了Java中“new”的用法,它是用于创建一个全新的类实例。为什么需要通过“new”关键字明确指示?难道不明白构造函数调用会实例化一个新对象吗?例如,如果没有new
,很明显会MyClass AnInstance = MyClass(AnArgument)
创建一个新对象。
从实际角度来看,我提出这个问题的原因是因为我认为“新”是为了防范危险而设计的,并且我想了解这种危险。
我在网上搜索了Java中“new”的用法,它是用于创建一个全新的类实例。为什么需要通过“new”关键字明确指示?难道不明白构造函数调用会实例化一个新对象吗?例如,如果没有new
,很明显会MyClass AnInstance = MyClass(AnArgument)
创建一个新对象。
从实际角度来看,我提出这个问题的原因是因为我认为“新”是为了防范危险而设计的,并且我想了解这种危险。
冒着一个答案被认为是“意见”的风险,我会抛弃
java
紧随 C 和 C++ 之后的内容,并本质上继承了后者的语法 - 尽管destroy
考虑到垃圾收集器,类似的东西是不必要的。因此,对于它没有严格的“要求”,
new
而是遵循它最强烈派生的语言的模式。是吗?
考虑这个类(它是真正有效的 Java):
在这种情况下,
MyClass(AnArgument)
调用此类中命名的方法MyClass
,并且从未实际创建 的实例MyClass
。我认为您的错误在于认为这
new MyClass(AnArgument)
是调用名为 的构造函数的语法MyClass
。我认为事实并非如此。MyClass
相反,它是通过调用适当的构造函数来创建 的实例的语法。事实上,定义构造函数的语法涉及重复类名;但我认为我们不应该将其视为构造函数名称。请注意,new MyClass.MyClass(AnArgument)
即使构造函数不在范围内,我们也不会编写,并且请注意,它作为类的类型参数new MyGenericClass<T>(AnArgument)
传递,而不是其构造函数(因为构造函数没有类型参数)。T
MyGenericClass
这是命名空间的问题。
在java中,方法和字段可以具有相同的名称,并且它们完全不相关。事实上,类型也可以,包也可以。所有 4 个都是完全正交的。这 4 者永远不会相遇:
这是完全合法的。这里没有任何内容会覆盖任何内容 - 这是一个
foo
在 package 中命名的类foo
,有 3 个成员:一个名为 的字段foo
、一个采用零参数的构造函数,以及一个foo
不采用任何参数且不返回任何内容的方法。你可以编译它。它会。没有任何警告。您的 IDE 可能会抱怨以小写字母开头的类型是非常规的。但这只是惯例。lang 规范允许这样做。javac
将编译上面的就好了。那么,如果你可以将所有这些东西都命名为同一个东西,那么它是如何工作的呢?
从上下文中java总是知道你在做什么。
在某些语言中,调用方法时括号是可选的,或者至少所有内容都位于同一名称空间中。
例如,在 JavaScript 中:
是合法的;
x
现在是对该函数的引用test
。事实上,这也意味着你不能在 javascript 中拥有同名的方法和变量:
不起作用。最后一条语句尝试将“5”作为函数执行,但事实并非如此。
在java中,情况并非如此(这些括号不是可选的,没有括号,它就与该方法无关,句号),因为java在具有4个完全不相关的名称空间方面有些独特。
因此,为什么
new
必须存在。因为如果它不存在,java 将不知道要挖掘 2 个相关命名空间(类型和方法)中的哪一个。换句话说,这个:是合法的java。它编译得很好。那么,如果导入这个 Test 类,然后写:
Test();
,我在谈论哪一个?在java中,很清楚:如果你写
new Test()
,它就是构造函数,如果你写Test()
,它就是静态方法。我们可以详细讨论拥有正交命名空间是否是一个明智的想法。然而,java 不喜欢破坏向后兼容性,在这一点上,改变这一切显然不值得所带来的痛苦,所以你的问题将归结为:“为什么 java 的设计者决定使用正交命名空间30 年前”,这……在这样的问题中很难回答,我需要一根鞭子和一顶棕色帽子,还有一些约翰·威廉姆斯的音乐。
在类级别,这些构造函数被编译为特殊方法,其行为大多类似于静态方法(因为它们不进行虚拟查找,并且不需要接收器 - 它与静态方法共享的属性,但不与实例方法共享),命名为
<init>
. 不Test
,或者不管你的班级叫什么名字。所以,最好考虑一下它们(因为这实际上是它的工作原理):
void
- 或者您正在声明一个方法!) - 但这只是为了让编译器知道您在做什么。将类型名称的重复视为 java 避免引入关键字的方法(它也可能代替public constructor(String arg1, int arg2)
,public TypeNameGoesHere(String arg1, int arg2)
但是,事实并非如此。再说一遍,30 年,如果我们想深入了解原因,请避开一些蛇)。注意:命名空间实际上确实满足。它位于 select AST 链中:
a.b.c.d.e
不明确:是 packagea.b
,然后是 typec
,具有名为 的静态内部类型d
,并且具有名为 的静态字段吗e
?或者它是a
包含类b
、内部类c
、静态字段的包d
,其中的类型z
具有名为 的实例字段e
?Javac 在编译过程中在黑暗中进行了最猛烈的尝试,并将其“锁定”。在运行时(类文件)级别,命名空间确实无法满足。每条指令都清楚地表明标识符所指的是 4 个命名空间中的哪一个。
据我所知,第一个原因是java语言的语法,需要使用new关键字来创建对象。其次,从技术上讲,new 关键字调用类的构造函数来创建其对象并返回。这种方式允许我们使用私有构造函数(对于单例类),而不能使用 new 关键字来创建对象。