-
¿Cómo crear un objeto inmutable en Java? Enumere todos los beneficios
Una clase inmutable es una clase cuyo estado no se puede cambiar después de la creación. Aquí, se considera esencialmente que el estado de un objeto son los valores almacenados en una instancia de una clase, ya sean tipos primitivos o tipos de referencia.
Para que una clase sea inmutable, se deben cumplir las siguientes condiciones:
- No proporcione definidores ni métodos que modifiquen campos u objetos que hagan referencia a campos. Los establecedores implican cambiar el estado de un objeto, que es lo que queremos evitar aquí.
- Haga todos los campos
final
yprivate
.private
No se podrá acceder a los campos marcados desde fuera de la clase y marcarlosfinal
garantiza que no los cambiará, ni siquiera por accidente. - No permita que las subclases anulen métodos. La forma más sencilla de hacerlo es declarar la clase como
final
. Las clases finalizadas en Java no se pueden anular. - Recuerde siempre que sus instancias variables pueden ser mutables o inmutables. Defínalos y devuelva nuevos objetos con contenido copiado para todos los objetos mutables (tipos de referencia). Las variables inmutables (tipos primitivos) se pueden devolver de forma segura y sin esfuerzo adicional.
Además, es necesario recordar los beneficios posteriores de las clases inmutables. Es posible que los necesite en una entrevista. Clases inmutables:
- fácil de diseñar, probar y usar
- Automáticamente seguro para subprocesos y no tiene problemas de sincronización.
- no requiere un constructor de copia
- le permite inicializar perezosamente un código hash y almacenar en caché el valor de retorno
- no requiere copia segura cuando se utiliza como campo
- hacer buenas
Map
claves ySet
elementos (estos objetos no deben cambiar de estado mientras estén en la colección) - haga que su clase sea permanente creándola una vez, y no es necesario verificarla nuevamente
- siempre tienen “atomicidad de falla” (un término acuñado por Joshua Bloch): si un objeto inmutable genera una excepción, nunca permanecerá en un estado no deseado o indefinido.
Mira el ejemplo escrito en esta publicación .
-
En Java, ¿pasar por valor o por referencia?
Java спецификация гласит, что все в Java передается по значению. Нет такого понятия, Cómo «передача по ссылке» в Java. Эти условия связаны с вызовом методов и передачей переменных, Cómo параметров метода. Хорошо, примитивные типы всегда передаются по значению без Cómoой-либо путаницы. Но, концепция должна быть понятна в контексте параметра метода сложных типов.
В Java, когда мы передает ссылку сложного типа Cómo любой параметр метода, всегда DIRECCIÓN памяти копируется в новую ссылочную переменную шаг за шагом. Посмотрите на изображение:
В приведенном примере, биты DIRECCIÓNа первого экземпляра копируются другой ссылочной переменной, в результате чего обе ссылки указывают на один участок памяти, где хранится un objeto. Помните, что присвоив второй ссылке null, вы не присвоите null первой ссылке. Но изменение состояния un objetoа с одной ссылающейся переменной, будет отображено и в другой ссылке.
Подробности смотрите тут.
-
Какое применение блока
finally
? Гарантирует этот блок выполнение своего códigoа? Когдаfinally
блок не вызывается?Блок
finally
всегда вызывается, если блокtry
существует. Это гарантирует, что блокfinally
вызывается даже, если случается неожиданное исключение. Ноfinally
является более полезным, чем просто для обработки исключений – этот блок позволяет выполнить чистку códigoа, случайно обошедшего черезreturn
,continue
obreak
. Размещение очищающего códigoа в блокfinally
всегда является хорошей практикой, даже когда не ожидается ниCómoих исключений.Если виртуальная машина завершает работу во время выполнения блока
try
ocatch
, тогда блокfinally
не будет выполнен. Аналогично, если нить, выполняя блокtry
ocatch
, будет прервана o убита, блокfinally
не будет выполнен, даже не смотря на то, что приложение продолжает работать. -
Почему существует два класса
Date
, один вjava.util package
а другой вjava.sql
?java.util.Date
представляет fecha и время, аjava.sql.Date
представляет только fecha. Дополнением кjava.sql.Date
является классjava.sql.Time
, который представляет только время.Класс
java.sql.Date
является субклассом (расширением) классаjava.util.Date
. Итак, что изменилось вjava.sql.Date
:toString()
формирует другое представление строки: yyyy-mm-dd- статический метод
valueOf(String)
создает fecha из строки с вышеуказанным представлением - исключены геттеры и сеттеры для часов, minutos и секунд
Класс
java.sql.Date
используется в JDBC и предназначен, чтобы не иметь составляющую времени, то есть часы, minutosы, секунды и миллисекунды должны быть нулю… но это не является обязательным для класса. -
Разъясните интерфейсы-маркеры.
Шаблон интерфейса-маркера – это шаблон проектирования в компьютерных науках, используемый языками программирования, которые предоставляют информацию об un objetoах во время выполнения. Это предоставляет способ ассоциации метаданных класса, где язык не имеет явной поддержки таких метаданных. В Java для этого используются интерфейсы без указания методов.
Хорошим примером применения интерфейса-маркера в Java является интерфейс
Serializable
. Класс реализует этот интерфейс для указания, что его неtransient
данные могут быть записаны в поток byteов o на файловую систему.Главной проблемой интерфейса-маркера является то, что интерфейс определяет соглашение для реализующих его классов, и это соглашение наследуется всеми субклассами. Это значит, что вы не сможете «де-реализовать» маркер. В приведенном примере, если вы создадите субкласс, который вы бы не хотели сериализовать (возможно потому, что он находится в преходящем (transient) состоянии), вы должны прибегнуть к явному бросанию
NotSerializableException
. -
Почему метод
main()
объявлен Cómopublic static void
?Почему public? Метод
main
имеет модификатор доступаpublic
, поэтому он может быть доступен везде и для любого un objetoа, который захочет использовать этот метод для запуска aplicaciones. Тут я не говорю, что JDK/JRE имеют подобный повод, поскольку java.exe o javaw.exe (для windows) используют Java Native Interface (JNI) вызов для запуска метода, поэтому они могут вызвать его в любом случае, независимо от модификатора доступа.Почему static? Давайте предположим, что у нас метод
main
не статический. Теперь, для вызова любого метода вам необходим экземпляр класса. Верно? Java разрешает иметь перегруженные конструкторы, это мы все знаем. Тогда который из них должен быть использован, и откуда возьмутся параметры для перегруженного конструктора?Почему void? Нет применения для возвращаемого значения в виртуальной машине, которая фактически вызывает этот метод. Единственное, что приложение захочет сообщить вызвавшему процессу – это нормальное o ненормальное завершение. Это уже возможно используя
System.exit(int)
. Не нулевое significado подразумевает ненормальное завершение, иначе все в порядке. -
В чем разница между созданием строки Cómo
new()
и литералом (при помощи двойных кавычек)?Когда мы создаем строку используя
new()
, она создается в хипе и также добавляется в пул строк, в то же время строка, созданная при помощи литерала, создается только в пуле строк.Вам необходимо ознакомиться с понятием пула строк глубже, чтобы ответить на этот o подобные вопросы. Мой совет – Cómo следует выучите класс String и пул строк.
-
Как работает метод
substring()
классаString
?Как и в других языках программирования, строки в Java являются последовательностью символов. Этот класс больше похож на служебный класс для работы с этой последовательностью. Последовательность символов обеспечивается следующей переменной:
/** The value is used for character storage. */ /** Значение используется для хранения символов */ private final char value[]; Для доступа к этому массиву в различных сценариях используются следующие переменные
/** The offset is the first index of the storage that is used. */ /** Смещение – это первый индекс используемого хранoща. */ private final int offset; /** The count is the number of characters in the String. */ /** Счет – это количество символов в строке. */ private final int count;
Каждый раз, когда мы создаем подстроку от существующего экземпляра строки, метод
substring()
только устанавливает новые значения переменныхoffset
иcount
. Внутренний массив символов не изменяется. Это возможный источник утечки памяти, если методsubstring()
использовать неосторожно:Первоначальное significado
value[]
не изменяется. Поэтому если вы создадите строку длиной 10000 символов и создадите 100 подстрок с 5-10 символами в каждой, все 101 un objetoы будут содержать один и тот же символьный массив длиной 10000 символов. Это без сомнения расточительство памяти.Этого можно избежать, изменив código следующим образом:
заменить
original.substring(beginIndex)
наnew String(original.substring(beginIndex))
, гдеoriginal
– исходная строка.Примечание переводчика: я затрудняюсь сказать к Cómoой версии Java это применимо, но на данный момент в Java 7 этот пункт статьи не актуален. Метод substring()
вызывает конструктор классаnew String(value, beginIndex, subLen)
, который в свою очередь обращается к методуArrays.copyOfRange(value, offset, offset+count)
. Это значит, что у нас будет каждый раз новое significado переменнойvalue[]
, содержащее наше новое количество символов. -
Объясните работу
HashMap
. Как решена проблема дубликатов?Большинство из вас наверняка согласится, что
HashMap
наиболее любимая тема для дискуссий на интервью в настоящее время. Если кто-нибудь попросит меня рассказать «Как работаетHashMap
?», я просто отвечу: «По принципу хэширования». Так просто, Cómo это есть.Итак, хеширование по сути является способом назначить уникальный código для любой переменной/un objetoа после применения любой формулы/алгоритма к своим свойствам.
Определение карты (
Map
) таково: «Объект, который привязывает ключи к значениям». Очень просто, верно? Итак,HashMap
содержит собственный внутренний классEntry
, который имеет вид:static class Entry implements Map.Entry { final K key; V value; Entry next; final int hash; …//More code goes here }
Когда кто-либо пытается поместить пару ключ-significado в
HashMap
, происходит следующее:- В первую очередь, un objeto ключа проверяется на
null
. Если ключnull
, significado сохраняется в позициюtable[0]
. Потому что хэшcódigo дляnull
всегда 0. - Затем, следующим шагом вычисляется хэш significado вызывая у переменной-ключа свой метод
hashCode()
. Этот хэш используется для вычисления индекса в массиве для хранение un objetoаEntry
. Разработчики JDK прекрасно понимали, что методhashCode()
может быть плохо написан и может возвращать очень большое o очень маленькое significado. Для решения этой проблемы они ввели другойhash()
метод, и передают хэшcódigo un objetoа этому методу для приведения этого значения к диапазону размера индекса массива. - Теперь вызывается метод
indexFor(hash, table.length)
для вычисления точной позиции для хранения un objetoаEntry
. - Теперь главная часть. Как мы знаем, два неодинаковых un objetoа могут иметь одинаковое significado хэшcódigoа, Cómo два разных un objetoа будет храниться в одинаковом расположении в архиве [называется корзиной]?
Ответ –
LinkedList
. Если вы помните, классEntry
имеет свойство “next”. Это свойство всегда указывает на следующий un objeto в цепи. Такое поведение очень похоже наLinkedList
.Итак, в случае совпадений хэшcódigoов, un objetoы Entry хранятся в форме
LinkedList
. Когда un objetoEntry
необходимо разместить на конкретном индексе,HashMap
проверяет, существует ли на этом месте другой un objetoEntry
? Если там нет записи, наш un objeto сохранится в этом месте.Если на нашем индексе уже находится другой un objeto, проверяется его поле
next
. Если оно равноnull
, наш un objeto становится следующим узлом вLinkedList
. Если next не равноnull
, эта procedimientosа повторяется, пока не будет найдено полеnext
равноеnull
.Qué будет, если мы добавим другое significado ключа, равное добавленному ранее? Логично, что оно должно заменить старое significado. Как это происходит? После определения индекса позиции для un objetoа
Entry
, пробегая поLinkedList
, расположенному на нашем индексе,HashMap
вызывает методequals()
для значения ключа для каждого un objetoаEntry
. Все эти un objetoыEntry
вLinkedList
имеют одинаковое significado хэшcódigoа, но методequals()
будет проверять на настоящее es igualство. Если ключ.equals(k)
будет true, тогда оба будут восприниматься Cómo одинаковый un objeto. Это вызовет замену только un objetoа-significado внутри un objetoаEntry
.Таким образом
HashMap
обеспечивает уникальность ключей. - В первую очередь, un objeto ключа проверяется на
-
Различия между интерфейсами и абстрактными классами?
Это очень распространенный вопрос, если вы проходите собеседование на программиста уровня junior. Наиболее значимые различия приведены ниже:
- В интерфейсах Java переменные априори
final
. Абстрактные классы могут содержать неfinal
переменные. - Интерфейс в Java безоговорочно не может иметь реализации. Абстрактный класс может иметь экземпляры методов, которые реализуют базовое поведение.
- Составляющие интерфейса должны быть
public
. Абстрактный класс может иметь модификаторы доступа на любой вкус. - Интерфейс должен быть реализован ключевым словом
implements
. Абстрактный класс должен быть расширен при помощи ключевого слова extends. - В Java класс может реализовывать множество интерфейсов, но может унаследоваться только от одного абстрактного класса.
- Интерфейс completamente абстрактный и не может иметь экземпляров. Абстрактный класс также не может иметь экземпляров класса, но может быть вызван, если существует метод
main()
. - Una clase abstracta es ligeramente más rápida que una interfaz porque la interfaz asume una búsqueda antes de llamar a cualquier método anulado en Java. En la mayoría de los casos, esta es una diferencia menor, pero si está escribiendo una aplicación en la que el tiempo es crítico, debe tener en cuenta este hecho.
- В интерфейсах Java переменные априори
-
¿Cuándo se anulan los métodos
hashCode()
yequals()
?Los métodos
hashCode()
yequals()
se definen en la claseObject
, que es la clase principal de todos los objetos Java. Por este motivo, todos los objetos Java heredan la implementación subyacente de estos métodos.El método
hashCode()
se utiliza para obtener un valor entero único para un objeto determinado. Este valor se utiliza para determinar la ubicación de la papelera de reciclaje cuando el objeto debe almacenarse en una estructura de datos comoHashTable
. De forma predeterminada, el métodohashCode()
devuelve una representación entera de la dirección de memoria donde está almacenado el objeto.El método
equals()
, como su nombre indica, se utiliza para la equivalencia de objetos simples. La implementación básica del método es verificar las referencias de dos objetos para comprobar si son equivalentes.Tenga en cuenta que normalmente es necesario anular un método
hashCode()
cada vez que se anula un métodoequals()
. Esto es necesario para respaldar la convención general del métodohashCode
, que establece que objetos iguales deben tener códigos hash iguales.El método equals() debe determinar la igualdad entre relaciones (debe ser recurrente, simétrico y transitivo). Además, debe ser persistente (si el objeto no ha cambiado, el método debe devolver el mismo valor). Además,
o.equals(null)
siempre debería devolver false .hashCode()
También debe ser persistente (si el objeto no ha cambiado bajo las condiciones del métodoequals()
, debe continuar devolviendo el mismo valor.La relación entre los dos métodos es: siempre, si
a.equals(b)
, entoncesa.hashCode()
debe ser igual queb.hashCode()
.
Andrey
Nivel 26
Núcleo de Java. Preguntas de la entrevista, parte 1
Para quienes escuchan la palabra Java Core por primera vez, estos son los fundamentos fundamentales del lenguaje. Con este conocimiento, puede realizar con seguridad una pasantía/prácticas. Estas preguntas le ayudarán a actualizar sus conocimientos antes de la entrevista o a aprender algo nuevo por sí mismo. Para adquirir habilidades prácticas, estudie en JavaRush .
GO TO FULL VERSION