Защо String е неизменяем в Java?

1. Въведение

В Java низовете са неизменни. Очевиден въпрос, който е доста разпространен в интервютата, е „Защо струните са проектирани като неизменяеми в Java?“

Джеймс Гослинг, създателят на Java, веднъж беше попитан в интервю кога трябва да се използват неизменяеми, на което той отговаря:

Бих използвал неизменяем, когато мога.

Освен това той подкрепя аргумента си, като посочва функции, които предоставя неизменността, като кеширане, сигурност, лесно повторно използване без репликация и т.н.

В този урок ще разгледаме допълнително защо дизайнерите на езика Java са решили да запазят String неизменен.

2. Какво представлява неизменяем обект?

Неизменим обект е обект, чието вътрешно състояние остава постоянно, след като е изцяло създадено . Това означава, че след като обектът е присвоен на променлива, ние не можем нито да актуализираме референцията, нито да мутираме вътрешното състояние по никакъв начин.

Имаме отделна статия, която разглежда подробно неизменяемите обекти. За повече информация прочетете статията за неизменяеми обекти в Java.

3. Защо String е неизменяем в Java?

Основните предимства на запазването на този клас като неизменяем са кеширането, защитата, синхронизацията и производителността.

Нека да обсъдим как работят тези неща.

3.1. Въведете String Pool

Най- String е най-широко използваният структурата на данните. Кеширането на Stral литералите и повторното им използване спестява много място в купчина, защото различни променливи String се отнасят до един и същ обект в String pool. String intern pool служи точно за тази цел.

Java String Pool е специалният регион на паметта, където низовете се съхраняват от JVM . Тъй като низовете са неизменни в Java, JVM оптимизира количеството памет, разпределена за тях, като съхранява само едно копие от всеки литерален низ в пула. Този процес се нарича интерниране:

String s1 = "Hello World"; String s2 = "Hello World"; assertThat(s1 == s2).isTrue();

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

Имаме отделна статия, посветена на Java String Pool. За повече информация преминете към тази статия.

3.2. Сигурност

Най- String се използва широко в Java приложения за съхранение на лични части от информацията, като потребителски имена, пароли, адреси за връзка, мрежови връзки и т.н. Това е също така широко използвани от клас товарачи JVM при зареждането на класове.

Следователно осигуряването на клас String е от решаващо значение за сигурността на цялото приложение като цяло. Например, помислете за този прост кодов фрагмент:

void criticalMethod(String userName) { // perform security checks if (!isAlphaNumeric(userName)) { throw new SecurityException(); } // do some secondary tasks initializeDatabase(); // critical task connection.executeUpdate("UPDATE Customers SET Status = 'Active' " + " WHERE UserName = '" + userName + "'"); }

В горния кодов фрагмент, да кажем, че получихме обект String от ненадежден източник. Първоначално правим всички необходими проверки за сигурност, за да проверим дали низът е само буквено-цифров, последван от още някои операции.

Не забравяйте, че нашият ненадежден метод за повикващ източник все още има препратка към този обект userName .

Ако низовете бяха променливи, тогава докато изпълним актуализацията, не можем да сме сигурни, че низът, който получихме, дори след извършване на проверки за сигурност, ще бъде в безопасност. Методът на ненадежден повикващ все още има препратка и може да промени низа между проверките на целостта. По този начин правим нашата заявка податлива на SQL инжекции в този случай. Така че променливите струни могат да доведат до влошаване на сигурността с течение на времето.

Тя също може да се случи, че String потребителско име е видимо за друга тема, която може след това да промените стойността си, след като проверката за цялост.

Като цяло неизменността ни идва на помощ в този случай, защото е по-лесно да се работи с чувствителен код, когато стойностите не се променят, тъй като има по-малко преплитания на операции, които могат да повлияят на резултата.

3.3. Синхронизация

Неизменяемостта автоматично прави нишката String безопасна, тъй като те няма да бъдат променени при достъп от множество нишки.

Следователно неизменяемите обекти като цяло могат да се споделят в множество нишки, работещи едновременно. Те също са безопасни за нишки, защото ако нишка променя стойността, вместо да я модифицира, в String pool ще бъде създаден нов String . Следователно струните са безопасни за многопоточност.

3.4. Кеширане на Hashcode

Тъй като String обектите се използват в изобилие като структура на данни, те също се използват широко в хеш реализации, като HashMap , HashTable , HashSet и др. Когато се работи с тези хеш реализации, методът hashCode () се извиква доста често за групиране.

Неизменността гарантира низовете, че стойността им няма да се промени. Така че на хеш-код () метод е засегнато в String клас за улесняване на кеширане, така че хеша се изчислява и кеширана през първата хеш-код () повикване и съща стойност се връща и досега.

Това от своя страна подобрява производителността на колекции, които използват хеш реализации, когато се експлоатират с String обекти.

От друга страна, променливите низове биха генерирали два различни хеш кода по време на вмъкване и извличане, ако съдържанието на String е модифицирано след операцията, потенциално губейки стойностния обект в Map .

3.5. производителност

Както видяхме по-рано, String pool съществува, защото Strings са неизменни. На свой ред, той подобрява производителността, като спестява куп памет и по-бърз достъп до хеш реализации, когато се работи със Strings.

Тъй като String е най-широко използваната структура от данни, подобряването на производителността на String има значителен ефект върху подобряването на ефективността на цялото приложение като цяло.

4. Заключение

Чрез тази статия можем да заключим, че низовете са неизменни точно, така че техните препратки могат да се третират като нормална променлива и човек може да ги предава между методи и между нишки, без да се притеснява дали действителният обект String , към който сочи, ще се промени.

Също така научихме какви биха могли да бъдат другите причини, които подтикнаха дизайнерите на езици Java да направят този клас неизменен.