18

Wrapper 类很好,它们的目的也很好理解。但是为什么我们要省略原始类型呢?

4

6 回答 6

43

这取决于您所说的“原始”是什么意思

Java中的“原始”通常被认为是“值类型”。但是,C# 有一个string关键字,其作用与 Java 的 String 完全相同,只是编辑器突出显示的方式不同。它们是类的别名System.Stringjava.lang.String。String 在这两种语言中都不是值类型,因此在这种情况下它不是原始类型。

如果“原始”是指内置于语言中,那么 String 是原始的。它只使用大写字母。字符串文字(引号中的内容)会自动转换为System.String+ 用于连接。因此,通过这个标记,它们(和数组)与 int、long 等一样原始。

首先,什么是字符串?

字符串不是包装器。字符串是引用类型,而原始类型是值类型。这意味着如果您有:

int x = 5;
int y = x;

x 和 y 的内存都包含“5”。但是有:

String x = "a";
String y = x;

x 和 y 的内存都包含一个指向字符“a”的指针(以及一个长度、一个偏移量、一个 ClassInfo 指针和一个监视器)。字符串的行为类似于原语,因为它们是不可变的,所以这通常不是问题,但是,如果您使用反射来更改字符串的内容(不要这样做!),x 和 y 都会看到变化. 事实上,如果你有:

char[] x = "a".toCharArray();
char[] y = x;
x[0] = 'b';
System.out.println(y[0] == 'b'); // prints "true"

所以不要只使用 char[] (除非这是你想要的行为,或者你真的想减少内存使用)。

EveryObject是一个引用类型——这意味着您编写的所有类、框架中的每个类,甚至是数组。唯一的值类型是简单的数字类型(int、long、short、byte、float、double、char、bool 等)。

为什么 String 不像 char[] 那样可变?

这有几个原因,但主要归结为心理学和实施细节:

  • 想象一下,如果你将一个字符串传递给另一个函数并且那个函数以某种方式改变了它,你会遇到什么样的混乱。或者如果它把它保存在某个地方并在将来改变它呢?对于大多数引用类型,您接受它作为类型的一部分,但 Java 开发人员决定,至少对于字符串,他们不希望用户担心这一点。
  • 字符串不能以原子方式处理,这意味着多线程/同步将成为一个问题。
  • 字符串文字(您在代码中用引号引起来的东西)在计算机的第1级可能是不可变的(出于安全原因)。这可以通过在程序启动时将它们全部复制到内存的另一部分或使用写时复制来解决,但这很

为什么我们没有字符串的值类型版本?

基本上,性能和实现细节,以及拥有 2 种不同字符串类型的复杂性。其他值类型具有固定的内存占用。int 始终为 32 位,long 始终为 64 位,bool 始终为 1 位,等等。2除此之外,这意味着它们可以存储在堆栈中,因此函数的所有参数都位于一个位置. 此外,在整个地方制作大量的字符串副本会影响性能。

另请参阅:在 C# 中,为什么 String 是一种行为类似于值类型的引用类型?. 指 .NET,但这同样适用于 Java。

1 - 在 C/C++ 和其他本机编译的语言中,这是正确的,因为它们被放置在进程的代码段中,操作系统通常会阻止您对其进行编辑。在 Java 中,这实际上通常是不正确的,因为 JVM 将类文件加载到堆上,因此您可以在那里编辑字符串。但是,没有理由不能原生编译 Java 程序(有一些工具可以做到这一点),并且某些架构(尤其是 ARM 的某些版本)确实直接执行 Java 字节码。

2 - 实际上,其中一些类型在机器级别上具有不同的大小。Ex bool 以 WORD 大小存储在堆栈中(x86 上为 32 位,x64 上为 64 位)。在类/数组中,它们可能会被区别对待。这都是由 JVM 决定的实现细节——规范说布尔值要么是真要么是假,机器可以弄清楚如何去做。

于 2010-01-21T11:38:51.267 回答
10

的原始类型Stringchar[]

这适用于许多语言(C、Java、C#、C++ 等等……)。

于 2010-01-21T11:39:04.907 回答
3

字符串可以是任意长度。java之父不想拥有一个他们无法为其分配具体内存大小的原始类型。这是字符串在 java 中不是原语的主要原因之一。

于 2010-01-21T12:35:22.713 回答
0

字符串是一种特殊情况。所有真正的原始类型(int、long 等)都是按值传递的,并直接在 JVM 中实现。String 是一种引用类型,因此像任何其他类一样处理(大写字母,按引用传递...),除了编译器有特殊的钩子可以像内置类型一样处理它(+ 用于字符串连接,例如)。

因为它已经是一个引用类型,所以它不需要像 Integer 这样的包装类就可以将它用作一个类(例如在集合中)

于 2010-01-21T11:39:00.783 回答
0

原始?

如果 Java 没有字符串的原语。原语是 int、float、double、boolean 等......和 ​​char。

因此,为了使用字符串,他们使用了一个对象。你实例化它,它存在于堆中,你有它的引用,等等。

他们是如何实施的?将它表示的值保存在 char 数组中。

不变性

但他们确保了不变性。当您有一个对 String 对象的引用时,您知道您可以将它自由地传递给其他对象,因为知道该引用指向的值不会改变。所有修改字符串的方法都返回字符串的其他实例,因此它不会更改其他对 String 的引用所表示的值。

可以是其他方式吗(例如在.Net中)

是的。他们可以定义一个保留字字符串,然后编译器进行转换。

但他们并没有...

于 2010-01-21T11:58:23.227 回答
-1

String 是一个 char 数组。因为它是一个数组,所以它不能是一个原始的!:-)

于 2010-01-21T11:38:22.667 回答