Почему string неизменяемый и финализированный класс java
Перейти к содержимому

Почему string неизменяемый и финализированный класс java

  • автор:

Что такое классы-обертки?

Значение примитива становится объектом, чтобы выполнять различные операции ( .parseInt()).

Примитивы не имеют методов.

Объекты классов-оберток являются неизменяемыми (Immutable).

Что такое автоупаковка и автораспаковка?

Для присваивания ссылок-примитивов объектам их классов-оберток (и наоборот) не требуется ничего делать, все происходит автоматически

x = y; // автораспаковка

y = x * 123; // автоупаковка

Автоупаковка и распаковка не работают для массивов.

Автоупаковка — это механизм неявной инициализации объектов классов-оберток (Byte, Short, Integer, Long, Float, Double, Character, Boolean) значениями соответствующих им исходных примитивных типов (byte, short, int. ), без явного использования конструктора класса.

Автоупаковка происходит при прямом присваивании примитива классу-обертке (с помощью оператора =), либо при передаче примитива в параметры метода (типа класса-обертки).

Автоупаковке в классы-обертки могут быть подвергнуты как переменные примитивных типов, так и константы времени компиляции (литералы и final-примитивы). При этом литералы должны быть синтаксически корректными для инициализации переменной исходного примитивного типа.

Автоупаковка переменных примитивных типов требует точного соответствия типа исходного примитива типу класса-обертки.

Например, попытка упаковать переменную типа byte в Short, без предварительного явного приведения byte в short вызовет ошибку компиляции.

Автоупаковка констант примитивных типов допускает более широкие границы соответствия.

В этом случае компилятор способен предварительно осуществлять неявное расширение/сужение типа примитивов.

Неявное расширение/сужение исходного типа примитива до типа примитива соответствующего классу-обертке (для преобразования int в Byte, сначала компилятор самостоятельно неявно сужает int к byte) автоупаковку примитива в соответствующий класс-обертку.

Однако, в этом случае существуют два дополнительных ограничения:

a) присвоение примитива обертке может производится только оператором = (нельзя передать такой примитив в параметры метода без явного приведения типов)

b) тип левого операнда не должен быть старше чем Character, тип правого не должен старше, чем int.

Допустимо расширение/сужение byte в/из short, byte в/из char, short в/из char и только сужение byte из int, short из int, char из int. Все остальные варианты требуют явного приведения типов.

Дополнительной особенностью целочисленных классов-оберток созданных автоупаковкой констант в диапазоне -128 . +127 является то, что они кэшируются JVM. Поэтому такие обертки с одинаковыми значениями будут являться ссылками на один объект.

Приведение типов

Что такое явное и неявное приведение типов?
В каких случаях в JAVA нужно использовать явное приведение?

Каждое выражение и каждая переменная имеет строго определенный тип уже на момент компиляции. Механизм приведения типов (casting) — способ преобразования значения переменной одного типа в значение другого типа:

Неявные – выполняются автоматически (расширяющие преобразования, сужающие с потерей данных: int->float, long->float, long->double).

Явные – надо указывать тип (сужающие преобразования от типа с большей разрядностью к типу с меньшей разрядностью). Потеря данных (старшие биты будут потеряны).

Схема приведения типов

↓ИЗ | В→ boolean byte short char int long float double
boolean N N N N N N N
byte N Y C Y Y Y Y
short N C C Y Y Y Y
char N C C Y Y Y Y
int N C C C Y Y* Y
long N C C C C Y* Y*
float N C C C C C Y
double N C C C C C C

C — сужающее преобразование, требующее явного приведения

Y* — автоматическое расширяющее преобразование, в процессе которого значение может потерять некоторые из наименее значимых разрядов

Разновидности приведения:
    Тождественное (identity) — Преобразование выражения любого типа к точно такому же типу всегда допустимо и происходит автоматически.

Расширение (повышение, upcasting) примитивного типа (widening primitive) — Означает, что осуществляется переход от менее емкого типа к более ёмкому. Этот тип приведения всегда допустим и происходит автоматически.

Например, от типа byte (длина 8 бит) к типу int (длина 32 бита). Такие преобразование безопасны в том смысле, что новый тип всегда гарантировано вмещает в себя все данные, которые хранились в старом типе и таким образом не происходит потери данных.

Сужение (понижение, downcasting) примитивного типа (narrowing primitive) — Означает, что переход осуществляется от более емкого типа к менее емкому. При таком преобразовании есть риск потерять данные .

В Java такое преобразование должно совершаться явным образом, при этом все старшие биты, не умещающиеся в новом типе, просто отбрасываются — никакого округления или других действий для получения более корректного результата не производится.

Например, если число типа int было больше 127, то при приведении его к byte значения битов старше восьмого будут потеряны.

Сужение объектного типа (narrowing reference) — Означает нисходящее приведение, то есть приведение от предка к потомку (подтипу). Возможно только если исходная переменная является подтипом приводимого типа.

Требует явного указания типа. При несоответствии типов в момент выполнения выбрасывается исключение ClassCastException.

При приведении ссылочных типов с самим объектом ничего не происходит, меняется лишь тип ссылки, через которую происходит обращение к объекту.

Для проверки возможности приведения нужно воспользоваться оператором instanceof :

Parent parent = new Child();

if (parent instanceof Child) <

Child child = (Child) parent;

Что такое пул интов?

Для более эффективного использования памяти, в JAVA используются так называемые пулы.

Есть строковый пул, Integer pool и тд. Когда мы создаем объект не используя операцию new, объект помещается в пул, и в последствии, если мы захотим создать такой же объект (опять не используя new), новый объект создан не будет, а мы просто получим ссылку на наш объект из пула.

Особенность Integer-пула — он хранит только числа, которые помещаются в тип данных byte: от -128 до 127. Для остальных чисел пул не работает.

Integer i1 = 127;

Integer i2 = 127;

Integer i3 = 128;

Integer i4 = 128;

Какие нюансы у строк в Java?

Это неизменяемый (immutable) (не меняется после создания) и финализированный (без потомков) тип данных; потокобезопасный может использоваться в многопоточке

  • Все объекты класса String JVM хранит в пуле строк;
  • Объект класса String можно получить используя двойные кавычки;
  • Можно использовать оператор + для конкатенации строк;
  • Начиная с Java 7 строки можно использовать в конструкции switch.

Каждый объект можно привести к строке .toString

Что такое пул строк?

Пул строк – это набор строк хранящийся в Heap .

Пул строк возможен благодаря неизменяемости строк в Java и реализации идеи интернирования строк;

Интернирование строк — это механизм, при котором одинаковые литералы представляют собой один объект в памяти.

Пул строк помогает экономить память, но по этой же причине создание строки занимает больше времени;

Когда для создания строки используются » , то сначала ищется строка в пуле с таким же значением, если находится, то просто возвращается ссылка, иначе создается новая строка в пуле, а затем возвращается ссылка на неё;

При использовании оператора new создается новый объект String. Затем при помощи метода intern() эту строку можно поместить в пул или же получить из пула ссылку на другой объект String с таким же значением;

String r = new String(«I’m»);

String t = r.intern();

System.out.println(«q==w: » + (q==w)); //true

System.out.println(«q==r: » + (q==r)); //false

System.out.println(«q==t: » + (q==t)); //true

Пул строк является примером паттерна «Приспособленец» (Flyweight).

Почему String неизменяемый и финализированный класс?

  • Пул строк возможен только потому, что строка неизменяемая, таким образом виртуальная машина сохраняет больше свободного места в Heap, поскольку разные строковые переменные указывают на одну и ту же переменную в пуле. Если бы строка была изменяемой, то интернирование строк не было бы возможным, потому что изменение значения одной переменной отразилось бы также и на остальных переменных, ссылающихся на эту строку.
  • Если строка будет изменяемой, тогда это станет серьезной угрозой безопасности приложения. Например, имя пользователя базы данных и пароль передаются строкой для получения соединения с базой данных и в программировании сокетов реквизиты хоста и порта передаются строкой. Так как строка неизменяемая, её значение не может быть изменено, в противном случае злоумышленник может изменить значение ссылки и вызвать проблемы в безопасности приложения.
  • Неизменяемость позволяет избежать синхронизации: строки безопасны для многопоточности и один экземпляр строки может быть совместно использован различными потоками.
  • Строки используются classloader-ом и неизменность обеспечивает правильность загрузки класса.
  • Поскольку строка неизменяемая, её hashCode() кэшируется в момент создания и нет необходимости рассчитывать его снова. Это делает строку отличным кандидатом для ключа в HashMap т.к. его обработка происходит быстрее.

Какая основная разница между String, StringBuffer, StringBuilder?

Класс String String является неизменяемым ( immutable ) — модифицировать объект такого класса нельзя, можно лишь заменить его созданием нового экземпляра.

Класс StringBuffer изменяемый — использовать StringBuffer следует тогда, когда необходимо часто модифицировать содержимое. Потокобезопасный . Синхронизирован ные методы работают медленнее не сихнронизированных.

Класс StringBuilder был добавлен в Java 5 и он во всем идентичен классу StringBuffer за исключением того, что он не синхронизирован и поэтому его методы выполняются значительно быстрей .

Класс StringJoiner используется, чтобы создать последовательность строк, разделенных разделителем с возможностью присоединить к полученной строке префикс и суффикс:

StringJoiner joiner = new StringJoiner(«.», «prefix-«, «-suffix»);

for (String s : «Hello the brave world».split(» «)) <

Что такое сигнатура метода?

Объявление метода — это весь код, который описывает метод.

модификатор_доступа + тип_возвращаемого_значения + имя_метода(список_параметров) + исключения

Сигнатура — название метода и типы параметров в определенном порядке. methodName(double, int)

Контракт метода — сигнатура метода, в сочетании с типом возвращаемого значения. В контракт также входят типы возбуждаемых методом исключений.

Насколько я понял модификатор доступа ни куда не входит.

Каким образом переменные передаются в методы, по значению или по ссылке?

Java передает параметры по значению. Всегда.

Скопировать значение внутри х и записать эту копию в у.

Ссылка А копируется в ссылку B. К объекту это не относится — у нас по-прежнему всего один объект. Но теперь есть две различных ссылки, контролирующие один и тот же объект Cat.

Java String. Почему строки в Java неизменные и финализированные?

Строки в Java не являются примитивным типом данных, как например int или double. Первым делом String – это класс, прописанный в пакете java.lang и представляющий строковый набор символов. String — наиболее широко используемый класс в Java. Трудно себе представить приложение, не используемое строки.

Особенности класса String в Java заключаются в том, что строки это неизменяемый (immutable) и финализированный тип данных, и возможности хранения всех объектов класса String в пуле строк. Так же к особенностям можно отнести возможность получения объектов класса String используя двойные кавычки и перегруженный оператор “+” для сцепления(конкатенации) строк.

Так почему же строки в Java неизменяемые? При ответе на этот вопрос также становится понятно, являются ли строки в Java потокобезопасными, и почему строка является популярным ключем в HashMap?

У неизменности строк есть ряд неоспоримых преимуществ:

  • Строковый пул (String pool) возможен только благодаря тому, что строки в Java неизменяемы. Виртуальная машина имеет возможность сохранить много места в памяти (heap space) т.к. разные строковые переменные указывают на одну переменную в пуле. При изменяемости строк было бы невозможно реализовать интернирование, поскольку если какая-либо переменная изменит значение, это отразится также и на остальных переменных, ссылающихся на эту строку.
  • Изменяемость строк несло бы в себе потенциальную угрозу безопасности приложения. Поскольку в Java строки используются для передачи параметров для авторизации, открытия файлов и т.д. — неизменяемость позволяет избежать проблем с доступом.
  • Так как строка неизменяемая то, она безопасна для много поточности и один экземпляр строки может быть совместно использован различными потоками. Это позволяет избежать синхронизации для потокобезопасности. Таким образом, строки в Java полностью потокобезопасны.
  • Поскольку строка неизменная, её hashcode кэшируется в момент создания и нет никакой необходимости рассчитывать его снова. Это делает строку отличным кандидатом для ключа в Map и его обработка будет быстрее, чем других ключей HashMap. Поэтому строка наиболее часто используется в качестве ключа HashMap.

Если резюмировать вышесказанное, то получаем, что основные причины неизменяемости String в Java это безопасность и наличие пула строк (String pool).

  • можно передавать строку между потоками не опасаясь, что она будет изменена
  • отсутствуют проблемы с синхронизацией потоков
  • отсутствие проблем с утечкой памяти
  • отсутствие проблем с доступом и безопасностью при использовании строк для передачи параметров авторизации, открытия файлов и т.д.
  • кэширование hashcode
  • Экономия памяти при использовании пула строк для хранения повторяющихся строк.

Если нужно изменять строки то, есть StringBuffer/StringBuilder. (Чем они отличаются?)

Do You Know Immutable Class in Java? Why String is Immutable?

Everything about Immutability — What, How, and When.

Vikram Gupta

Javarevisited

Hey, this article is about mutability and immutability in Java. I’ll be explaining immutable classes, their advantages, how to create them, and finally why string class is immutable.

What Is an Immutable Class in Java?

Immutable class means once the object of the class is created its fields cannot be modified or changed. In Java, all the wrapper classes like Boolean, Short, Integer, Long, Float, Double, Byte, Char, and String classes are immutable classes.

What Are the Advantages of Immutable Classes?

The following are the advantages of immutable classes or objects:

  1. Object fields (state) cannot be changed or modified.
  2. It can be passed to any method without worrying about whether that method changes or modifies any of the object fields.
  3. The object’s hash code can easily be cached.
  4. These objects are a good choice for keys for Maps.
  5. These objects are good for a multi-threaded environment as the object’s state won’t change.
  6. An immutable object’s state won’t change, so the same object can be used at multiple places and hence saving memory.

How to Create an Immutable Class in Java?

A simple java POJO class can be easily converted to an Immutable class by following the below steps :

I have written two POJO classes Employee and Company. The company is an attribute of the Employee class. We are going to make Employee an Immutable class by using the above 5 steps mentioned. The Company class will remain the same everywhere in this article.

Company class :

1. Do Not Write Setters for Class:

By removing or not writing setters for object fields, the programmer has no choice but to change the object field values using the setters methods.

Employee class :

You may have observed that I’ve skipped the setter methods for object fields for the Employee class. so that no one can change the object field values using setter methods.

2. Include an All Argument Constructor:

By including an all argument constructor in the class we are allowed to initialize the object fields at the time of object creation only.

Employee class :

3. Make Class As Final:

By making our Employee class final, this class cannot be extended by any other class, and hence the object of our final class cannot be modified by any other classes as no other classes would be able to extend it.

Employee class :

4. Use Deep Clone for Mutable Fields in the Constructor:

By using deep cloning for mutable fields which are passed to an all argument constructor while creating the object, we are making sure there won’t be any reference for cloned fields of the object so that no one can modify this object.

Employee class :

If we directly use the company reference which is being passed to the constructor to assign the value to the company field of Employee class then using this reference, one can change the companyName or companySize fields of the reference passed to the constructor as Company class is a mutable class.

Hence deep clone of company reference is created using a new operator and then assigned to the company field of Employee class.

5. Return a Deep Cloned Object of Mutable Fields of Class From Getter Methods:

By returning deep cloned objects for mutable fields of the Employee class from getter methods, there won’t be a reference to the actual mutable field of the class and hence no one can change or modify the mutable field of the object of the Employee class.

Employee class :

Finally, we have Employee as an Immutable class whose object state won’t change.

NOTE : Optionally all the fields of Employee class can be declared as final so that it cannot be modified elsewhere .

Why Is String Immutable?

The following are the main reasons for string immutability :

1. Use of String Constant Pool:

The string pool refers to a collection of string literals stored in the heap memory area. When multiple string variables contain the same string literal, they can refer to the same string object in the string pool. This concept allows the Java Virtual Machine to save memory efficiently. The diagram below illustrates the idea of the string pool.

2. Security :

In Java, strings are commonly utilized to store sensitive information such as user names and passwords. If strings were mutable, there would be a risk of these strings being altered by malicious individuals. Thus, it would not be secure to store sensitive information as mutable strings.

3. Thread-Safety :

Because string objects are immutable, accessing them from multiple threads does not result in changes, making them safer for use in a multithreaded environment. Additionally, the same string object can be shared among multiple threads.

4. Cacheable HashCode :

Strings are the most widely used objects in any java application. They are used in HashMap , HashTable , HashSet , etc. . Also note that the overridden hashCode() method of the String class is quite frequently called for bucketing.

As strings are immutable and hence, they won’t change, and hence when first-time hashCode() is called the hashcode of the string object that is cached and later on, for frequent hashCode() method calls the same value is returned.

If we would have used the mutable objects with Collections like HashMap , HashSet , or HashTable , there could have been different hashcodes, one when object contents are not modified and the other when object contents are modified. Hence mutable objects should not be used as keys in the case of Map data structures, if they are used in Maps, then we might lose the value associated with the keys in Map.

5. Improved Performance :

Typically, performance and memory usage are closely related. By using the string pool, multiple string variables that have the same contents only occupy a single instance in the pool, as explained in the previous point. This reduction in memory usage in the JVM’s heap leads to improved performance of the application.

Thank you for reading this article. I hope I have covered all corners of Immutable classes and Strings.

You Can Follow Vikram Gupta For Similar Content.

You may like to read the following interview questions:

Java String. Вопросы к собеседованию и ответы на них, ч.2

Java String. Вопросы к собеседованию и ответы на них, ч.2 - 1

К сожалению статья не поместилась одним фрагментом, пришлось разбить её на две части. Начало смотрите тут

12. Напишите функцию для нахождения самого длинного палиндрома в данной строке

13. Какие различия между String, StringBuffer и StringBuilder

14. Почему строка неизменная и финализированная в Java

Строковый пул возможен только потому, что строка неизменна в Java, таким образом виртуальная машина сохраняет много места в памяти (heap space), поскольку разные строковые переменные указывают на одну переменную в пуле. Если бы строка не была неизмененяемой, тогда бы интернирование строк не было бы возможным, потому что если какая-либо переменная изменит значение, это отразится также и на остальных переменных, ссылающихся на эту строку.

Если строка будет изменяемой, тогда это станет серьезной угрозой безопасности приложения. Например, имя пользователя базы данных и пароль передаются строкой для получения соединения с базой данных и в программировании сокетов реквизиты хоста и порта передаются строкой. Так как строка неизменяемая, её значение не может быть изменено, в противном случае любой хакер может изменить значение ссылки и вызвать проблемы в безопасности приложения.

Так как строка неизменная, она безопасна для много поточности и один экземпляр строки может быть совместно использован различными нитями. Это позволяет избежать синхронизации для потокобезопасности, строки полностью потокобезопасны.

Строки используются в Java classloader и неизменность обеспечивает правильность загрузки класса при помощи Classloader . К примеру, задумайтесь об экземпляре класса, когда вы пытаетесь загрузить java.sql.Connection класс, но значение ссылки изменено на myhacked.Connection класс, который может осуществить нежелательные вещи с вашей базой данных.

Поскольку строка неизменная, её hashcode кэшируется в момент создания и нет необходимости рассчитывать его снова. Это делает строку отличным кандидатом для ключа в Map и его обработка будет быстрее, чем других ключей HashMap . Это причина, почему строка наиболее часто используемый объект, используемый в качестве ключа HashMap .

15. Как разделить строку на части?

16. Почему массив строк предпочтительнее строки для хранения пароля?

17. Как вы проверите две строки на подобность в Java?

18. Что такое пул строк?

Java String. Вопросы к собеседованию и ответы на них, ч.2 - 2

Как подсказывает название, пул строк – это набор строк, который хранится в памяти Java heap. Мы знаем, что String это специальный класс в Java, и мы можем создавать объекты этого класса, используя оператор new точно так же, как и создавать объекты, предоставляя значение строки в двойных кавычках. Диаграмма ниже объясняет, как пул строк размещается в памяти Java heap и что происходит, когда мы используем различные способы создания строк. Пул строк возможен исключительно благодаря неизменяемости строк в Java и реализации идеи интернирования строк. Пул строк также является примером паттерна Приспособленец (Flyweight). Пул строк помогает экономить большой объем памяти, но с другой стороны создание строки занимает больше времени. Когда мы используем двойные кавычки для создания строки, сначала ищется строка в пуле с таким же значением, если находится, то просто возвращается ссылка, иначе создается новая строка в пуле, а затем возвращается ссылка. Тем не менее, когда мы используем оператор new, мы принуждаем класс String создать новый объект строки, а затем мы можем использовать метод intern() для того, чтобы поместить строку в пул, или получить из пула ссылку на другой объект String с таким же значением. Ниже приведен пример, показывающий работу пула строк. Программа выведет следующее:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *