1. Введение
Студенты, участвовавшие в социальном рекрутинге, знают, что при поступлении в компанию на собеседование на позицию развития, после заполнения личной информации, обычно сначала попросят пройти письменный тест, а затем компания будет определять, продолжать ли собеседование в соответствии с к результатам письменного теста. , Если ответ не является хорошим, некоторые компании могут прямо сказать: «Технический менеджер или директор занят, вы возвращаетесь и ждете уведомления», а некоторые компании могут продолжить интервью, чтобы узнать о ваш проектный опыт и так далее.
По крайней мере, в первые 5 лет работы или даже дольше, собеседование обычно не пропускает часть письменного теста (кроме Даниэля, некоторые компании), я не могу вспомнить, сколько компаний я проинтервьюировал, а сколько собеседование вопросы, которые я сделал. , В результате я иногда хожу по магазинам сейчас, и я всегда чувствую себя знакомым во многих местах. Я чувствую, что пришел на интервью много лет назад. Я смеялся над собой, и я сомневался в том, что я сделал в Шанхай тогда очень важно.
В Интернете есть много статей, объясняющих несколько ключевых слов «вопросов для собеседования по Java», почему я должен обобщать их сам? В основном это следующие причины:
- Слишком много статей, но я не знаю, какую из них прочитать (точно так же, как книга, в которой говорится, что слишком много информации равносильно отсутствию информации)
- Достоверность статьи невысокая (много раз выявлялось, что описание некорректно или код не запускается)
- Углубите свое понимание и память
- Раз и навсегда, в следующий раз вам не придется медленно рыться в интернете, просто посмотрите, что вы разобрали
В этой статье в основном организованы вопросы интервью о базовых знаниях Java, в основном включая следующие пункты:
- Разница между целым числом и целым числом
- Разница между == и равным
- Разница между String, StringBuilder, StringBuffer
- Упаковка и распаковка
- Передача по значению и передача по ссылке в Java
Далее я объясню их один за другим.
2. Разница между Integer и int
2.1 Различие основных понятий
- Integer — это класс-оболочка (ссылочный тип) int, который является базовым типом данных (типом значения) Java.
- Целочисленные переменные должны быть созданы, прежде чем их можно будет использовать, в то время как переменные int этого не делают.
- Целочисленный объект на самом деле упоминается, когда новое целое число фактически генерирует указатель на объект, и INT непосредственно сохраняется значение данных.
- Значение по умолчанию для Integer равно null, а значение по умолчанию для int равно 0.
2.2 Несколько распространенных сценариев сравнения между Integer и int
1) Сравните две новые переменные Integer() и всегда возвращайте false
Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.println(i == j); // false
Две целочисленные переменные, сгенерированные new, генерируют два объекта с разными адресами памяти.
2) Сравните переменную Integer, сгенерированную не новой, с переменной, сгенерированной new Integer(), и всегда возвращайте false
Integer i = new Integer(100);
Integer j = 100;
System.out.println(i == j); // false
Переменная Integer, сгенерированная non-new, указывает на объект в пуле констант Java, в то время как переменная, сгенерированная new Integer(), указывает на вновь созданный объект в куче, а их адреса в памяти различны.
3) Сравнение двух не новых сгенерированных целочисленных переменных, если значения двух переменных находятся между -128 и 127, результат сравнения верен, а если значения двух переменных не находятся в этом интервале, результат сравнения неверный.
Integer i = 100;
Integer j = 100;
System.out.println(i == j); //true
Integer i1 = 128;
Integer j1 = 128;
System.out.println(i1 == j1); //false
Почему так происходит, разберем причины:
Integer i = 100;
Во время компиляции он будет переведен вInteger i = Integer.valueOf(100);
, а исходный код метода valueOf класса Integer в Java выглядит следующим образом:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
Как видно из исходного кода:
Целое число в Java кэширует числа от -128 до 127. Таким образом, когда Integer i = 100, 100 будет кэшировано, а в следующий раз, когда вы запишете Integer j = 100, оно будет взято непосредственно из кеша вместо нового.
4) При сравнении целочисленной переменной с переменной INT до тех пор, пока значения двух переменных равны, результат является верным
Integer i = new Integer(100);
int j = 100;
System.out.print(i == j); //true
Потому что, когда класс-оболочка Integer сравнивается с базовым типом данных int, Java автоматически распаковывает его в int, а затем сравнивает, что фактически становится сравнением двух переменных int.
3. Разница между == и равным
3.1 Различие основных понятий
1) Для == сравнение заключается в том, равны ли значения
Если он воздействует на переменную базового типа данных, он напрямую сравнивает ее сохраненные значения на предмет равенства.
При воздействии на переменную ссылочного типа сравнение заключается в том, чтобы увидеть, равны ли адреса объектов, на которые указывает.
На самом деле, независимо от того, является ли это базовым типом данных или переменной ссылочного типа данных, == сравнивает значение, но значение, хранящееся в переменной ссылочного типа, является адресом объекта
2) Для метода equals сравнение заключается в том, является ли это одним и тем же объектом.
Во-первых, метод equals() не может работать с переменными примитивных типов данных,
Кроме того, метод equals() существует в классе Object, а класс Object является прямым или косвенным родительским классом всех классов, поэтому метод equals() во всех классах наследуется от класса Object без переопределения метода equals(). метод. В классе вызов метода equals() имеет тот же эффект, что и использование ==. Он также сравнивает адрес объекта, на который указывает переменная ссылочного типа. Однако в классах, предоставляемых Java, некоторые классы переписали метод equals(). , переопределенный метод equals() обычно сравнивает значения двух объектов, таких как класс String.
Исходный код метода equals() класса объекта:
public boolean equals(Object obj) {
return (this == obj);
}
Исходный код метода equals() класса String:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
3.2 Пример
Пример 1:
int x = 10;
int y = 10;
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(x == y); // true
System.out.println(str1 == str2); // false
System.out.println(str1.equals(str2)); // true
Пример 2:
String str3 = "abc";
String str4 = "abc";
System.out.println(str3 == str4); // true
Причина, по которой str3 и str4 равны, так это то, что используется постоянный пул в памяти. При запуске к STR3 для создания объекта, если нет объекта в постоянном пуле, в постоянном пуле создается объект «ABC», и в постоянном пуле, и Когда он создан во второй раз, он напрямую использует, поэтому объекты, созданные дважды, на самом деле являются одинаковым объектом, и их значения адреса равны.
Пример 3:
Сначала определите класс Student
package com.zwwhnly.springbootaction;
public class Student {
private int age;
public Student(int age) {
this.age = age;
}
}
Затем создайте два экземпляра Student для сравнения.
Student student1 = new Student(23);
Student student2 = new Student(23);
System.out.println(student1.equals(student2)); // false
В это время метод equals вызывает метод equals() класса Object базового класса, который представляет собой сравнение ==, поэтому он возвращает false.
Затем мы переписываем метод equals () до тех пор, пока два ученика одного возраста, что это один и тот же ученик.
package com.zwwhnly.springbootaction;
public class Student {
private int age;
public Student(int age) {
this.age = age;
}
@Override
public boolean equals(Object obj) {
Student student = (Student) obj;
return this.age == student.age;
}
}
На данный момент сравните два экземпляра только сейчас и верните True.
Student student1 = new Student(23);
Student student2 = new Student(23);
System.out.println(student1.equals(student2)); // true
4. Разница между String, StringBuilder, StringBuffer
4.1 Объясните разницу
1) Скорость бега
Порядок скорости работы: StringBuilder > StringBuffer > String
Причина, по которой String самая медленная:
String — это строковая константа, а StringBuilder и StringBuffer — строковые переменные, то есть после создания объекта String этот объект нельзя изменить, но последние два объекта являются переменными и могут быть изменены.
2) Безопасность потока
С точки зрения безопасности потоков, StringBuilder небезопасен для потоков, в то время как StringBuffer является потокобезопасным (многие методы имеют ключевое слово synchronized).
3) Сценарии использования
Строка: подходит для небольшого количества строковых операций.
StringBuilder: подходит для большого количества операций над символьным буфером в рамках одного потока.
StringBuffer: подходит для большого количества операций в символьном буфере в условиях многопоточности.
4.2 Пример
Например, 10000 на Срабцы строки мы смотрим в три раза их потребностям:
String str = "";
long startTime = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
str = str + i;
}
long endTime = System.currentTimeMillis();
long time = endTime - startTime;
System.out.println("String消耗时间:" + time);
StringBuilder builder = new StringBuilder("");
startTime = System.currentTimeMillis();
for (int j = 0; j < 10000; j++) {
builder.append(j);
}
endTime = System.currentTimeMillis();
time = endTime - startTime;
System.out.println("StringBuilder消耗时间:" + time);
StringBuffer buffer = new StringBuffer("");
startTime = System.currentTimeMillis();
for (int k = 0; k < 10000; k++) {
buffer.append(k);
}
endTime = System.currentTimeMillis();
time = endTime - startTime;
System.out.println("StringBuffer消耗时间:" + time);
результат операции:
Время потребления строки: 258
Время использования StringBuilder: 0
Время потребления StringBuffer: 1
Также проверено, что StringBuilder> StringBuffer> String, упомянутый выше.
5. Упаковка и распаковка
5.1 Что такое бокс? Что такое распаковка?
Упаковка: автоматически преобразует примитивные типы данных в типы-оболочки.
Распаковка: автоматическое преобразование типов-оболочек в примитивные типы данных.
Integer i = 10; // 装箱
int j = i; // 拆箱
5.2 Как реализованы упаковка и распаковка?
Процесс упаковки достигается путем вызова метода valueOf оболочки,
Процесс распаковки реализуется путем вызова метода xxxValue экземпляра оболочки (xxx представляет соответствующий базовый тип данных).
Как доказать этот вывод, создадим новый класс Main и добавим в метод main следующий код:
package com.zwwhnly.springbootaction;
public class Main {
public static void main(String[] args) {
Integer i = 100;
int j = i;
}
}
Затем откройте окно cmd, переключитесь на путь, где находится класс Main, выполните команду: javac Main.java, вы обнаружите, что в этом каталоге будет сгенерирован файл Main.class, откройте его с помощью IDEA, и вы находим, что скомпилированный код выглядит следующим образом:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.zwwhnly.springbootaction;
public class Main {
public Main() {
}
public static void main(String[] var0) {
Integer var1 = Integer.valueOf(100);
int var2 = var1.intValue();
}
}
Примечание. В приведенном выше примере используется IDEA 2017.2.
В более новой версии IDEA (2018.3.3 или 2019.1.3) Main.class, который вы видите, выглядит следующим образом:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.zwwhnly.springbootaction;
public class Main {
public Main() {
}
public static void main(String[] var0) {
Integer var1 = 100;
int var2 = var1;
}
}
5.3 Пример
Пример 1:
Double i1 = 100.0;
Double i2 = 100.0;
Double i3 = 200.0;
Double i4 = 200.0;
System.out.println(i1==i2);
System.out.println(i3==i4);
Выходной результат:
false
false
Почему все они возвращают false? Давайте посмотрим на метод Double.valueOf() и узнаем:
private final double value;
public Double(double value) {
this.value = value;
}
public static Double valueOf(double d) {
return new Double(d);
}
Пример 2:
Boolean i1 = false;
Boolean i2 = false;
Boolean i3 = true;
Boolean i4 = true;
System.out.println(i1==i2);
System.out.println(i3==i4);
Выходной результат:
true
true
Почему все они возвращают true? Давайте взглянем на метод Boolean.valueOf() и узнаем:
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
6. Передача по значению и по ссылке в Java
6.1 Основные понятия
Передача по значению: Передача копии объекта, даже если копия изменена, не повлияет на исходный объект, потому что при передаче по значению значение фактического параметра фактически копируется в формальный параметр.
Передача по ссылке: передается не фактический объект, а ссылка на объект, и внешние изменения объекта, на который ссылаются, также будут отражаться на исходном объекте, поскольку при передаче по ссылке адресное значение фактического параметра фактически скопированные в исходный объект формальные параметры.
Описание: Передача объекта (массив, класс, интерфейс) осуществляется по ссылке, а данные примитивного типа (целое число, число с плавающей запятой, символ, логическое значение) передаются по значению.
6.2 Пример
Пример 1 (передача по значению):
package com.zwwhnly.springbootaction;
public class ArrayListDemo {
public static void main(String[] args) {
int num1 = 10;
int num2 = 20;
swap(num1, num2);
System.out.println("num1 = " + num1);
System.out.println("num2 = " + num2);
}
public static void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
System.out.println("a = " + a);
System.out.println("b = " + b);
}
}
результат операции:
a = 20
b = 10
num1 = 10
num2 = 20
Видно, что хотя значения a и b поменялись местами в методе swap(), значения num1 и num2 в основном методе не изменились.
Пример 2 (передача ссылочного типа):
package com.zwwhnly.springbootaction;
public class ArrayListDemo {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
change(arr);
System.out.println(arr[0]);
}
public static void change(int[] array) {
System.out.println(array[0]);
array[0] = 0;
}
}
результат операции:
1
0
Видно, что в методе change() первый элемент массива изменяется на 0, и первый элемент массива в основном методе также изменяется на 0.
Пример 3 (тип StringBuffer):
package com.zwwhnly.springbootaction;
public class ArrayListDemo {
public static void main(String[] args) {
StringBuffer stringBuffer = new StringBuffer("博客园:申城异乡人");
System.out.println(stringBuffer);
changeStringBuffer(stringBuffer);
System.out.println(stringBuffer);
}
public static void changeStringBuffer(StringBuffer stringBuffer) {
stringBuffer = new StringBuffer("掘金:申城异乡人");
stringBuffer.append(",欢迎大家关注");
}
}
результат операции:
Blog Garden: Незнакомец в Шэньчэне
Blog Garden: Незнакомец в Шэньчэне
Может быть, вы думаете, что во второй раз вы должны вывести «Самородки: незнакомец в Шэньчэне, всем просьба обратить внимание», почему вывод по-прежнему является исходным значением, то есть потому, что в changeStringBuffer создается новый объект StringBuffer, в это время Переменная stringBuffer Адрес памяти, на который указывает указатель, изменился, поэтому переменная stringBuffer в основном методе не затрагивается.
Если вы измените код метода changeStringBuffer() следующим образом:
public static void changeStringBuffer(StringBuffer stringBuffer) {
stringBuffer.append(",欢迎大家关注");
}
Тогда бегущий результат станет:
Blog Garden: Незнакомец в Шэньчэне
Blog Garden: Незнакомец в Шэньчэне, приглашаю всех обратить внимание
Пример 4 (строковый тип):
package com.zwwhnly.springbootaction;
public class ArrayListDemo {
public static void main(String[] args) {
String str = new String("博客园:申城异乡人");
System.out.println(str);
changeString(str);
System.out.println(str);
}
public static void changeString(String string) {
//string = "掘金:申城异乡人";
string = new String("掘金:申城异乡人");
}
}
результат операции:
Blog Garden: Незнакомец в Шэньчэне
Blog Garden: Незнакомец в Шэньчэне
Не работает в методе ChangeString ()string = "掘金:申城异乡人";
все ещеstring = new String("掘金:申城异乡人");
, переменная str в основном методе не будет затронута, а также проверяется неизменность строки после ее создания.
Пример 5 (пользовательский тип):
package com.zwwhnly.springbootaction;
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(String name) {
this.name = name;
}
}
package com.zwwhnly.springbootaction;
public class ArrayListDemo {
public static void main(String[] args) {
Person person = new Person("zhangsan");
System.out.println(person.getName());
changePerson(person);
System.out.println(person.getName());
}
public static void changePerson(Person p) {
Person person = new Person("lisi");
p = person;
}
}
результат операции:
zhangsan
zhangsan
Измените код метода changePerson() на:
public static void changePerson(Person p) {
p.setName("lisi");
}
Тогда текущий результат:
zhangsan
lisi
7. Ссылка
О == и равняется разнице между контактом и интервью, чтобы вы могли ответить
Разница между знаком == и методом equals() в Java
Разница между String, StringBuilder, StringBuffer в Java
Глубокое погружение в упаковку и распаковку в Java
Вопросы для интервью для Integer, new Integer() и сравнения int
Разница между int и Integer в вопросах интервью Java
Сводка наиболее распространенных вопросов на собеседовании по Java — неделя 1