Собеседование по Java — работа со строками (String in Java) (вопросы и ответы)
Список вопросов и ответов для собседования по Java по теме «Работа со строками».
К списку вопросов по всем темам
Вопросы
1. Какие “строковые” классы вы знаете?
2. Какие основные свойства “строковых” классов (их особенности)?
3. Можно ли наследовать строковый тип, почему?
4. Дайте определение понятию конкатенация строк.
5. Как преобразовать строку в число?
6. Как сравнить значение двух строк?
7. Как перевернуть строку?
8. Как работает сравнение двух строк?
9. Как обрезать пробелы в конце строки?
10. Как заменить символ в строке?
11. Как получить часть строки?
12. Дайте определение понятию “пул строк”.
13. Какой метод позволяет выделить подстроку в строке?
14. Как разбить строку на подстроки по заданному разделителю?
15. Какой метод вызывается для преобразования переменной в строку?
16. Как узнать значение конкретного символа строки, зная его порядковый номер в строке?
17. Как найти необходимый символ в строке?
18. Можно ли синхронизировать доступ к строке?
19. Что делает метод intern()?
20. Чем отличаются и что общего у классов String, StringBuffer и StringBuilder?
21. Как правильно сравнить значения строк двух различных объектов типа String и StringBuffer?
22. Почему строка неизменная и финализированная в Java?
23. Почему массив символов предпочтительнее строки для хранения пароля?
24. Почему строка является популярным ключом в HashMap в Java?
25. Напишите метод удаления данного символа из строки.
Ответы
1. Какие “строковые” классы вы знаете?
- public final class String implements java.io.Serializable, Comparable<String>, CharSequence
- public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence
- public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence
2. Какие основные свойства “строковых” классов (их особенности)?
Все строковые классы — final (следовательно от них нельзя унаследоваться).
String.
Строка — объект, что представляет последовательность символов. Для создания и манипулирования строками Java платформа предоставляет общедоступный финальный (не может иметь подклассов) класс java.lang.String. Данный класс является неизменяемым (immutable) — созданный объект класса String не может быть изменен.
StringBuffer
Строки являются неизменными, поэтому частая их модификация приводит к созданию новых объектов, что в свою очередь расходует драгоценную память. Для решения этой проблемы был создан класс java.lang.StringBuffer, который позволяет более эффективно работать над модификацией строки. Класс является mutable, то есть изменяемым — используйте его, если Вы хотите изменять содержимое строки. StringBuffer может быть использован в многопоточных средах, так как все необходимые методы являются синхронизированными.
StringBuilder
StringBuilder — класс, что представляет изменяемую последовательность символов. Класс был введен в Java 5 и имеет полностью идентичный API с StringBuffer. Единственное отличие — StringBuilder не синхронизирован. Это означает, что его использование в многопоточных средах нежелательно. Следовательно, если вы работаете с многопоточностью, Вам идеально подходитStringBuffer, иначе используйте StringBuilder, который работает намного быстрее в большинстве реализаций.
Обработка строк в Java. Часть I: String, StringBuffer, StringBuilder: http://habrahabr.ru/post/260767/
3. Можно ли наследовать строковый тип, почему?
Классы объявлены final, поэтому наследоваться не получится.
4. Дайте определение понятию конкатенация строк.
Конкатенация — операция объединения строк, что возвращает новую строку, что является результатом объединения второй строки с окончанием первой. Операции конкатенации могут быть выполнены так:
1 2 3 4 5 6 7 8 9 10 11 |
StringBuffer stringBuffer = new StringBuffer(); StringBuilder stringBuilder = new StringBuilder(); String str = "ABC"; str += "DEF"; String str2 = "one".concat("two").concat("three"); stringBuffer.append("DDD").append("EEE"); stringBuilder.append("FFF").append("GGG"); System.out.println(str + " " +str2 + " " + stringBuffer.toString() + " " + stringBuilder.toString());//ABCDEF onetwothree DDDEEE FFFGGG |
Сравнение производительности конкатенации строк:
Оператор ‘+=’ > 92.243 с;
String.concat() > 1.254 с;
StringBuffer > 1.208 с;
StringBuilder > 1.121 с.
Конкатенация и настройки JVM: http://microfork.com/string-concatenation-java/
5. Как преобразовать строку в число?
У каждой обертки для примитивов есть свой метод valueOf(String s), который возвращает преобразованное численное значение из строки. При этом форматы строки и принимаемого типа должны совпадать. Например:
1 2 3 4 5 6 |
String x = "523.5"; Double xd = Double.valueOf(x); /* Integer xy = Integer.valueOf(x); //java.lang.NumberFormatException: For input string: "523.5" */ System.out.println(xd); //523.5 |
6. Как сравнить значение двух строк?
Оператор == работает с ссылками объекта String. Если две переменные String указывают на один и тот же объект в памяти, сравнение вернет результат true. В противном случае результат будет false, несмотря на то что текст может содержать в точности такие же символы. Оператор == не сравнивает сами данные типа char. Для сравнения посимвольно необходимо использовать метод equals();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
String s1 = new String("ABC"); String s2 = new String("ABC"); String s3 = "ABC"; String s4 = "ABC"; System.out.println(s1==s2); //false System.out.println(s3==s4); //true. Т.к. один набор литералов будет указывать на одну область памяти System.out.println(s1.equals(s2));//true s1=s2; System.out.println(s1==s2); //true if("someString" == "someString") { //true System.out.println("true"); } System.out.println(s1.compareTo(s2)); //0 System.out.println("C".compareTo("A")); //2 System.out.println("A".compareTo("C")); //-2 |
7. Как перевернуть строку?
1 2 3 4 |
String s = "ABCDEFG"; StringBuilder stringBuilder = new StringBuilder(s); stringBuilder.reverse(); System.out.println(stringBuilder.toString()); //GFEDCBA |
Можно и алгоритмом переставляя каждый char, но это на ваше усмотрение:).
8. Как работает сравнение двух строк?
Строка в Java — это отдельный объект, который может не совпадать с другим объектом, хотя на экране результат выводимой строки может выглядеть одинаково. Просто Java в случае с логическим оператором == (а также !=) сравнивает ссылки на объекты.
Метод equals сравнивает посимвольно на эквивалентность.
9. Как обрезать пробелы в конце строки?
1 2 3 |
String s = "a "; System.out.println(s.trim() + "b");//ab System.out.println(s + "b");//a b |
10. Как заменить символ в строке?
Можно использовать метод replace(CharSequence target, CharSequence replacement), который меняет символы в строке. Можно преобразовать в массив символов и заменить символ там. Можно использовать StringBuilder и метод setCharAt(int index, char ch)
1 2 3 4 5 6 7 8 9 |
String sb = "AABAA"; String s = "ABCDEF".replace("C", "**"); String sb2 = sb.replace(sb, "##"); System.out.println(s + " " + sb2); //AB**DEF and ## String fs = "123456789"; char[] charSequence = fs.toCharArray(); charSequence[3] = ' |
11. Как получить часть строки?
Метод substring(int beginIndex, int lastIndex) — возвращает часть строки по указанным индексам.
1 2 3 4 |
String fs = "123456789"; String sub = fs.subSequence(3,6).toString(); String sub2 = fs.substring(3,6); System.out.println(sub2); //456 |
12. Дайте определение понятию “пул строк”.
Пул строк – это набор строк, который хранится в памяти Java heap. Мы знаем, что String это специальный класс в Java, и мы можем создавать объекты этого класса, используя оператор new точно так же, как и создавать объекты, предоставляя значение строки в двойных кавычках.
Диаграмма ниже объясняет, как пул строк размещается в памяти Java heap и что происходит, когда мы используем различные способы создания строк.
Пул строк возможен исключительно благодаря неизменяемости строк в Java и реализации идеи интернирования строк. Пул строк также является примером паттерна Приспособленец (Flyweight).
Пул строк помогает экономить большой объем памяти, но с другой стороны создание строки занимает больше времени.
Когда мы используем двойные кавычки для создания строки, сначала ищется строка в пуле с таким же значением, если находится, то просто возвращается ссылка, иначе создается новая строка в пуле, а затем возвращается ссылка.
Тем не менее, когда мы используем оператор new, мы принуждаем класс String создать новый объект строки, а затем мы можем использовать метод intern() для того, чтобы поместить строку в пул, или получить из пула ссылку на другой объект String с таким же значением.
Ниже приведен пример, показывающий работу пула строк.
1 2 3 4 5 6 |
String s1 = "Cat"; String s2 = "Cat"; String s3 = new String("Cat"); System.out.println("s1 == s2 :"+(s1==s2)); //s1 == s2 :true System.out.println("s1 == s3 :"+(s1==s3)); //s1 == s3 :false |
13. Какой метод позволяет выделить подстроку в строке?
В дополнении к «как получить часть строки» можно использовать метод string.indexOf(char c), который вернет индекс первого вхождения символа. Таким образом потом можно использовать этот номер для выделения подстроки с помощью substring();
14. Как разбить строку на подстроки по заданному разделителю?
Мы можем использовать метод split(String regex) для разделения строки на массив символов, используя в качестве разделителя регулярное выражение. Метод split(String regex, int numOfStrings) является перегруженным методом для разделения строки на заданное количество строк. Мы можем использовать обратную черту для использования специальных символов регулярных выражений в качестве обычных символов.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
String line = "I am a java developer"; String[] words = line.split(" "); String[] twoWords = line.split(" ", 2); System.out.println("String split with delimiter: "+Arrays.toString(words));//String split with delimiter: [I, am, a, java, developer] System.out.println("String split into two: "+Arrays.toString(twoWords));//String split into two: [I, am a java developer] //split string delimited with special characters String wordsWithNumbers = "I|am|a|java|developer"; String[] numbers = wordsWithNumbers.split("\\|"); System.out.println("String split with special character: "+ Arrays.toString(numbers));//String split with special character: [I, am, a, java, developer] |
15. Какой метод вызывается для преобразования переменной в строку?
1 2 3 |
public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); } |
16. Как узнать значение конкретного символа строки, зная его порядковый номер в строке?
str.charAt(int i) вернет символ по индексу.
17. Как найти необходимый символ в строке?
str.indexOf(char ch) или lastIndexOf(char c) — вернет индекс первого и последнего вхождения символа.
1 2 3 |
String fs = "12345678904"; int a = fs.indexOf("456"); //3 int b = fs.lastIndexOf("4"); //10 |
18. Можно ли синхронизировать доступ к строке?
String сам по себе потокобезопасный класс. Если мы работаем с изменяемыми строками, то нужно использовать StringBuffer.
19. Что делает метод intern()?
Когда метод intern() вызван, если пул строк уже содержит строку, эквивалентную к нашему объекту, что подтверждается методом equals(Object), тогда возвращается ссылка на строку из пула. В противном случае объект строки добавляется в пул и ссылка на этот объект возвращается.
Этот метод всегда возвращает строку, которая имеет то же значение, что и текущая строка, но гарантирует что это будет строка из пула уникальных строк.
Ниже приведен пример работы метода intern()
1 2 3 4 5 6 7 |
String a = "string a"; String b = new String("string a"); String c = b.intern(); System.out.println(a == b); //false System.out.println(b == c); //false System.out.println(a == c); //true |
20. Чем отличаются и что общего у классов String, StringBuffer и StringBuilder?
В дополнение к ответу вначале приведу сравнение производительности классов.
Сравнение производительности. Linux
Класс | Open JDK 1.6.0_18 | HotSpot 1.6.0_20 | JRockit 4.0.1 |
---|---|---|---|
String | 27390ms | 26850ms | 26940ms |
StringBuffer | 35.55ms | 34.87ms | 15.41ms |
StringBuilder | 33.01ms | 31.78ms | 12.82ms |
Сравнение производительности. Windows XP:
Класс | HotSpot 1.6.0_20 | JRockit 4.0.1 |
---|---|---|
String | 55260ms | 45330ms |
StringBuffer | 19.38ms | 14.50ms |
StringBuilder | 16.83ms | 12.76ms |
21. Как правильно сравнить значения строк двух различных объектов типа String и StringBuffer?
Привести их к одному типу и сравнить.
22. Почему строка неизменная и финализированная в Java?
Есть несколько преимуществ в неизменности строк:
- Строковый пул возможен только потому, что строка неизменна в Java, таким образом виртуальная машина сохраняет много места в памяти(heap space), поскольку разные строковые переменные указывают на одну переменную в пуле. Если бы строка не была неизмененяемой, тогда бы интернирование строк не было бы возможным, потому что если какая-либо переменная изменит значение, это отразится также и на остальных переменных, ссылающихся на эту строку.
- Если строка будет изменяемой, тогда это станет серьезной угрозой безопасности приложения. Например, имя пользователя базы данных и пароль передаются строкой для получения соединения с базой данных и в программировании сокетов реквизиты хоста и порта передаются строкой. Так как строка неизменяемая, её значение не может быть изменено, в противном случае любой хакер может изменить значение ссылки и вызвать проблемы в безопасности приложения.
- Так как строка неизменная, она безопасна для многопоточности и один экземпляр строки может быть совместно использован различными потоками. Это позволяет избежать синхронизации для потокобезопасности, строки полностью потокобезопасны.
- Строки используются в Java classloader и неизменность обеспечивает правильность загрузки класса при помощи Classloader. К примеру, задумайтесь об экземпляре класса, когда вы пытаетесь загрузить java.sql.Connection класс, но значение ссылки изменено на myhacked.Connection класс, который может осуществить нежелательные вещи с вашей базой данных.
- Поскольку строка неизменная, её hashcode кэшируется в момент создания и нет необходимости рассчитывать его снова. Это делает строку отличным кандидатом для ключа в Map и его обработка будет быстрее, чем других ключей HashMap. Это причина, почему строка наиболее часто используемый объект в качестве ключа HashMap.
23. Почему массив символов предпочтительнее строки для хранения пароля?
Строка неизменяемая в Java и хранится в пуле строк. С тех пор, как она была создана, она остается в пуле, пока не будет удалена сборщиком мусора, поэтому, когда мы думаем, что закончили работу с паролем, он остается доступным в памяти некоторое время, и нет способа избежать этого. Это риск безопасности, поскольку кто-либо, имеющий доступ к дампу памяти сможет найти пароль в виде чистого текста.
Если мы используем массив символов для хранения пароля, мы можем очистить его после того, как закончим с ним работать. Таким образом, мы можем контролировать, как долго он находится в памяти, что позволяет избежать риска безопасности, свойственного строке.
24. Почему строка является популярным ключом в HashMap в Java?
Поскольку строки неизменны, их хэшкод кэшируется в момент создания, и не требует повторного пересчета. Это делает строки отличным кандидатом для ключа в Map и они обрабатываются быстрее, чем другие объекты-ключи HashMap. Вот почему строки преимущественно используются в качестве ключей HashMap.
25. Напишите метод удаления данного символа из строки.
Мы можем использовать метод replaceAll для замены всех вхождений в строку другой строкой. Обратите внимание на то, что метод получает в качестве аргумента строку, поэтому мы используем класс Character для создания строки из символа, и используем её для замены всех символов на пустую строку.
1 2 3 4 5 |
public static String removeChar(String str, char ch) { if (str == null) return null; return str.replaceAll(Character.toString(ch), ""); } |
http://goo.gl/K38JMG — Java String. Вопросы к собеседованию и ответы на них, ч.1. info.javarush.ru
http://goo.gl/OxO2I0 — Java String. Вопросы к собеседованию и ответы на них, ч.2
К списку вопросов по всем темам
6411 thoughts on “Собеседование по Java — работа со строками (String in Java) (вопросы и ответы)”
Добавить комментарий
Для отправки комментария вам необходимо авторизоваться.
Для удобства работы в String есть еще одна функция — toCharArray, которая возвращает в выходном массиве типа char всю строку.
Да всё верно. В примере «как заменить символ в строке» использовал этот метод.
В 9 вопросе 2 и 3 строчка перепутаны.
В последовательности разницы нет. Строки неизменяемые и в каждой строчке будет новая строка. s.trim() никак на s не повлияет.
В 19 вопросе ошибка. Строка созданная оператором new никак не попадает в пул строк
Нет там ошибки. Для этого и нужен метод intern(): добавлять в пул строку созданную через new.
То есть метод intern() добавляет строку в пул, а new не добавляет? Тогда как в 12-ом вопросе на картинке new добавил в пул? (в 19-ом всё правильно.).
Степану:
Все правильно написано! Если ты напрямую создаешь объект через new, то он не попадает в пул. Перед тем как тут умничать напиши код и проверь. Более того даже так:
Речь идет именно о 12 вопросе.
Там нарисовано, что new String(«Cat») сразу попадает в пул.
Может имелся в виду массив символов?
Верно