Ответ 1
Это зависит от того, что вы подразумеваете под "примитивным"
"Примитив" в Java обычно воспринимается как "тип значения". Однако С# имеет ключевое слово string
, которое действует точно так же, как Java String, оно просто выделяется редактором по-разному. Это псевдонимы для классов System.String
или java.lang.String
. Строка не является типом значений на любом языке, поэтому таким образом она не является примитивной.
Если под "примитивным" вы подразумеваете встроенный в язык, то String является примитивным. Он просто использует заглавную букву. Строковые литералы (эти вещи в кавычках) автоматически преобразуются в System.String
и + используются для конкатенации. Таким образом, этим маркером они (и массивы) являются такими же примитивными, как ints, longs и т.д.
Во-первых, что такое String?
Строка не является оберткой. Строка является ссылочным типом, тогда как примитивные типы - это типы значений. Это означает, что если у вас есть:
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 [] (если это не то поведение, которое вы хотите, или вы действительно пытаетесь уменьшить использование памяти).
Каждый Object
является ссылочным типом - это означает все классы, которые вы пишете, каждый класс в структуре и даже массивы. Единственными вещами, которые являются типами значений, являются простые числовые типы (int, long, short, byte, float, double, char, bool и т.д.)
Почему переменная String не работает как char []?
Есть несколько причин для этого, но в основном это сводится к деталям психологии и реализации:
- Представьте себе хаос, который у вас был бы, если бы вы передали строку в другую функцию, и эта функция каким-то образом изменила ее. Или что, если он где-то сэкономил и изменил его в будущем? С большинством ссылочных типов вы принимаете это как часть этого типа, но разработчики Java решили, что, по крайней мере, для строк, они не хотели, чтобы пользователи беспокоились об этом.
- Строки не могут обрабатываться атомарно, т.е. многопоточность/синхронизация станут проблемой.
- Строковые литералы (вещи, которые вы помещаете в код в кавычках) могут быть неизменными на уровне компьютера 1 (из соображений безопасности). Это можно было бы получить, скопировав их все в другую часть памяти при запуске программы или использовании copy-on-write, но это медленно.
Почему у нас нет версии строки типа value?
В основном, характеристики производительности и реализации, а также сложность наличия двух разных типов строк. Другие типы значений имеют фиксированный объем памяти. Int всегда 32 бита, длинный всегда 64 бит, bool всегда 1 бит и т.д. 2 Между прочим, это означает, что они могут быть сохранены в стеке, так что все параметры к функции жить в одном месте. Кроме того, создание гигантских копий строк по всему месту приведет к гибели производительности.
См. также: В С#, почему String является ссылочным типом, который ведет себя как тип значения?. Относится к .NET, но это так же применимо в Java.
1 - В C/С++ и других языках с компиляцией изначально это верно, потому что они помещаются в сегмент кода процесса, который ОС обычно останавливает вас от редактирования. В Java это на самом деле обычно неверно, поскольку JVM загружает файлы классов в кучу, поэтому вы можете редактировать строку там. Однако нет причин, по которым программа Java не может быть скомпилирована (есть инструменты, которые делают это), а некоторые архитектуры (в частности, некоторые версии ARM) непосредственно выполняют байт-код Java.
2 - На практике некоторые из этих типов различаются по размеру на уровне машины. E.x. bools хранятся как WORD-размер в стеке (32 бит на x86, 64 бит на x64). В классах/массивах к ним можно относиться по-разному. Это все детали реализации, которые остались до JVM - спецификация говорит, что bools являются истинными или ложными, и машина может понять, как это сделать.