Эй, ребята, разве это не сезон интервью, cxuan планирует переписать вопросы для интервью, связанные с Java, давайте начнем с основ, эти вопросы для интервью относятся к базовой серии,Не включает вопросы, связанные с многопоточностью, и вопросы, связанные с JVM., многопоточность и JVM я поставил сзади, дальше много говорить не буду, давайте!
Основы Java
Каковы характеристики Java
-
并发性的
: где вы можете выполнять множество операторов, не выполняя их все сразу -
面向对象的
: Классовые и объектно-ориентированные языки программирования. -
独立性的
: служба поддержкиНапиши один раз, беги куда угоднонезависимый язык программирования, т. е. скомпилированный код может работать на всех платформах, поддерживающих Java.
Особенности Java
Особенности Java следующие
-
简单
, Java облегчит вашу работу, позволяя сосредоточиться на основной бизнес-логике, не заботясь об указателях, перегрузке операторов, утилизации памяти и других функциях, не связанных с основным бизнесом. -
便携性
, Java не зависит от платформы, а это означает, что любое приложение, написанное для одной платформы, можно легко перенести на другую. -
安全性
, который преобразует весь код в байт-код после компиляции, который не может быть прочитан людьми. Это позволяет разрабатывать безвирусные и защищенные от несанкционированного доступа системы/приложения. -
动态性
, он имеет возможность адаптироваться к изменяющимся средам, он может поддерживать динамическое выделение памяти, тем самым уменьшая потери памяти и повышая производительность приложений. -
分布式
, Java предоставляет функциональные возможности, помогающие создавать распределенные приложения. использовать远程方法调用(RMI)
, программа может вызвать метод другой программы по сети и получить результат. Вы можете получить доступ к файлам, вызвав методы с любого компьютера в Интернете. Это революционная функция, слишком важная для современного Интернета. -
健壮性
, Java имеет мощные функции управления памятью, которые проверяют код во время компиляции и выполнения, что помогает устранить ошибки. -
高性能
, самая темная технология Java — это программирование байт-кода.Байт-код, скомпилированный из кода Java, можно легко преобразовать в собственный машинный код. Высокая производительность благодаря своевременному JIT-компилятору. -
解释性
, Java компилируется в байт-код, который интерпретируется средой выполнения Java. -
多线程性
, Java поддерживает несколько потоков выполнения (также называемых облегченными процессами), включая набор примитивов синхронизации. Это упрощает программирование с потоками, а Java обеспечивает безопасность потоков с помощью модели монитора.
Каковы характеристики объектно-ориентированного
Существуют три основные особенности объектно-ориентированного
-
Инкапсуляция. Инкапсуляция является одной из объектно-ориентированных функций и основной функцией концепции объекта и класса. Инкапсуляция заключается в инкапсуляции объективных вещей в абстрактные классы, а классы могут оперировать своими данными и методами только доверенными классами или объектами и скрывать информацию от ненадежных.
-
Наследование: Наследование относится к использованию всех функций существующего класса и расширению этих функций без перезаписи исходного класса.
-
Полиморфизм: Полиморфизм — это метод, который позволяет установить родительский объект равным одному или нескольким его дочерним объектам, после присваивания родительский объект может вести себя по-разному в зависимости от свойств дочерних объектов, назначенных ему в данный момент. Проще говоря, это предложение: разрешается присваивать указателям типов подклассов указатели типов суперклассов.
В чем разница между JDK и JRE
- Английское название JRE — Java Runtime Environment, Java Runtime Environment. В основном он состоит из двух частей: стандартной реализации jvm и некоторых базовых библиотек классов Java. По сравнению с jvm это часть библиотеки классов Java.
- Английское название JDK — Java Development Kit, Java Development Kit. jdk — это ядро всей Java-разработки, в него интегрированы jre и некоторые полезные гаджеты. Например: javac.exe, java.exe, jar.exe и т. д.
Здесь также нужно объяснить, что такое JVM
- Английское название JVM — Java Virtual Machine, что означает виртуальную машину Java. Виртуальная машина Java лежит в основе кроссплатформенной реализации.
Грубо говоря, отношения между JRE, JDK и JVM выглядят следующим образом.
Опишите разницу между передачей по значению и передачей по ссылке.
Чтобы действительно понять, вы можете обратиться к этой статье:Ууху. Call.com/question/31…
Говоря простым языком, это
值传递
Это относится к копированию фактических параметров в функцию при вызове функции, поэтому, если функция изменяет переданные ей формальные параметры, фактические параметры не будут затронуты.
引用传递
Это означает, что адрес объекта напрямую передается в функцию при вызове функции, изменение формального параметра повлияет на значение фактического параметра.
В чем разница между == и equals
==
это оператор в Java, он имеет два метода сравнения
- за
基本数据类型
Например, == судит обе стороны值
Они равны
public class DoubleCompareAndEquals {
Person person1 = new Person(24,"boy");
Person person2 = new Person(24,"girl");
int c = 10;
private void doubleCompare(){
int a = 10;
int b = 10;
System.out.println(a == b);
System.out.println(a == c);
System.out.println(person1.getId() == person2.getId());
}
}
- за
引用类型
Например, == судит обе стороны引用
Равны ли они, то есть определить, указывают ли два объекта на одну и ту же область памяти.
private void equals(){
System.out.println(person1.getName().equals(person2.getName()));
}
equals
является родительским классом всех объектов в Java, т.е.Object
Метод, определенный классом. Он может только сравнивать объекты, он указывает, равны ли значения по обе стороны от ссылки. Так что помните, это не то, что == сравнивает ссылки на равенство, equals сравнивает значения, которые необходимо различать.
equals, используемый для сравнения между объектами, имеет следующие характеристики
-
自反性
: x.equals(x) должен возвращать true для любой непустой ссылки x. -
对称性
: Для любых ненулевых ссылок x и y, если x.equals(y) истинно, то y.equals(x) также истинно. -
传递性
: для любого ненулевого ссылочного значения есть три значения, x, y и z, если x.equals(y) возвращает true, а y.equals(z) возвращает true, то x.equals(z) также должен возвращать true. . -
一致性
: для любых ненулевых ссылок x и y они всегда должны быть равны, если x.equals(y) равен. -
非空性
: x.equals(null) должен возвращать false для любого значения x, которое не является нулевой ссылкой.
Каковы основные типы данных в Java и сколько байт они занимают
В Java типы данных только四类八种
- Целочисленный тип: byte, short, int, long
байт также является байтом, 1 байт = 8 бит, значение байта по умолчанию равно 0;
short занимает два байта, то есть 16 бит, 1 short = 16 бит, и его значение по умолчанию также равно 0;
int занимает четыре байта, то есть 32 бита, 1 int = 32 бита, значение по умолчанию 0;
long занимает восемь байт, то есть 64 бита, 1 long = 64 бита, значение по умолчанию 0L;
Таким образом, размер байта, занимаемый целочисленным типом, равен long > int > short > byte.
- плавающая точка
Существует два типа данных с плавающей запятой: float и double.
float — тип с плавающей запятой одинарной точности, занимающий 4 бита, 1 float = 32 бита, значение по умолчанию — 0.0f;
double — тип с плавающей запятой двойной точности, занимающий 8 бит, 1 double = 64 бита, значение по умолчанию — 0.0d;
- тип персонажа
Тип символа — char, тип char — одиночный 16-битный символ Unicode, а минимальное значение —\u0000 (也就是 0 )
, максимальное значение\uffff (即为 65535)
, тип данных char может хранить любой символ, например char a = 'A'.
- логический
Логическое значение относится к логическому значению. Логическое значение имеет только два значения, истинное или ложное, что соответствует только 1 биту. Значение по умолчанию — ложное.
вышеx 位
Все ссылаются на занятость в памяти.
Как переопределяется равенство в String
Строка представляет в Java字符串
, класс String особенный, весь его классfinal
Модифицированный, то есть String не может быть унаследован ни одним классом, ни одним修改
Все строковые методы создают новую строку.
Метод equals — это метод, определенный классом Object, который является родительским классом для всех классов, включая String, который переопределяется String.equals
метод, давайте посмотрим, как его переписать
- Во-первых, он оценит две сравниваемые строки и их
引用
равны. Если ссылки равны, возвращайте true напрямую. Если они не равны, продолжайте со следующим суждением. - Затем оцените, является ли сравниваемый объект экземпляром String. Если нет, верните false напрямую. Если да, сравните длину двух строк, чтобы увидеть, равны ли они. Если длина не хочет быть равной, нет необходимости для сравнения; то же самое, будет сравнивать каждую из строк
字符
Независимо от того, равен ли он, если символ не равен, он сразу вернет false.
Ниже приведена его блок-схема
Вот еще одно напоминание, у вас могут возникнуть сомнения, когда
if (this == anObject) {
return true;
}
Как это суждение может вернуть истину? Потому что все они строки, разве они не все сравнения пространства кучи? Внезапно я обнаружил, что они никогда не пойдут, но вы забылиString.intern()
метод, концепция, которую он представляет, отличается в разных версиях JDK.
В JDK1.7 и более поздних версиях вызов внутреннего метода позволяет определить, есть ли указанная строка в пуле констант среды выполнения.Если нет, добавить строку в пул констант и вернуть объект в пул констант.
Процесс проверки выглядит следующим образом
private void StringOverrideEquals(){
String s1 = "aaa";
String s2 = "aa" + new String("a");
String s3 = new String("aaa");
System.out.println(s1.intern().equals(s1));
System.out.println(s1.intern().equals(s2));
System.out.println(s3.intern().equals(s1));
}
-
Во-первых, s1.intern.equals(s1) все равно возвращает true, потому что строка s1 уже существует в пуле констант на момент ее создания.
-
Затем второй оператор возвращает false, потому что s1 возвращает объект в пуле констант, а s2 возвращает объект в куче.
-
Третий оператор, s3.intern.equals(s1), возвращает значение true, поскольку объект s3 создает объект в куче, но «aaa» в s3 возвращает объект в пуле констант.
Почему метод override equals должен переопределять метод hashcode
Метод equals и hashCode являются методами, определенными в Object, и они часто переопределяются вместе.
Метод equals — это метод, используемый для сравнения того, равны ли объекты по размеру, а метод hashcode — это метод, используемый для определения хеш-значения каждого объекта. Если вы переопределяете только метод equals, но не переопределяете метод хэш-кода, это может привести к возникновению двух разных объектов, чьи хэш-коды также равны, что приведет к конфликту. Например
String str1 = "通话";
String str2 = "重地";
Хеш-коды двух одинаковы, но равные не равны.
Давайте посмотрим на официальное определение hashCode.
Подводя итог,
- Если метод hashCode вызывается для одного и того же объекта во время выполнения Java, независимо от того, сколько раз он вызывается, должен быть возвращен один и тот же hashCode, но в разных программах Java значение, возвращаемое при выполнении метода hashCode, может быть несогласованным.
- Если эквиваленты двух объектов равны, то хэш-код должен быть одинаковым.
- Если эквиваленты двух объектов не равны, то hashCode также может быть одинаковым, поэтому вам нужно переписать метод hashCode, потому что вы не знаете основную структуру hashCode (во всяком случае, я не знаю, есть большие коровы, которые могут этому научить), поэтому вам нужно переписать метод hashCode, чтобы генерировать разные значения hashCode для разных объектов, что может улучшить скорость доступа к разным объектам.
- hashCode обычно реализуется путем преобразования адреса в целое число.
Если хэш-код двух объектов одинаков, то равенство также должно быть истинным.
Это определенно не обязательно верно Для очень простого примера, если вы перепишете метод хэш-кода для вычисления остатка, то хэш-коды двух объектов, вероятно, будут повторяться, но эквиваленты двух объектов не обязательно будут одинаковыми.
Даже если вы не переопределите метод hashcode, я приведу вам пример кода
String str1 = "通话";
String str2 = "重地";
System. out. println(String. format("str1:%d | str2:%d", str1. hashCode(),str2. hashCode()));
System. out. println(str1. equals(str2));
Вывод двух приведенных выше фрагментов кода
стр1: 1179395 | стр2: 1179395 ложный
Равенства двух строк не совпадают. То есть даже для строк с одинаковым хэш-кодом equals может быть разным.
String s1 = new String("abc") создает несколько объектов в памяти
Раз или два, String s1 объявляет переменную s1 типа String, которая не является объектом. использоватьnew
ключевое слово создаст объект в куче, другой объектabc
, он будет создан в пуле констант, поэтому всего будет создано два объекта; если abc уже существует в пуле констант, то будет создан один объект.
Подробности читайте в другой статье автораУникальное подробное объяснение String, StringBuffer, StringBuilder
Почему String неизменяем, как String определяется в исходном коде jdk и почему он так спроектирован.
Сначала пойми, что такое不可变对象
, неизменяемый объект — это то, что после создания внутреннее состояние его объекта не может быть изменено Что это значит? То есть неизменяемые объекты должны соответствовать следующим принципам.
- Внутренние свойства неизменяемых объектов являются окончательными
- Внутренние свойства неизменяемых объектов являются частными
- Неизменяемые объекты не могут предоставлять какие-либо методы, которые могут изменять внутреннее состояние, а также методы установки.
- Неизменяемые объекты нельзя наследовать и расширять
Вместо того, чтобы спрашивать, почему String неизменяем, спросите, как спроектировать String таким образом, чтобы он был неизменным.
Класс String — это объект, который существует независимо от основных типов данных Java. Вы можете понимать String как набор строк. Строка разработана как окончательный, что означает, что после создания объекта String его значение не может быть изменено. любой способ изменить значение String — воссоздать String. После создания объекта String он будет существовать в пуле констант времени выполнения. Пул констант времени выполнения является частью области методов. После JDK1.7 он был перемещен в кучу.
Неизменяемые объекты на самом деле не являются неизменными, вы можете передать反射
изменять его внутренние свойства и значения, но обычно мы этого не делаем.
Для чего используется статическое ключевое слово? говорить о своем понимании
static — очень важное ключевое слово в Java, и концепция, представляемая static,静态的
, в Java статический в основном используется для
- Модифицированные переменные, статические модифицированные переменные называются
静态变量
, также известен как类变量
, переменная класса принадлежит классу.У разных классов есть только одна статическая переменная, а статически модифицированная переменная находится в области методов, статически модифицированную переменную можно напрямую передать черезимя класса.имя переменнойЧтобы получить к нему доступ, вам не нужно использовать его, создавая экземпляр класса. - Модифицированные методы, статические модифицированные методы называются
静态方法
, статический метод может напрямую передаватьимя класса.имя методаиспользовать, нестатические свойства и методы нельзя использовать внутри статических методов - static может изменять блоки кода, в основном разделенные на два типа, один из которых определяется непосредственно в классе, используя
static{}
, который называется静态代码块
, один определен в классе静态内部类
,использоватьstatic class xxx
определять. - static можно использовать для статических пакетов импорта с помощью
import static xxx
Для достижения этого этот метод обычно не рекомендуется - static можно использовать в сочетании с одноэлементным шаблоном для достижения потокобезопасного одноэлементного шаблона путем двойной проверки блокировки.
Для более глубокого понимания, пожалуйста, обратитесь к этой статьеМожет ли небольшая статика быть сложной для меня?
Для чего используется последнее ключевое слово? говорить о своем понимании
final — это ключевое слово в Java, означающее不可变的
, в Java final в основном используется для
- Модифицированные классы, окончательные модифицированные классы не могут быть унаследованы, а значит, их нельзя использовать
extends
для наследования от конечного класса. - Модифицированные переменные, финально-модифицированные переменные не могут быть перезаписаны, и есть два значения того, чтобы не быть перезаписанным.Для базовых типов данных, финально-модифицированные переменные, их значения не могут быть изменены, а финально-модифицированные объекты - ссылка на объект изменить нельзя, но свойства внутри объекта можно изменить. Окончательные измененные переменные играют определенную роль
不可变
Следовательно, его можно использовать для защиты данных только для чтения, особенно в параллельном программировании, поскольку ясно, что конечные переменные больше нельзя назначать, что помогает уменьшить дополнительные издержки синхронизации. - Модифицированные методы, окончательные модифицированные методы не могут быть переопределены.
- Последний модификатор не обязательно связан с оптимизацией производительности Java-программ.
В чем разница между абстрактным классом и интерфейсом
И абстрактные классы, и интерфейсы являются ключевыми словами в Java.И абстрактные классы, и интерфейсы позволяют определять методы без реализации конкретных методов. Абстрактные классы и интерфейсы разрешено наследовать, и они широко используются в исходном коде JDK и фреймворка для реализации полиморфизма и различных шаблонов проектирования.
Разница в том,
-
抽象级别不同
: классы, абстрактные классы и интерфейсы на самом деле представляют собой три разных уровня абстракции: уровень абстракции — интерфейс > абстрактный класс > класс. В интерфейсе разрешено только определение метода, а реализация метода не разрешена.Определение и реализация метода может быть осуществлена в абстрактном классе, а в абстрактном классе разрешена только реализация метода. класс. Определение метода, о котором я сказал, не разрешено в методе. появится позже{}
-
使用的关键字不同
: использование классаclass
представлять; абстрактные классы используютabstract class
представлять; интерфейс используетinterface
Представлять -
变量
: переменные, определенные в интерфейсе, могут быть только общедоступными статическими константами, а переменные в абстрактном классе являются обычными переменными.
разница между переопределением и перегрузкой
В Java переопределение и перегрузка — это разные проявления одного и того же метода Давайте проведем простое различие между переопределением и перегрузкой.
-
子父级关系不同
, переопределение предназначено для разных проявлений дочернего и родительского элементов, а перегрузка — для разных проявлений в одном и том же классе; -
概念不同
, обычно используется метод переопределения подкласса суперкласса@override
Для представления; объявление метода и типы параметров и порядок переопределенного метода должны быть точно такими же, как в родительском классе; перегрузка предназначена для концепции в том же классе, что требует, чтобы перегруженный метод удовлетворял любому из следующих требований: порядок, количество параметров и тип параметров могут быть разными.
Можно ли перегрузить или переопределить конструктор?
Этот вопрос проверяет ваше понимание и знание конструкторов.
Создание объекта в нашей Java фактически вызывает конструктор объекта, например следующий код
InstanceObject IO = new InstanceObject() ; // 调用了无参构造方法
InstanceObject IO = new InstanceObject(xxx) ; // 调用了有参数的构造方法
И что такое концепция перегрузки?
Это означает, что мы можем определить некоторые методы с одинаковыми именами, различать эти методы, определяя разные входные параметры, а затем при вызове JVM выберет соответствующий метод для выполнения в соответствии с различными стилями параметров..
Другими словами, концепция перегрузки больше описывает相同
Другое описание названного метода. Тогда наш приведенный выше код явно перегружен, потому что имя такое же, я могу судить по тому, есть ли параметры для вызова разных конструкторов для инициализации.
Так можно ли переопределить конструктор? Здесь мы сначала посмотрим на то, что переписывает
Переопределение — это подкласс, переписывающий процесс реализации метода, который разрешает доступ к родительскому классу, и ни возвращаемое значение, ни формальные параметры не могут быть изменены.. Из определения концепции переопределения мы знаем, что конструктор не может быть переопределен.
Во-первых, у конструктора нет возвращаемого значения, а во-вторых, имя конструктора должно совпадать с именем класса.
Вы не можете написать public A() в классе A; вы также можете написать public A() в классе B, который, очевидно, не будет компилироваться.
Что такое диапазон значений байта и как его вычислить
Диапазон значений байта -128 -> 127, всего 256. Тип byte занимает в компьютере один байт, поэтому он равен 8 битам, поэтому максимум равен 2^7 = 1111 1111.
Используется в Java补码
Для представления двоичных чисел старший бит дополнения — это бит знака, старший бит — 0 для положительных чисел, старший бит 1 — для отрицательных чисел, а дополнение положительных чисел — это его бит.本身
, так как старший бит является битом знака, положительное число представляет 0111 1111 , что равно 127. Наибольшее отрицательное число 1111 1111, которое включает в себя два нуля, один +0, один -0, +0 классифицируется как положительное число, то есть 0, -0 классифицируется как отрицательное число, то есть -128, поэтому диапазон байтов -128-127.
Разница между HashMap и HashTable
Та же точка
И HashMap, и HashTable реализованы на основе хеш-таблиц, и каждый элемент внутриkey-value
Для пар ключ-значение и HashMap, и HashTable реализуют интерфейсы Map, Cloneable и Serializable.
разница
- Родительский класс отличается: HashMap наследует
AbstractMap
класс, а HashTable наследуетDictionary
своего рода
- Нулевые значения бывают разными: HashMap допускает пустые значения ключа и значения, HashTable не допускает пустых значений ключа и значения. HashMap обрабатывает нулевые ключи как обычные ключи. Повторяющиеся нулевые ключи не допускаются.
- Потокобезопасность: HashMap не является потокобезопасным. Если несколько внешних операций изменяют структуру данных HashMap одновременно, например, добавляют или удаляют, необходимо выполнять операции синхронизации. Только изменение ключа или значения не является операцией по изменению структура данных. При желании создайте поточно-ориентированную карту, такую как
Collections.synchronizedMap
илиConcurrentHashMap
. А HashTable сама по себе является потокобезопасным контейнером. - Производительность: хотя и HashMap, и HashTable основаны на
单链表
, но HashMap может обеспечить постоянную производительность за счет выполнения операций ввода или получения; в то время как операции ввода и получения HashTable добавляютсяsynchronized
Заблокировано, поэтому эффективность очень низкая.
- Начальная емкость другая: начальная длина HashTable равна 11, затем емкость каждого расширения становится предыдущей 2n+1 (n — предыдущая длина), а начальная длина HashMap равна 16, а каждое последующее расширение становится удвоенным. исходный размер. При создании, если задано начальное значение емкости, HashTable будет напрямую использовать заданный вами размер, а HashMap расширит его до степени двойки.
Разница между HashMap и HashSet
HashSet наследует интерфейс AbstractSet и реализует интерфейсы Set, Cloneable и java.io.Serializable. HashSet не допускает дублирования значений в коллекции. Нижний слой HashSet на самом деле является HashMap, и все операции с HashSet на самом деле являются операциями с HashMap. Таким образом, HashSet также не гарантирует порядок коллекции и не является потокобезопасным контейнером.
Базовая структура HashMap
В JDK1.7 HashMap принимает位桶 + 链表
реализация, т.е. использование链表
Для обработки коллизий связанные списки с одним и тем же значением хеш-функции хранятся в массиве. Однако когда в ведре много элементов, то есть когда много элементов с одинаковым значением хеш-функции, эффективность последовательного поиска по значению ключа низка.
Поэтому, по сравнению с JDK 1.7, в JDK 1.8 внесены некоторые изменения в базовую структуру.Когда количество элементов в каждом сегменте превышает 8, оно будет преобразовано в красно-черное дерево для оптимизации эффективности запросов.
Почему длина HashMap равна степени 2?
Я думал над этим вопросом несколько дней. Когда я обсуждал ежедневный вопрос с друзьями в группе, я спросил их, почему length%hash == (n - 1) & hash. Они сказали, что предпосылкой равенства является длина длины 2 в степени 2, и тогда я ответил, не может ли длина быть степенью двойки? На самом деле я не понял причинно-следственной связи, потому что длина HashMap является степенью числа 2, поэтому остаток используется для определения индекса в ведре. Если длина длины не является степенью двойки, вы можете привести пример, чтобы попробовать
Например, когда длина равна 9, 3 и (9-1) = 0, 2 и (9-1) = 0, все на 0, сталкиваются;
Это увеличивает вероятность коллизий HashMap.
Многопоточная операция HashMap вызывает проблему бесконечного цикла
HashMap не является потокобезопасным контейнером. В сценариях с высокой степенью параллелизма его следует использовать.ConcurrentHashMap
, использование HashMap в многопоточном сценарии вызовет проблему с бесконечным циклом (на основе JDK1.7), проблема заключается вrehash
место, то есть
do {
Entry<K,V> next = e.next; // <--假设线程一执行到这里就被调度挂起了
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
Это перефразированный фрагмент кода JDK1.7, который образует цикл в параллельном сценарии.
JDK1.8 также вызывает проблемы с бесконечным циклом.
Каковы реализации безопасности потоков HashMap
Поскольку HashMap не является потокобезопасным контейнером, рекомендуется использовать его в параллельных сценариях.ConcurrentHashMap
, или с потокобезопасным HashMap используйтеCollections
Потокобезопасные контейнеры под пакетом, такие как
Collections.synchronizedMap(new HashMap());
Вы также можете использовать HashTable, который также является потокобезопасным контейнером на основе хранилища ключ-значение.HashMap и HashTable часто сравнивают, потому что структура данных HashTable такая же, как у HashMap.
Наиболее эффективным из вышеперечисленных является ConcurrentHashMap.
Расскажите о процессе установки HashMap
Сначала используется хеш-функция для вычисления ключа, а затем выполняется настоящий метод вставки
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
// 如果table 为null 或者没有为table分配内存,就resize一次
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
// 指定hash值节点为空则直接插入,这个(n - 1) & hash才是表中真正的哈希
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
// 如果不为空
else {
Node<K,V> e; K k;
// 计算表中的这个真正的哈希值与要插入的key.hash相比
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
// 若不同的话,并且当前节点已经在 TreeNode 上了
else if (p instanceof TreeNode)
// 采用红黑树存储方式
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
// key.hash 不同并且也不再 TreeNode 上,在链表上找到 p.next==null
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
// 在表尾插入
p.next = newNode(hash, key, value, null);
// 新增节点后如果节点个数到达阈值,则进入 treeifyBin() 进行再次判断
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
// 如果找到了同hash、key的节点,那么直接退出循环
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
// 更新 p 指向下一节点
p = e;
}
}
// map中含有旧值,返回旧值
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
// map调整次数 + 1
++modCount;
// 键值对的数量达到阈值,需要扩容
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
Ядро метода put HashMap находится вputval
метод, его процесс вставки выглядит следующим образом
- Во-первых, он определит, является ли HashMap новым, и если да, то сначала будет изменен его размер.
- Затем оцените, существует ли уже вставляемый элемент в HashMap (указывая на наличие коллизии), если нет, напрямую сгенерируйте новый узел k-v для хранения, а затем решите, нужно ли его расширять.
- Если вставляемый элемент уже существует, значит, произошел конфликт, который для разрешения конфликта будет преобразован в связанный список или красно-черное дерево.Сначала определите, равны ли хэш и ключ в связанном списке .Если они равны, заменить старое значение новым значением. , если узел относится к типу TreeNode, то он будет обработан непосредственно в красно-черном дереве.Если хеш и ключ не равны или типа TreeNode , он будет непосредственно преобразован в связанный список для обработки, и связанный список будет пройден.Если следующий узел связанного списка равен нулю, рассудите, следует ли преобразовать в красно-черное дерево, если нет, найдите узел с точно такой же ключ во время процесса обхода и заменить старый узел новым узлом
Для более глубокого понимания HashMap обратитесь к этой статье.После прочтения этой HashMap не проблема поспорить с интервьюером.
Базовая реализация ConcurrentHashMap
ConcurrentHashMap — это потокобезопасная карта, а также предпочтительная структура данных в сценариях с высоким параллелизмом.Нижний уровень ConcurrentHashMap должен использовать分段锁
быть реализованным.
Целочисленный буферный пул
Целочисленный буферный пулIntegerCache
, который является статическим внутренним классом Integer .
Его значение по умолчанию используется для кэширования чисел от -128 до 127. Если есть числа от -128 до 127, используйте новое целое без создания объектов, оно будет взято непосредственно из пула кэша, эта операция уменьшит количество объектов в выделение кучи, что полезно для повышения эффективности работы программы.
Например, создание Integer a = 24 на самом деле вызывает IntegervalueOf
, этот вывод можно сделать путем декомпиляции
Затем мы смотрим на метод valueOf
Если оно находится в пределах указанного диапазона пула буферов, кэшированное значение будет возвращено напрямую, без создания нового объекта Integer.
Размер кэша можно использоватьXX:AutoBoxCacheMax
чтобы указать, что при инициализации виртуальной машиныjava.lang.Integer.IntegerCache.high
свойства устанавливаются и сохраняются вsun.misc.VM
в частных системных свойствах.
Связь между UTF-8 и Unicode
Поскольку каждая страна имеет свою уникальную кодировку символов, Unicode был разработан для создания нового стандарта для отображения символов в большинстве языков, используемых сегодня, некоторые из которых не являются необходимыми, но полезны для создания текста. Он незаменим. Юникод унифицирует кодировку всех символов. Это Набор символов, то есть набор символов. Набор символов просто дает всем символам уникальный номер, но не указывает, как их хранить. Разные символы имеют разное пространство для хранения, а некоторые требуется слово. Разделы могут быть сохранены, в то время как другие требуют 2, 3 или 4 байта.
UTF-8 — это просто набор текстовых символов, которые можно解码
с одной стороны, это способ стать длиннее. UTF-8 означает 8-битный формат для представления символов Unicode с использованием 1–4 байтов для представления символов.
U+ 0000 ~ U+ 007F: 0XXXXXXX
U+ 0080 ~ U+ 07FF: 110XXXXX 10XXXXXX
U+ 0800 ~ U+ FFFF: 1110XXXX 10XXXXXX 10XXXXXX
U+10000 ~ U+1FFFF: 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
Можно видеть, что UTF-8 достигает переменной длины за счет количества битов флага в начале. Для однобайтовых символов занят только один байт, что обеспечивает обратную совместимость с ASCII и может включать все символы Unicode, такие как UTF-32, и может эффективно уменьшить пространство, занимаемое при хранении и передаче.
Проект находится в среде UTF-8, char c = 'medium', это законно?
Да, поскольку кодировка Unicode использует 2-байтовую кодировку, UTF-8 — это реализация Unicode, она использует набор символов переменной длины для кодирования, а char c = 'medium' — это два байта, поэтому его можно сохранить. законный.
Что следует отметить о списке, полученном Arrays.asList
Arrays.asList
Это статический метод в Array, который может преобразовать массив в последовательность List. Обратите внимание на следующие моменты.
- Список после преобразования Arrays.asList больше не может быть структурно изменен Что такое структурное изменение? То есть вы больше не можете выполнять сложение или вычитание элементов списка.
public static void main(String[] args) {
Integer[] integer = new Integer[] { 1, 2, 3, 4 };
List integetList = Arrays.asList(integer);
integetList.add(5);
}
Результат будет выброшен напрямую
Exception in thread "main" java.lang.UnsupportedOperationException
Мы можем найти проблему, посмотрев исходный код
// 这是 java.util.Arrays 的内部类,而不是 java.util.ArrayList
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
Унаследовав AbstractList, методы add, remove и set напрямую генерируют исключения, то есть, если унаследованный подкласс не переопределяет эти методы, экземпляр подкласса будет напрямую генерировать исключения при вызове этих методов.
Ниже приведено определение метода в AbstractList, мы можем увидеть конкретное исключение:
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
public E remove(int index) {
throw new UnsupportedOperationException();
}
public E set(int index, E element) {
throw new UnsupportedOperationException();
}
Хотя метод set также создает поле, поскольку внутренний класс ArrayList переопределяет метод set, его можно изменить для поддержки его элементов.
- Arrays.asList не поддерживает преобразование базовых типов.
Базовые типы данных (byte, short, int, long, float, double, boolean) в Java не поддерживают преобразование с помощью метода Arrays.asList.
Разница между коллекцией и коллекциями
Коллекция и коллекции находятся по адресуjava.util
класс под пакетом
Коллекция — это родительский класс класса коллекции, это интерфейс верхнего уровня, большинство абстрактных классов, таких какAbstractList
,AbstractSet
Оба наследуют класс Collection.Класс Collection определяет только один стандартный метод, такой как add, remove, set, equals и т. д. Конкретные методы реализуются абстрактными классами или классами реализации.
Коллекции — это класс инструментов для классов коллекций, а коллекции обеспечивают базовое использование некоторых классов инструментов.
- Метод sort сортирует текущую коллекцию, классы, реализующие интерфейс Comparable, могут использовать только одну схему сортировки, которая называется естественным сравнением.
- Например, реализация потокобезопасных контейнеров
Collections.synchronizedList
,Collections.synchronizedMap
Ждать - reverse Обратный, используйте метод reverse для сортировки указанного списка в порядке убывания в соответствии с естественным порядком элементов.
- fill заменяет все элементы в указанном списке указанным элементом.
Есть много применений, читатели могут прочитать исходный код коллекций для просмотра, коллекции не могут быть созданы, поэтому все методы в коллекциях создаютсяCollections.方法
звонить напрямую.
Вы знаете отказоустойчивый и отказоустойчивый
fail-fast
это Java快速失败
Механизм, все коллекции в пакете java.util являются отказоустойчивыми, а отказоустойчивые выбрасываютConcurrentModificationException
Исключение, отказоустойчивость, вы можете понимать это как механизм быстрого обнаружения, он может использоваться только для обнаружения ошибок и не будет восстанавливаться после ошибок, отказоустойчивость не обязательно только в多线程
ArrayList также выдаст это исключение, если оно существует в среде, основная причина в том, чтоmodCount не равен ожидаемомуModCount.
fail-safe
это Java安全失败
Механизм, что означает, что при обходе он не обращается напрямую к исходной коллекции, а сначала копирует содержимое исходной коллекции и проходит по скопированной коллекции. Поскольку копия исходной коллекции просматривается во время итерации, изменения, внесенные в исходную коллекцию в процессе обхода, не могут быть обнаружены итератором, поэтому ConcurrentModificationException не будет запущено.java.util.concurrent
Все контейнеры в пакете отказоустойчивы и могут использоваться в многопоточных условиях и модифицироваться одновременно.
Разница между ArrayList, LinkedList и Vector
Это тоже старый вопрос.
ArrayList, LinkedList, Векторрасположены вjava.util
Классы инструментов в пакете, все они реализуют интерфейс List.
- Нижний слой ArrayList представляет собой динамический массив, который эволюционирует на основе характеристик массивов, поэтому доступ к ArrayList очень быстрый, но добавление и удаление происходит медленно, поскольку оно включает копирование массива. ArrayList – это не потокобезопасный контейнер, что может вызвать проблемы в параллельных сценариях. Если вы хотите использовать потокобезопасный контейнер, рекомендуется использовать
Collections.synchronizedList
; ArrayList будет увеличивать свою емкость на 50% по мере расширения. - Нижний слой LinkedList представляет собой двусвязный список, поэтому добавление и удаление LinkedList выполняется очень быстро: просто удалите элементы и укажите соответствующие указатели на новые элементы. Но обход LinkedList медленнее, потому что значение следующего элемента может быть известно только каждый раз при доступе к элементу. LinkedList также не является потокобезопасным контейнером, рекомендуется использовать
Collections.synchronizedList
- Vector Vector — это самый ранний контейнер-коллекция, Vector — потокобезопасный контейнер, и каждый из его методов грубо добавлен.
synchronized
Lock, поэтому эффективность его добавления, удаления и обхода очень низкая. Когда Вектор расширяется, его емкость удваивается.
В чем разница между исключением и ошибкой
Исключение обычно относится к异常
, Исключение в основном делится на два вида исключений, одно из которых возникает во время компиляции и называетсяcheckedException
, одно из них — это исключение, возникающее во время выполнения программы, называемоеuncheckedException
, обычное CheckException имеетIOException
, uncheckedException вместе именуетсяRuntimeException
, общее исключение RuntimeException в основномNullPointerException
,IllegalArgumentException
,ArrayIndexOutofBoundException
и т. д., исключение может быть поймано.
Ошибка относится к ошибке, возникающей во время работы программы, которая обычно приводит к сбою программы.Ошибка обычно неустранима, и ошибка не может быть обнаружена.
Для получения подробной информации, пожалуйста, обратитесь к этой статьеПосле прочтения этого исключения и ошибки не проблема поспорить с интервьюером.
В чем разница между String, StringBuilder и StringBuffer
Строка относится конкретно к строкам в Java, а класс String находится вjava.lang
В пакете класс String модифицируется с помощью final. После того, как строка String создана, ее нельзя изменить. Любая модификация String эквивалентна повторному созданию строки. Нижний слой строки String реализован с помощью StringBuilder.
StringBuilder вjava.util
В пакете StringBuilder не является потокобезопасным контейнером.Метод append StringBuilder часто используется для сращивания строк, и его эффективность сплайсинга выше, чем у String.+
Эффективность сращивания высокая. StringBuilder обычно не используется в параллельных средах.
StringBuffer находится вjava.util
В пакете StringBuffer является потокобезопасным контейнером.В многопоточных сценариях StringBuffer обычно используется для конкатенации строк.
И StringBuilder, и StringBuffer унаследованы отAbstractStringBuilderclass, класс AbstractStringBuilder реализует общие операции StringBuffer и StringBuilder.
Для более глубокого понимания, пожалуйста, обратитесь к этой статьеГлубокое понимание String, StringBuilder и StringBuffer
В чем принцип динамического прокси
Агенты обычно делятся на静态代理
и动态代理
, все они являются приложениями режима прокси, статический прокси означает, что программа была скомпилирована перед запуском, и программа знает, кто будет выполнять метод прокси.
Динамический прокси можно определить только во время работы программы.По сравнению со статическим прокси преимущество динамического прокси заключается в том, что он может удобно обрабатывать функции класса прокси без изменения методов в каждом классе прокси. Можно сказать, что динамический прокси основан на反射
осуществленный. С помощью отражения мы можем напрямую манипулировать классами или объектами, например получать определения классов, получать объявленные свойства и методы, вызывать методы и изменять определения классов во время выполнения.
Динамические прокси — это механизм для создания прокси во время выполнения и динамической обработки вызовов методов. Есть много способов реализовать динамический прокси, прокси, предоставляемый Java, называетсяJDK 动态代理
, динамический прокси JDK основан на наследовании классов.
Чтобы понять динамический прокси, вы можете обратиться к этой статьеГлубокое понимание динамических агентов
Несколько реализаций динамических прокси
Я перечислю четыре способа реализации динамического прокси, которые
- Динамический прокси-сервер JDK: динамический прокси-сервер JDK также является динамическим прокси-сервером Java, который представляет собой динамический прокси-сервер на основе интерфейса, который обычно проксирует все классы в интерфейсе.
- Динамический прокси-сервер CGLIB: Динамический прокси-сервер CGLIBЭто реализация прокси для класса, в основном для создания подкласса для указанного класса и переопределения методов в нем., то есть динамический прокси CGLIB использует метод наследования классов -> перезапись метода.
- Явасистский агент:
Javassist
— это библиотека классов для редактирования байт-кода в Java; она позволяет программам Java определять новый класс во время выполнения и изменять файл класса при загрузке JVM. - ASM Proxy: ASM — это среда генерации байт-кода Java, которая может динамически генерировать подклассы или другие прокси-классы в двоичном формате или динамически изменять классы перед их загрузкой в память виртуальной машиной Java.
Информацию о реализации этих четырех байт-кодов см.Динамические прокси — это так просто!
Объясните сериализацию и десериализацию
Сериализация означает сериализацию. Объекты, реализующие сериализацию и десериализацию, должны реализовыватьserializable
интерфейс,Сериализация — это преобразование объекта в поток байтов, который сохраняется на диске или в сети. Десериализация — это процесс, обратный сериализации..
Когда я узнал о сериализации, у меня часто возникал вопрос, а зачем объекты нужно сериализовать?
Для целей передачи данных, поскольку этот объект находится в формате объекта в вашем коде, но не в формате объекта во время передачи, поэтому, когда другие процессы или другие машины хотят связаться с вами, вы оба будете отправлять различные типы данных. , также возможно отправить этот объект, поэтому этот объект обязательно будет преобразован в формат, который может быть распознан в сети или на диске, то есть в двоичный.
То есть отправителю необходимо преобразовать объект Java в последовательность байтов, прежде чем его можно будет передать по сети; получатель должен восстановить последовательность байтов в объект Java, что и делает интерфейс десериализации.
Разница между целым числом и целым числом
Слишком много различий между int и Integer
- int — это базовый тип данных в Java, int представляет
整型
, int занимает 4 байта, то есть 32 бита, начальное значение int — значение по умолчанию 0, int выделен в стеке в модели памяти Java, int не имеет метода. - Integer — это класс-оболочка для основных типов данных в Java. Integer — это объект. Integer может выполнять вызовы методов. Значение Integer по умолчанию — null. Integer размещается в куче в модели памяти Java. Int и Integer могут быть преобразованы друг в друга во время вычисления Процесс int -> Integer называется
装箱
, процесс Integer -> int вызывается拆箱
, Integer и IntegerCache, которые будут автоматически кэшировать значения в диапазоне -128-127
Для более глубокого понимания распаковки и упаковки, пожалуйста, обратитесь к этой статье.Подробное объяснение автоупаковки и распаковки в Java
Какие методы ввода-вывода предоставляет Java
Существует много способов ввода-вывода Java, традиционный ввод-вывод также называетсяBIO
, основные потоки следующие.
Реализация пакета ввода-вывода Java относительно проста, но имеет узкие места в производительности.Традиционный ввод-вывод основан на синхронной блокировке.
Предоставляется начиная с JDK 1.4NIO
, то есть приjava.nio
пакет, обеспечивает на основеканал, селектор, буферАбстракция для создания мультиплексированных, синхронных, неблокирующих программ ввода-вывода.
NIO был улучшен после JDK 1.7, представив异步非阻塞
способ, также известный какAIO(Asynchronous IO)
. Это можно проиллюстрировать на примере из жизни: руководитель проекта передаст ошибку своим подчиненным для исправления ошибки, тогда руководитель проекта не будет ждать, пока сотрудник решит ошибку все время, он должен назначить ошибки другим подчиненных или заниматься другими делами в период, когда сотрудник решает ошибку.После устранения ошибки сообщите менеджеру проекта, что ошибка решена.
Для более глубокого понимания IO, вы можете обратиться к этой статьеГлубокое понимание IO.
Расскажите о шаблонах проектирования, которые вы знаете
Карта разума
Например, можно использовать глобальную уникальность.单例模式
.
можно использовать策略模式
Оптимизируйте слишком много, если... иначе...
для стандарта模版模式
Захватите чужой банк, но не хотите менять первоначальный класс适配器模式
использовать组合
вместо наследства
использовать装饰器
Можно приготовить кофе с сахаром и сыром
代理
Может быть использован для любого посредника...
Напишите несколько реализаций одноэлементного шаблона
Это также распространенный вопрос на собеседовании.Как правило, вас не попросят написать шаблон синглтона от руки. Даже если он написан от руки, вам нужно написать только код ключа. Этот вопрос на самом деле хочет задать несколько реализаций одноэлементного шаблона и есть ли какие-либо проблемы с каждой реализацией.
В общем, вы можете ответить на это
- Голодный китайский стиль: потокобезопасность, высокая эффективность вызовов, но без отложенной загрузки
- Стиль ленивого человека: потокобезопасный, неэффективный вызов, но с возможностью отложенной загрузки.
- Double CheckLock реализует синглтон: DCL — это механизм оценки двойной блокировки (из-за базовой модели JVM иногда возникают проблемы, и его не рекомендуется использовать).
- Режим реализации статического внутреннего класса: безопасность потоков, высокая эффективность вызовов, отложенная загрузка
- Класс перечисления: потокобезопасный, высокая эффективность вызовов, не может задерживать загрузку, может естественным образом предотвращать вызовы отражения и десериализации.
Если вы хотите узнать больше об этом вопросе интервью, вы можете прочитатьЯ объяснил интервьюеру, что такое синглтон, и он поднял мне большой палец вверх.
В чем разница между Comparator и Comparable
-
Сопоставимый больше похож на естественный порядок
-
Компаратор больше похож на пользовательскую сортировку
Когда оба существуют, для сравнения используются правила компаратора (выборочная сортировка).
Для некоторых распространенных типов данных (таких как String, Integer, Double...) они реализуют интерфейс Comparable по умолчанию и реализуют метод compareTo, который мы можем использовать напрямую.
Для некоторых пользовательских классов им может потребоваться реализовать разные стратегии сравнения в разных ситуациях, мы можем создать новый интерфейс Comparator, а затем использовать конкретную реализацию Comparator для сравнения.
Для более глубокого понимания Comparator и Comparable вы можете обратиться к этой статье.Сопоставимое и компараторное понимание.
Какие методы обычно встречаются в классе Object
Класс Object является родительским классом для всех объектов и содержит некоторые методы, которые могут использовать все объекты.
- hashCode(): хеш-код, используемый для вычисления объекта.
- equals(): используется для сравнения значений между объектами на равенство
- toString(): используется для преобразования объекта в строку
- clone(): для копирования между объектами
- wait(): используется для реализации ожидания между объектами.
- notify(): используется для уведомления объекта об освобождении ресурсов.
- notifyAll(): используется для уведомления всех объектов об освобождении ресурсов.
- finalize(): используется для указания сборщику мусора выполнить сборку мусора.
- getClass(): используется для получения класса объекта
Java Generics и стирание типов
Достаточно одной статьи о дженериках и стирании Java.
Основной принцип отражения, каковы три способа создания экземпляра класса путем отражения
Механизм отражения заключается в том, чтобы заставить Java-программы иметь自省(introspect)
С помощью отражения мы можем напрямую манипулировать классами и объектами, например, получать определение класса, получать свойства и методы класса и создавать методы.
Три способа создать экземпляр класса:
- экземпляр объекта.getClass();
- Создано Class.forName()
- Создание метода instance.newInstance() объекта
Для более глубокого понимания отражения, пожалуйста, обратитесь к статьеНаучившись размышлять, я был принят! (галантерея)
Разница между сильной ссылкой, если ссылка, фантомная ссылка и фантомная ссылка
Различные типы ссылок, о которых мы говорим, на самом деле логичны, и для виртуальных машин они в основном отражают различные типы объектов.可达性(reachable)
статус и пара垃圾收集(garbage collector)
Влияние.
Жизненный цикл объекта можно описать следующим процессом.
Объекты создаются и инициализируются, объекты используются во время выполнения, а затем выходят из области видимости, объекты становятся недоступными и собираются сборщиком мусора. Область, отмеченная на рисунке красным цветом, указывает на то, что объект находится в стадии сильной достижимости.
Представлен JDK1.2java.lang.ref
Пакеты, объекты имеют четыре стадии жизненного цикла:强可达(Strongly Reachable)
,软可达(Soft Reachable)
,弱可达(Weak Reachable)
,幻象可达(Phantom Reachable)
.
Если мы обсуждаем только объекты, подходящие для сборки мусора, то есть только три типа: мягкая достижимость, слабая достижимость и фантомная достижимость.
-
Мягкая доступность: Мягкая доступность — это состояние, к которому мы можем получить доступ только через мягкие ссылки.
SoftReference
объекты, на которые есть ссылки, и объекты, на которые строго ссылаются, нет. Мягкие ссылки используются для описания некоторыхполезно, но не нужноОбъект. Сборщик мусора будет хранить объекты с мягкой ссылкой как можно дольше, но это произойдетOutOfMemoryError
Раньше объект, на который ссылались, был восстановлен. Если объект, на который ссылаются, восстанавливается, а памяти по-прежнему недостаточно для выделения, будет выдана ошибка OutOfMemoryError. -
Слабо достижимые: Слабо достижимые объекты
WeakReference
упоминаемый объект. Сборщик мусора может собирать слабоссылочные объекты в любое время и не будет пытаться сохранить слабоссылочные объекты. -
Phantom Reach: Phantom Reach создан
PhantomReference
Для ссылочного объекта фантомная достижимость означает, что нет сильной, мягкой или слабой ссылки для ассоциирования, и она завершена только тогда, когда фантомная ссылка указывает на этот объект.
Кроме того, есть два условия оценки доступности: сильная достижимость и недостижимость.
- Сильная достижимость: объекты, которые только что были созданы, инициализированы и используются, находятся в состоянии сильной достижимости.
-
不可达(unreachable)
: недостижимый объект означает, что объект можно очистить.
Ниже приведена диаграмма перехода для различных состояний достижимости.
Определение условий достижимости также является частью рассмотрения того, как сборщик мусора JVM решает, как обрабатывать объекты.
Все ссылки на доступность объектаjava.lang.ref.Reference
Подкласс , который имеетget()
метод, который возвращает ссылочный объект. Этот метод возвращает значение null, если этот ссылочный объект был очищен программой или сборщиком мусора. То есть помимо фантомных ссылок объекты могут получать как мягкие, так и слабые ссылки. и эти объекты могут быть искусственно拯救
, становится строгой ссылкой, например, назначение ключевого слова this объекту просто повторно связывает его с любым объектом в цепочке ссылок.
Для более глубокого понимания проблемы цитирования вы можете прочитать эту статьюГлубокое понимание различных вопросов цитирования.
Разница между final, finally и finalize()
Можно сказать, что эти трое не имеют ничего общего друг с другом.Как мы упоминали выше, final можно использовать для изменения классов, переменных и методов.Вы можете обратиться к последнему вопросу интервью выше.
finally — это ключевое слово, которое часто используется с блоками try для обработки исключений. Используя блоки кода try...finally, код в части finally обязательно будет выполнен, поэтому мы часто используем метод finally для операций закрытия ресурсов.
В JDK1.7 рекомендуется использоватьtry-with-resources
Чтобы изящно закрыть ресурсы, он может напрямую использовать try(){} для закрытия ресурсов без написания ключевого слова finally.
finalize — это метод в объекте Object. Он используется для повторного использования объектов. Как правило, мы не рекомендуем этот метод. Finalize связан со сборкой мусора. В Java 9 finalize помечен какdeprecated
, Если нет особой причины, не реализуйте метод finalize и не ожидайте, что он будет удален сборщиком мусора.
Для более глубокого понимания final, finally и finalize вы можете прочитать эту статью.Прочитав этот финал, напоследок и доработав, поспорить с интервьюером не проблема.
Каковы классификации внутренних классов, объясните их отдельно
В Java вы можете поместить определение одного класса в определение другого класса, т.внутренний класс. Сам внутренний класс является атрибутом класса и определяется так же, как и другие атрибуты.
Существует четыре основных типа внутренних классов.
- внутренний класс-член
- локальный внутренний класс
- анонимный внутренний класс
- статический внутренний класс
静态内部类
Это статический класс, определенный внутри класса.Статический внутренний класс может получить доступ ко всем статическим переменным внешнего класса, но не может получить доступ к нестатическим переменным внешнего класса;
成员内部类
Нестатический класс, определенный внутри класса и в позиции члена, является внутренним классом-членом. Члены внутреннего класса могут получить доступ ко всем переменным и методам внешнего класса, включая статические и нестатические, частные и общедоступные.
Внутренний класс, определенный в методе,局部内部类
. Локальный класс, определенный в методе экземпляра, может получить доступ ко всем переменным и методам внешнего класса, а локальный класс, определенный в статическом методе, может получить доступ только к статическим переменным и методам внешнего класса.
匿名内部类
Это внутренний класс без имени.Помимо отсутствия имени, анонимные внутренние классы обладают следующими характеристиками:
- Анонимный внутренний класс должен наследовать абстрактный класс или реализовывать интерфейс.
- Анонимные внутренние классы не могут определять статические члены и статические методы.
- Когда формальный параметр метода, в котором он находится, должен использоваться анонимным внутренним классом, он должен быть объявлен окончательным.
- Анонимный внутренний класс не может быть абстрактным, он должен реализовывать все абстрактные методы унаследованного класса или реализованного интерфейса.
Назовите несколько распространенных исключений
- NullPointerException: исключение нулевого указателя
- NoSuchMethodException: метод не найден
- IllegalArgumentException: исключение недопустимого аргумента
- IndexOutOfBoundException: исключение нижнего индекса массива за пределами границ
- IOException: возникло исключение, поскольку файл не найден, не открыт или операция ввода-вывода не может быть выполнена.
- ClassNotFoundException : исключение, вызванное файлом, который не найден
- NumberFormatException: неправильный формат данных кода UTF для символа, вызывающий исключение;
- InterruptedException: исключение, вызванное прерыванием потока
Разница между статической привязкой и динамической привязкой
Java-программа должна пройти через три этапа: написание, компиляция и выполнение, среди которых написание кода не входит в рамки нашего обсуждения, поэтому наше внимание, естественно, будет сосредоточено на编译
и运行
Эти два этапа из-за громоздкого процесса компиляции и запуска объясняются ниже, исходя из моего понимания:
Java-программы проходят два основных этапа от создания исходного файла до выполнения программы:
1. Время компиляции — это процесс компиляции исходных файлов в байт-код компилятором.
2. Файл байт-кода интерпретируется и выполняется виртуальной машиной Java.
связывать
Связывание — это процесс связывания вызова метода с классом, вызывающим метод, который называется связыванием.
Существует два основных типа креплений:
статическая привязка и динамическая привязка
Другие названия привязки
статическая привязка == ранняя привязка == привязка во время компиляции
динамическая привязка == поздняя привязка == привязка во время выполнения
Чтобы облегчить различие: следующее вместе называется статической привязкой и динамической привязкой.
статическая привязка
Перед запуском программы, то есть во время компиляции, JVM может определить, кто вызывает метод.Этот механизм называется статическим связыванием.
Определите три ключевых слова статического связывания и их соответствующее понимание.
Если метод модифицируется любым из ключевых слов private, static, final, то метод является предварительно привязанным.
Конструкторы также рано связываются
private: ключевое слово private означает private.Если метод, измененный private, не может быть вызван другими классами, кроме этого класса, это метод, уникальный для этого класса, поэтому компилятор идентифицирует, какому методу принадлежит этот метод.
public class Person {
private String talk;
private String canTalk(){
return talk;
}
}
class Animal{
public static void main(String[] args) {
Person p = new Person();
// private 修饰的方法是Person类独有的,所以Animal类无法访问(动物本来就不能说话)
// p.canTalk();
}
}
final: окончательные измененные методы не могут быть переопределены, но могут быть вызваны подклассами.Если метод объявлен окончательным, динамическое связывание может быть эффективно отключено
public class Fruit {
private String fruitName;
final String eatingFruit(String name){
System.out.println("eating " + name);
return fruitName;
}
}
class Apple extends Fruit{
// 不能重写final方法,eatingFruit方法只属于Fruit类,Apple类无法调用
// String eatingFruit(String name){
// super.eatingFruit(name);
// }
String eatingApple(String name){
return super.eatingFruit(name);
}
}
static: метод, измененный static, является особым, его не нужно вызывать новым классом.类名.变量名
Прямой вызов метода очень важен, новый очень важен, и его также можно рассматривать как предохранитель для включения полиморфизма.Если имя класса и имя переменной вызываются напрямую, имя класса в это время определяется, и оно будет Не следует генерировать полиморфизм, следующий код:
public class SuperClass {
public static void sayHello(){
System.out.println("由 superClass 说你好");
}
}
public class SubClass extends SuperClass{
public static void sayHello(){
System.out.println("由 SubClass 说你好");
}
public static void main(String[] args) {
SuperClass.sayHello();
SubClass.sayHello();
}
}
После того, как SubClass наследует SuperClass, в
Нельзя переопределить метод sayHello, то есть метод sayHello() скрыт от подкласса, но вы можете написать свой собственный метод sayHello(), то есть метод sayHello() подкласса SubClass. видно, что метод состоит из Modified с помощью ключевого слова static, это также привязка времени компиляции
динамическая привязка
Связывание по типу конкретного объекта во время выполнения
В дополнение к методам и конструкторам, измененным private, final и static, процесс, с помощью которого JVM решает, какой объект вызывает метод во время выполнения, называется динамической привязкой.
Если компиляция и запуск рассматриваются как временная шкала, процесс компиляции программы должен быть выполнен до запуска, тогда привязка, выполняемая в период компиляции, является ранней привязкой, а привязка, которая происходит после запуска программы, является поздней привязкой.
public class Father {
void drinkMilk(){
System.out.println("父亲喜欢喝牛奶");
}
}
public class Son extends Father{
@Override
void drinkMilk() {
System.out.println("儿子喜欢喝牛奶");
}
public static void main(String[] args) {
Father son = new Son();
son.drinkMilk();
}
}
Класс Son наследует класс Father и переопределяет метод dringMilk() родительского класса.В результате получается, что сын любит пить молоко. Итак, каков метод привязки выше?
Вышеупомянутый метод связывания называется动态绑定
, потому что, когда вы пишете Father son = new Son(), компилятор не знает, на кого на самом деле ссылается объект сына.Он знает только во время работы программы, что сын является объектом класса Отец, но он указывает на Son's Reference, это понятие называется полиморфизмом, то мы можем выделить три принципа полиморфизма:
-
наследовать
-
переписать
-
Ссылка родительского класса указывает на объект дочернего класса
То есть в Отец сын = новый Сын() срабатывает механизм динамической привязки.
Процесс динамической привязки
- Таблица методов виртуальной машины для извлечения фактического типа объекта;
- сигнатура метода поиска виртуальной машины;
- метод вызова.
Характеристики динамического связывания и статического связывания
статическая привязка
Статическое связывание запускается во время компиляции, затем его основные функции
1. Запускается во время компиляции, может заранее знать ошибки кода
2. Повысить эффективность работы программы
динамическая привязка
1. Предпосылки для использования динамического связывания могут повысить удобство использования кода и сделать его более гибким.
2. В основе шаблонов проектирования лежит полиморфизм, который может уменьшить связанность.
Что такое синтаксический сахар в Java
Синтаксический сахар относится к определенному синтаксису, добавленному к языку программирования.Этот синтаксис никак не влияет на функциональность языка, но более удобен для использования программистами.. Поскольку код Java должен выполняться в JVM,JVM не поддерживает синтаксический сахар. Синтаксический сахар будет восстановлен до простой базовой синтаксической структуры на этапе компиляции программы.解语法糖
.
Ниже я перечислю, какие синтаксические сахара есть в Java.
-
Дженерики: Дженерики — это синтаксический сахар. В JDK1.5 был введен универсальный механизм, но сам общий механизм
类型擦除
Для этого в JVM нет дженериков, только обычные типы и обычные методы, а параметры типов дженериков будут стираться во время компиляции. -
Автоматическая распаковка и автоматическая упаковка. Автоматическая распаковка и автоматическая упаковка — это синтаксический сахар, который говорит об автоматическом преобразовании между классами-оболочками восьми примитивных типов данных и их примитивными типами данных. Проще говоря, бокс — это автоматическое преобразование примитивных типов данных в
包装器
тип; распаковка — это автоматическое преобразование типа-оболочки в примитивный тип данных. -
Внутренний класс: Внутренний класс на самом деле является синтаксическим сахаром, потому что это только концепция времени компиляции.После компиляции компилятор создаст отдельный файл класса для внутреннего класса с именем external$innter.class.
-
Параметры переменной длины: Параметры переменной длины также используются относительно редко.Так называемые параметры переменной длины — это методы, которые могут принимать параметры неопределенной длины. Как правило, мы не используем параметры переменной длины в нашей разработке, и параметры переменной длины не рекомендуются, что затруднит работу с нашими программами.
-
Расширенный цикл for: по сравнению с обычным циклом for, расширенный цикл for является более мощным, а код более лаконичным, вам не нужно знать количество обходов и индекс массива для прохождения; объект расширенного цикла for либо массив, либо реализованный интерфейс Iterable. Этот синтаксический сахар в основном используется для обхода массива или коллекции и не может изменять размер коллекции во время цикла.
-
Switch поддерживает строки и перечисления:
switch
Ключевое слово изначально поддерживает только整数
тип. Если за переключателем следует тип String, компилятор преобразует его в StringhashCode
Значение , так что на самом деле синтаксис переключателя сравнивает хэш-код String . -
Условная компиляция: обычно компилируются все строки исходной программы. Но иногда вы хотите скомпилировать какой-то контент только при соблюдении определенных условий, то есть указать условия компиляции для некоторого контента, т.е.
条件编译(conditional compile)
. -
Утверждение: т. н.
assert
Ключевое слово — это новая функция, добавленная после jdk 1.4. Он в основном используется во время разработки кода и тестирования для оценки некоторых ключевых данных.Если эти ключевые данные не соответствуют данным, ожидаемым вашей программой, программа выдаст предупреждение или завершит работу. -
try-with-resources: начиная с JDK 1.7, в java появился оператор try-with-resources, упрощающий try-catch-finally до try-catch, который на самом деле является своего рода
语法糖
, который преобразуется в оператор try-catch-finally во время компиляции. Новое объявление состоит из трех частей: объявления try-with-resources, блока try и блока catch. Он требует, чтобы переменные, определенные в объявлении try-with-resources, реализовывали интерфейс AutoCloseable, чтобы их метод close мог автоматически вызываться системой, заменяя функцию finally закрытия ресурсов. -
Добавление строки: это должен знать каждый, есть два вида склейки строк, если результат склейки можно определить во время компиляции, то используйте
+
Конкатенированные строки будут напрямую оптимизированы компилятором в результате добавления.Если результат конкатенации не может быть определен во время компиляции, нижний слой будет напрямую использоватьStringBuilder
изappend
соединение
Для более глубокого понимания синтаксического сахара Java вы можете обратиться к этой статье.Синтаксический сахар в Java, действительно сладкий.
Сходства и различия между List и Set
Это тоже извечный вопрос.
Та же точка
Всего в коллекциях Java есть три типа, а именно List, Set и Map.Все они расположены в пакете java.util, и все они являются интерфейсами и имеют свои собственные классы реализации.
Класс реализации ListArrayList, LinkedList, Vector, CopyOnWriteArrayListЖдать
Классы реализации Set:HashSet, TreeSet, LinkedHashSet, SortedSetЖдать
У них также есть свои собственные абстрактные классы: абстрактный класс List — AbstractList, а абстрактный класс Set — AbstractSet. Абстрактные классы в основном используются как расширения интерфейсов верхнего уровня, то есть таких интерфейсов, как List и Set.При реализации некоторых функций интерфейса верхнего уровня они также определяют некоторые методы шаблона.При этом используется шаблон проектирования шаблона.
List и Set оба наследуютCollection
интерфейс, принадлежащий集合
.
Поговорим о разнице между List и Set
разница
упорядоченность
Список представляет собой有序集合
, то есть элементы в списке расположены по порядку, интерфейс списка может точно управлять порядком вставки каждого элемента, а элементы можно искать по индексу.
Set не требует порядка множества, и разные классы реализации могут определять свой порядок, например, HashSet — неупорядоченная структура данных, и элементы в HashSet неупорядочены, TreeSet будет отсортирован в соответствии с естественным порядком elements; LinkedHashSet будет отсортирован в соответствии с порядком элементов, вставленных в Set; SortedSet будет отсортирован в соответствии с порядком сравнения Comparable или Comparator, что означает, что вы можете настроить правила сортировки.
Повторяется ли элемент
List допускает существование повторяющихся элементов, а List может разрешать вставку нулевых элементов, в то время как Set не допускает дублирования элементов, поэтому Set может допускать существование только одного нулевого элемента.
Расскажи мне, что ты знаешь о карте
Map также является классом коллекции, который очень часто используется в нашей повседневной разработке.
Карта является опоройkey-value
это键值对
хранимый объект. Среди них ключевой объект не может повторяться, а объект-значение может повторяться, а объект-значение также может быть типа Map, точно так же, как элементы в массиве также могут быть массивами.
Классы реализации интерфейса карты:HashMap, TreeMap, LinkedHashMapсвоего рода.
HashMap — наша наиболее часто используемая реализация Map.Основная структура HashMap:массив + связанный список, он будет хранить данные в соответствии со значением hashCode ключа, вы можете использоватьget(key)
Чтобы получить значение, соответствующее ключу, HashMap не является потокобезопасным контейнером и может разрешать только одну нулевую пару ключ-значение. Когда элементов в HashMap мало, HashMap хранит элементы в виде связанного списка, когда количество данных достигает определенного уровня, связанный список будет преобразован в красно-черное дерево для хранения.
TreeMap — это карта красно-черных деревьев, сортирует ключи в соответствии с заданным порядком, TreeMap не является потокобезопасной картой, в TreeMap нельзя допускать нулевые значения, иначе будет выброшено исключение нулевого указателя.
LinkedHashMap гарантирует порядок вставки элементов, который медленнее, чем HashMap при обходе запроса, а также не является потокобезопасным контейнером. LinkedHashMap может разрешать пустые элементы.
Стоит отметить, что реализация Map также имеетHashtable
иConcurrentHashMap
, оба элемента являются потокобезопасными Maps.
Обычно мы не используем Hashtable, потому что его потокобезопасность использует только простое насилие.synchronized
Блокировка синхронизации, накладные расходы на блокировку синхронизации относительно велики, и ее не рекомендуется использовать.
Последний — ConcurrentHashMap. ConcurrentHashMap — это карта, основанная на многопоточности и высокой степени параллелизма. Она часто используется в многопоточных сценариях.分段锁
, блокировка сегмента блокирует каждый сегмент, что уменьшает детализацию блокировки, обеспечивая безопасность потоков.
Различия между ArrayList, LinkedList и Vector
ArrayList — это структура данных, основанная на динамических массивах, а LinkedList — структура данных, основанная на связанных списках.
Для операций получения и установки с произвольным доступом ArrayList лучше, чем LinkedList, потому что LinkedList перемещает указатель.
Для операций добавления и удаления доминирует LinedList, потому что ArrayList перемещает данные.
И ArrayList, и LinkedList не являются потокобезопасными, они оба должны быть заблокированы вручную или созданы с использованием потокобезопасной реализации Collections.synchronizedList в Collections. Все они имеют отказоустойчивый механизм.
В это время вы также можете спроситьVector
разница
Есть два основных отличия: потокобезопасность и масштабируемость.
Как и ArrayList, Vector также реализован через массивы, разница в том, что он поддерживает потоки同步
, то есть только один поток может записывать вектор за раз, что позволяет избежать несогласованности, вызванной одновременной записью нескольких потоков, но для достижения синхронизации требуются большие затраты, поэтому доступ к нему медленнее, чем доступ к ArrayList.
Когда элементы в Vector или ArrayList превышают свой первоначальный размер, Vector удваивает свою емкость, а ArrayList увеличивает свой размер только на 50%. Таким образом, ArrayList полезен для экономии места в памяти.
Принцип реализации Collections.sort и Arrays.sort
Сначала представьте исходный код Collections.sort и Arrays.sort.
Как видно из этих трех фрагментов кода, Collections.sort, наконец, вызывает метод в Arrays.sort, поэтому вам не нужно читать Collections.sort, просто посмотрите на Arrays.sort.
В исходном коде Arrays.sort есть три ветвления. Если внешний компаратор не указан, метод сортировки будет вызываться напрямую. Метод сортировки после вызова выглядит следующим образом.
сначала будетLegacyMergeSort.userRequestedсуд, что означает этот суд?
Да, в JDK1.6 используетсяLegacyMergeSort
, который используется в JDK1.7TimeSort
, если вы хотите использовать оригинальный LegacyMergeSort, вам нужно добавить его в системную переменную
-Djava.util.Arrays.useLegacyMergeSort=true
эта конфигурация.
Если эта конфигурация не используется, вызов по умолчаниюComparableTimSort.sortметод, который фактически являетсяTimSort
оптимизация, а алгоритм сортировки TimSortСортировка слиянием.
Мы также можем видеть это из второго решения в Arrays.sort,ComparableTimSort и TimSortСамая большая разница заключается в том, предоставляете ли вы внешний компаратор.
В чем разница между Iterator и ListIterator
Мы часто используем Iterator в нашем ежедневном процессе разработки, а ListIterator — редко.Этот вопрос в основном проверяет ваше знакомство с исходным кодом List и ваше понимание отказоустойчивого механизма.
В общем, основные различия между Iterator и ListIterator заключаются в следующем.
-
Итератор не может изменять количество элементов в коллекции в процессе обхода, иначе будет выдано исключение.
-
Сфера использования различна, Iterator можно использовать во всех коллекциях, а ListIterator можно использовать только в типах и подтипах List.
-
listIterator имеет метод add, который может добавлять элементы в коллекцию, а iterator не может.
-
И у listiterator, и у iterator есть методы next и next для последовательного обхода элементов, но у listiterator есть методы previous и previous, которые могут проходить элементы в обратном порядке.
-
listiterator может найти текущую позицию индекса nextIndex и previousIndex могут быть реализованы, итератор не имеет этой функции
-
Listiterator может реализовать модификацию объекта.Можно реализовать метод set().Итератор может быть только пройден и не может быть изменен.
Разговор о механизме расширения ArrayList
Сегодня интервьюер снова спросил о механизме расширения вашего ArrayList. . . . . . Просто посмотрите исходный код
Когда он будет расширен, это должно быть, когда вызывается метод add для добавления элементов.
Добавление элементов ArrayList будет оцениваться, что такжеensureCapacityInternal
Что делает метод, то есть метод, чтобы судить и определять размер емкости, мы будем следить непосредственно
Этот метод вынесет решение, и мы также дали его в комментариях выше, то есть указал ли ваш ArrayList начальную емкость при его построении.Если в списке нет элементов, он будет оцениваться начальная емкость, которую вы установили, и максимальная емкость в ArrayList.Берите большую.
тогда позвониensureExplicitCapacity
способ определить, требуется ли расширение
Можно видеть, что если размер элемента массива ArrayList больше, чем сохраненный элемент в это время, он вызоветgrow
метод, этот метод роста на самом деле является методом расширения.
Этот код представляет собой механизм расширения ArrayList. Давайте проанализируем
Сначала будет получено количество элементов ArrayList, затем емкость ArrayList будет расширена на 50%, и расширенная емкость будет сравниваться с емкостью параметра, если она меньше параметра, то будет увеличена емкость большей емкости. использоваться для копирования элементов. Если расширенная емкость больше, чем максимальная емкость ArrayList, будет взято значение максимальной емкости.
hugeCapacity
Метод сначала оценивает, меньше ли параметр 0 , если да, он выдает исключение OutOfMemoryError Exception, если нет, судит, больше ли параметр и максимальная емкость ArrayList, если параметр больше, он примет значениеInteger.MAX_VALUE, если он маленький, он займет MAX_ARRAY_SIZE.
Разница между BIO, NIO и AIO
Проще говоря,BIO(Blocking I/O)
, это синхронный блокирующий ввод-вывод, чтение и запись данных должны выполняться в одном потоке, то есть он имеет только один поток последовательности выполнения, если он сталкивается с операцией чтения потока ввода-вывода, он должен ждать, пока Операция чтения потока ввода-вывода. После завершения выборки или записи можно выполнять следующую работу.
NIO(non-blocking IO)
Также известен какnew io
, который является недавно добавленным потоком ввода-вывода в JDK 1.4 и выше. Это синхронная неблокирующая модель ввода-вывода. В NIO поток возвращается сразу после инициирования запроса. Синхронизация означает, что он должен ждать, пока данные в буфере ввода-вывода будут готовы. сначала выполните некоторые другие операции.Но он должен регулярно опрашивать, чтобы проверить, готовы ли данные буфера ввода-вывода. NIO в Java означает новый ввод-вывод. По сути, это NIO плюс технология мультиплексирования ввода-вывода. Обычный NIO — это опрос потока, чтобы узнать, готов ли буфер ввода-вывода, в то время как новый ввод-вывод в Java относится к опросу потоков, чтобы увидеть, какие из них готовы в группе буферов ввода-вывода, что является идеей мультиплексирования ввода-вывода. В модели мультиплексирования ввода-вывода задача проверки готовности данных ввода-вывода передается модели выбора или epoll на уровне системы, которая контролируется системой для снижения нагрузки на пользовательские потоки.
AIO
Это настоящая асинхронная неблокирующая модель ввода-вывода. В приведенной выше реализации NIO пользовательский поток должен регулярно опрашивать, чтобы проверить, готовы ли данные буфера ввода-вывода, который занимает ресурсы потока приложения Фактически, опрос эквивалентен блокировке и на самом деле не освобождает текущий поток, потому что он все еще нужно запросить, какой ввод-вывод готов. Настоящий идеальный асинхронный неблокирующий ввод-вывод должен позволить системе ядра завершиться, а пользовательскому потоку нужно только сообщить ядру, когда буфер будет готов, уведомить меня или выполнить функцию обратного вызова, которую я вам передал.
Разница между глубоким копированием и поверхностным копированием
В Java по степени копирования свойств объекта (базовые классы данных и ссылочные типы) различают два типа:
- мелкая копия
Shallow Copy
- глубокая копия
Deep Copy
Неглубокая копия: неглубокая копия воссоздает объект с копией значений свойств исходного объекта. Если свойство является примитивным типом, копируется значение примитивного типа; если свойство является адресом памяти (ссылочным типом), копируется адрес памяти, поэтому, если один объект изменит этот адрес, это повлияет на другой объект. То есть конструктор копирования по умолчанию выполняет только поверхностное копирование объекта, то есть копирует один за другим член за членом, то есть копирует только пространство объекта без копирования ресурсов.
Чтобы реализовать мелкое копирование, вам нужно реализоватьCloneable
интерфейс и переопределитьclone()
метод.
Глубокая копия: для объекта-члена базового типа данных, поскольку базовый тип данных передается по значению, значение атрибута напрямую присваивается новому объекту. Копия базового типа, в которой один объект изменяет значение, не затрагивая другой (то же самое, что и поверхностная копия). Для ссылочных типов, таких как массивы или объекты класса, глубокое копирование создаст новое пространство объектов, а затем скопирует содержимое внутри, чтобы они указывали на разные области памяти. Изменение одного из них не повлияет на другой. Для объектов с несколькими слоями каждый объект должен реализоватьCloneable
и переписатьclone()
методом, а затем реализовать серийную послойную копию объекта. Глубокие копии медленнее и дороже мелких копий.
Пять способов создания объектов в Java
Существует пять основных способов создания объектов в Java.
- использовать new для создания объектов
Object obj = new Object();
- Используйте метод newInstance для создания
User user = (User)Class.forName("com.cxuan.test.User").newInstance();
// 或者使用
User user = User.class.newInstance();
- Используйте отражение для создания объектов
Constructor<User> constructor = User.class.getConstructor();
User user = constructor.newInstance();
- Используйте клонирование объектов для создания объектов
Constructor<User> constructor = User.class.getConstructor();
User user = constructor.newInstance();
user.setName("cxuan");
User user2 = (User)user.clone();
System.out.println(user2.getName());
- Создать объект с помощью десериализации
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxx"));
out.writeObject(user2);
out.close();
//Deserialization
ObjectInputStream in = new ObjectInputStream(new FileInputStream("xxx"));
User user3 = (User) in.readObject();
in.close();
user3.setName("cxuan003");
System.out.println(user3 + ", hashcode : " + user3.hashCode());
Для более глубокого понимания этих методов создания объектов вы можете обратиться кИнвентаризация n операций по созданию объектов в Java
Мелочи
Эта статья писалась давно.Статистика паблика аккаунта WeChat 3w слов, 31 картинка, а время чтения около 77 минут.
Я знаю, что это время чтения может занять линию метро 10, чтобы объехать Пекин, и многие люди будут противны.Статья такая длинная, у кого есть время, чтобы прочитать ее? Я слышал этот вопрос о фаст-фуде бессчетное количество раз, но каждый раз теряю слух. Да, каждый день мы листаем Доуинь, чтобы увидеть красивых женщин, листаем заголовки, чтобы посмотреть на красивых женщин, листаем официальный аккаунт, чтобы каждый день хвастаться группой воротил, а потом ругаемся: «Черт, какая трата Лао-цзы на 1 час. ", а потом прикинулся серьезным посмотрел 15 минут кода и продолжил тратить.
Я знаю, что эту статью до сих пор многие не читают, потому что она скоро будет захлестнута потоком информации. Может быть, после прочтения вы поставите ее в избранное. Даже если вы думаете, что я написал педиатрию, эта статья может быть в Ваше программирование В моей карьере нет волн, и я не хочу слишком много описывать явление. Я просто скажу, что я сделал. В этой статье, наверное, меньше 20 ссылок, и 14 из них — это контент моего официального аккаунта.
Уникальное подробное объяснение String, StringBuffer, StringBuilder
Может ли небольшая статика быть сложной для меня?
После прочтения этой HashMap не проблема поспорить с интервьюером.
После прочтения этого исключения и ошибки не проблема поспорить с интервьюером.
Глубокое понимание динамических агентов
Динамические прокси — это так просто!
Я объяснил интервьюеру, что такое синглтон, и он поднял мне большой палец вверх.
Сопоставимое и компараторное понимание
Научившись размышлять, я был принят! (галантерея)
Глубокое понимание различных вопросов цитирования
Прочитав этот финал, напоследок и доработав, поспорить с интервьюером не проблема
Синтаксический сахар в Java, действительно сладкий.
Инвентаризация n операций по созданию объектов в Java
Я думаю, это может быть правильно, я на githubGitHub.com/Next Day Picks/Не голоден…что было сказано выше.
Хорошо, это все, что касается того, что вы ищете, просто не стесняйтесь, я надеюсь, что эта статья может вам помочь.
Я сам переписал шесть PDF-файлов. После того, как WeChat искал «Programmer cxuan» и следил за официальной учетной записью, я ответил cxuan в фоновом режиме и получил все PDF-файлы.Эти PDF-файлы следующие: