#java #data-structures #primitive-types
#java #структуры данных #примитивные типы
Вопрос:
Мне интересно, почему параметр для метода indexOf является int , когда в описании указано значение char.
public int indexOf(int ch)
Returns the index within this string of the first occurrence of the specified **character**
http://download.oracle.com/javase/1,5.0/docs/api/java/lang/String.html#indexOf(int)
Also, both of these compiles fine:
char c = 'p';
str.indexOf(2147483647);
str.indexOf(c);
a] В принципе, что меня смущает, так это то, что int в java равен 32 битам, в то время как символы Unicode равны 16 битам.
b] Почему бы не использовать сами символы вместо использования int . Является ли это какой-либо оптимизацией производительности?. Сложнее ли представлять символы, чем int? Как?
Я предполагаю, что это должно быть простое обоснование для этого, и это заставляет меня знать об этом еще больше!
Спасибо!
Ответ №1:
Реальная причина в том, что indexOf(int)
ожидается кодовая точка Unicode, а не 16-битный «символ» UTF-16. Кодовые точки Unicode на самом деле имеют длину до 21 бита.
(Представление более длинной кодовой точки в формате UTF-16 на самом деле представляет собой 2 16-битных «символьных» значения. Эти значения известны как начальные и конечные суррогаты; D80016 для DBFF16 и DC0016 для DFFF16 соответственно; смотрите Часто задаваемые вопросы по Unicode — UTF-8, UTF-16, UTF-32 amp; BOM для получения подробных сведений.)
Если вы укажете indexOf(int)
кодовую точку > 65535, он будет искать пару символов UTF-16, которые кодируют кодовую точку.
Это указано javadoc (хотя и не очень четко), и изучение кода показывает, что это действительно то, как реализован метод.
Почему бы просто не использовать 16-разрядные символы?
Это довольно очевидно. Если бы они это сделали, не было бы простого способа найти кодовые точки, превышающие 65535 в строках. Это было бы серьезной проблемой для людей, которые разрабатывают интернационализированные приложения, где текст может содержать такие кодовые точки. (Многие предположительно интернационализированные приложения делают неверное предположение, что char
представляет кодовую точку. Часто это не имеет значения, но все чаще это имеет значение.)
Но для вас это не должно иметь никакого значения. Метод все равно будет работать, если ваши строки состоят только из 16-битных кодов … или, если на то пошло, только из кодов ASCII.
Комментарии:
1. Спасибо за ответ. хорошо, теперь я вижу, что indexOf (int) ожидает кодовую точку Unicode, мой другой вопрос был .. почему это? . Почему бы просто не использовать 16-разрядные символы?
2. Потому что символ Unicode на самом деле равен 22 битам, а не 16. Итак, существуют «символы / буквы» (кодовые точки), которые не могут быть сохранены в java char. Вот почему строка Java может использовать 2 символа для хранения одной ‘кодовой точки / буквы’ (смотрите суррогатные пары utf-16, если вы действительно хотите знать).
Ответ №2:
Символы в Java хранятся в их целочисленном представлении в Юникоде. Документация по классу Character содержит более подробную информацию об этом формате.
Из документов на этой странице:
Методы, которые принимают значение int, поддерживают все символы Юникода, включая дополнительные символы. Например, Character.isLetter(0x2F81A) возвращает true, потому что значение кодовой точки представляет букву (идеограф CJK).
Комментарии:
1. Thnx. 2 инструкции из документа: младший (наименее значимый) 21 бит int используется для представления кодовых точек Unicode, а верхние (наиболее значимые) 11 бит должны быть равны нулю. Спецификация Unicode, которая определяет символы как 16-разрядные объекты фиксированной ширины, поэтому, если unicode состоит из 16 бит, зачем использовать 21 бит для их представления?
2. Да, но строки представляют собой байт [] под обложками, закодированный как UTF-8. Стандартные символы (0-255) занимают только один байт (не два байта, которые занимал бы символ полной ширины). Символы старше 255 занимают несколько байт, иногда более 2 байт. Закодированный символ имеет целочисленный (32-разрядный) эквивалент — это то, что ищет indexOf()
3. @p1 Юникод не был 16-разрядным в течение очень долгого времени. Unicode 2.0 снял 16-разрядное ограничение, и это было ПЯТНАДЦАТЬ лет назад (я чувствую себя старым). Технически ISO-10646 является 31-разрядным адресным пространством, и Unicode теоретически может представлять любое из них. В действительности UTF-16 ограничен 21 битами, и Unicode фактически обязался поддерживать только эти 21 бит. Крайне маловероятно, что ISO-10646 когда-либо будет разрешено не синхронизироваться с Unicode таким образом, который нарушил бы UTF-16, поэтому 21-разрядность фактически теперь является жестко заданным ограничением.
4. @Bohemian — Ваш комментарий о том, что строка находится
byte[]
под обложками, неверен. Обычное представление в памяти используетchar[]
… не UTF-8.5. @StephenC Тогда я был еще тупее : / — Поставил вам оценку за то, что вы вернулись к поиску этого в комментарии (вы, должно быть, экстрасенс или одержимый :))
Ответ №3:
Метод str.indexOf(int)
принимает значение int. Если вы передадите char
в него, java приведет char
к int
, поскольку char
это 16-разрядное число.
Ответ №4:
В Java есть множество неявных правил приведения типов, выполняемых под капотом. Для примитивов существуют специальные правила, которые все описаны в документе «Преобразования и рекламные акции«, являющемся частью документации Sun по Java. Что касается вашего конкретного вопроса, преобразование int в char является «сужающим примитивным преобразованием». Смотрите раздел 5.1.3 в приведенном выше документе.
При этом обычной практикой программирования является обмен небольшими целыми положительными числами и символами, которые кодируются как целые числа. Это восходит к их использованию, неотличимому от использования в C, когда существовал только ASCII.