我们可以给Java添加结构吗?
我在一次采访中问了这个问题,但无法回答。希望你能帮助我 问题是:为什么Java开发人员没有添加对结构的支持?为什么不可能将堆栈上分配的值类型添加到Java我们可以给Java添加结构吗?,java,struct,value-type,Java,Struct,Value Type,我在一次采访中问了这个问题,但无法回答。希望你能帮助我 问题是:为什么Java开发人员没有添加对结构的支持?为什么不可能将堆栈上分配的值类型添加到Java 我想与以前的java版本应该存在一些向后兼容性问题?但是,我无法想出任何方法。我认为带有公共变量的类与结构非常接近: final class Person { String name; int age; } 因此,如果类已经涵盖了这种类型的功能,那么没有必要添加类似于structs的内容。如果问题的实质是“为什么不可能将堆栈上分
我想与以前的java版本应该存在一些向后兼容性问题?但是,我无法想出任何方法。我认为带有公共变量的
类与结构非常接近:
final class Person {
String name;
int age;
}
因此,如果类已经涵盖了这种类型的功能,那么没有必要添加类似于structs
的内容。如果问题的实质是“为什么不可能将堆栈上分配的值类型添加到Java中”,那么答案应该是Java中的数据位于堆中,并在堆栈中通过引用传递,泛型类型除外 虽然Java不允许堆栈分配,但它确实使用了一些调用转义分析
找到一个与此相关的链接:
Java语言不提供在堆栈上显式分配对象的任何方法,但这一事实并不妨碍JVM在适当的情况下仍然使用堆栈分配。JVM可以使用一种称为转义分析(escape analysis)的技术,通过这种技术,JVM可以判断某些对象在其整个生命周期内都被限制在单个线程中,并且生命周期受给定堆栈帧的生命周期的限制。这样的对象可以在堆栈而不是堆上安全地分配。更好的是,对于小对象,JVM可以完全优化分配,只需将对象的字段提升到寄存器中
结构本质上是一组用胶带固定在一起的变量。复制结构或按值传递给方法等同于复制所有变量或按值传递所有变量。如果一个人除了重写所有变量外,从不在其构造函数之外修改结构中的任何变量,那么结构的语义将反映类的语义;有些人认为,一切都应该像类一样运行,可以以任何其他方式使用的结构都是“邪恶的”,但对于想要的是一组用管道胶带固定在一起的变量的情况,暴露的字段结构是理想的
例如,考虑Point3d
的设计,使得Point
类型的变量封装了三个float
值,分别称为X
、Y
和Z
。理想情况下,人们希望每个变量、数组插槽或Point
类型的其他存储位置封装这三个值,而不封装其他值,这样当且仅当所有三个坐标匹配时,两个存储位置才被视为等效。公开的字段结构将完美地封装这一含义,因为字段声明Point3d foo,bar
将为六个float
字段foo.X
、foo.Y
、foo.Z
、bar.X
、bar.Y
和bar.Z
分配空间。如果说foo=bar;foo.X=5f;bar.Y=7f代码>,相当于foo.X=bar.X;foo.Y=bar.Y;foo.Z=bar.Z;foo.X=5f;bar.Y=7f代码>。因为foo.X
和Bar.X
是不同的变量,就像foo.Y
和Bar.Y
一样,写入foo.X
不会影响Bar.X
,写入Bar.Y
也不会影响foo.Y
”
如果Point3d
是一个不可变的类类型,那么就不可能说foo.X=5f代码>;相反,有必要执行类似于foo=newpoint3d(5,foo.y,foo.z)的操作代码>更笨重、更慢、更容易出现错误。如果它是一个可变类类型,可以说foo.X=5f
,类型为Point3d
的每个存储位置将不仅封装坐标,还封装到每个其他存储位置的连接,该存储位置包含对同一实例的引用。保存特定Point3d
实例的唯一现存引用的存储位置可用于仅封装坐标,但公开信息的唯一方法是将其复制到其他对象(可能是另一个Point3d
实例)
值得注意的是,.NET除了具有结构类型外,还具有“byref”的概念。在C#中,如果Point3d
是一个结构,并且定义了一个方法:
void MovePointRight(ref Point3d pt, float amount) { pt.X += amount; }
并称之为:
MovePointRight(ref foo, 5.3f);
然后,当该方法执行时,pt.X
将引用foo.X
,同样地,.Y
和.Z
。在Java中,使变量可用于方法以便在其中存储信息的唯一方法是创建包含这些变量的类对象的实例并传递对它的引用;无法控制该方法对该引用的操作。例如,它可以将引用传递给将来某个时间将更改对象的其他线程。在C#中,将byref传递给变量的代码可以确定,当被调用的方法返回时,byref及其所有副本都将消失。传递ref foo
将允许MovePointRight
执行它想执行的任何操作foo.X
、foo.Y
和foo.Z
,但调用可能导致的任何更改都将在其返回之前发生
如果JVM不需要使用泛型,那么向Java添加结构在某种程度上是可能的。简单地让每个结构定义定义多个离散变量,让一个结构定义数组定义多个数组。给定Point3d[]myPoints
,创建四元素数组的请求应创建三个四元素数组float
,并将它们分配给myPoints.X[]
、myPoints.Y[]
和myPoints.Z[]