提交 fefb86ec 编写于 作者: W wizardforcel

2020-06-13 17:31:27

上级 fe28e4a0
......@@ -42,7 +42,7 @@
**可重复测试**每次运行都会产生相同的结果。 要完成可重复的测试,必须将它们与外部环境中的任何东西隔离开,而不是直接控制。 在这些情况下,请随意使用模拟对象。 它们就是为此目的而设计的。
有时,您需要直接与外部环境影响进行交互,例如数据库。 您需要设置一个私沙箱,以避免与测试同时更改数据库的其他开发人员发生冲突。 在这种情况下,您可以使用[内存数据库](//howtodoinjava.com/hibernate/hibernate-4-using-in-memory-database-with-hibernate/)
有时,您需要直接与外部环境影响进行交互,例如数据库。 您需要设置一个私沙箱,以避免与测试同时更改数据库的其他开发人员发生冲突。 在这种情况下,您可以使用[内存数据库](//howtodoinjava.com/hibernate/hibernate-4-using-in-memory-database-with-hibernate/)
如果测试不可重复,那么您肯定会得到一些虚假的测试结果,并且您不能浪费时间去追逐幻象问题。
......
......@@ -93,6 +93,6 @@ public class QuickSortExample
Output: [3, 6, 10, 12, 13, 24, 70, 90]
```
在 Java 中, [**`Arrays.sort()`**](http://developer.classpath.org/doc/java/util/Arrays-source.html)方法使用快速排序算法使用双枢轴元素对基元数组进行排序。 双枢轴使该算法更快。 检查出。
在 Java 中, [**`Arrays.sort()`**](http://developer.classpath.org/doc/java/util/Arrays-source.html)方法使用快速排序算法使用双枢轴元素对原始类型数组进行排序。 双枢轴使该算法更快。 检查出。
学习愉快!
\ No newline at end of file
......@@ -76,7 +76,7 @@
#### 1.7 [Java 中的多态是什么?](//howtodoinjava.com/object-oriented/what-is-polymorphism-in-java/)
简而言之,**多态性**是一种能力,通过它我们可以创建在不同程序环境下表现不同的函数或参考变量。 与继承,抽象和封装一样,多态是面向对象编程的主要构建块之一。
简而言之,**多态性**是一种能力,通过它我们可以创建在不同程序环境下表现不同的函数或引用变量。 与继承,抽象和封装一样,多态是面向对象编程的主要构建块之一。
通过示例更详细地了解该概念。 这是如此重要。
......@@ -107,7 +107,7 @@
* 如何在枚举中实现反向查找?
* 什么是`EnumMap``EnumSet`
#### 1.12 [Java 序列化和可序列化接口](//howtodoinjava.com/java/serialization/a-mini-guide-for-implementing-serializable-interface-in-java/)
#### 1.12 [Java 序列化和`Serializable`接口](//howtodoinjava.com/java/serialization/a-mini-guide-for-implementing-serializable-interface-in-java/)
如果您准备对电信公司或在其应用流程中使用**序列化**的任何此类域进行 Java 面试,那么您将从本教程中受益匪浅。 用 Java 进行序列化的可做与不可做的一个很好的列表。 可能的问题可能包括:
......@@ -119,7 +119,7 @@
#### 1.13 [Java `main`方法](//howtodoinjava.com/java/related-concepts/a-mini-guide-to-main-method-in-java/ "A mini guide to main method in java")
有没有想过为什么`main()`是公的,静态的和`void`? 在 Java 面试中,这不是一个经常问到的面试问题,但我仍然建议您阅读这篇文章来回答以下问题:
有没有想过为什么`main()`是公的,静态的和`void`? 在 Java 面试中,这不是一个经常问到的面试问题,但我仍然建议您阅读这篇文章来回答以下问题:
* Java `main`方法语法?
* 为什么`main`方法是公开的?
......
......@@ -37,89 +37,94 @@ When do you override hashCode and equals()?
* 自动是线程安全的,并且没有同步问题
* 不需要复制构造器
* 不需要克隆的实现
* 允许 hashCode 使用延迟初始化,并缓存其返回值
* 允许`hashCode`使用延迟初始化,并缓存其返回值
* 用作字段时不需要防御性地复制
* 制作好`Map`键和`Set`元素(这些对象在集合中时不得更改状态)
* 在构造时就建立了其类不变式,因此无需再次检查
* 始终具有“ **失败原子性**”(约书亚·布洛赫(Joshua Bloch)使用的术语):如果不可变对象抛出异常,则永远不会处于不希望或不确定的状态。
* 始终具有“**失败原子性**”(Joshua Bloch 使用的术语):如果不可变对象抛出异常,则永远不会处于不希望或不确定的状态。
看一下这篇在 中用 [**编写的示例。**](//howtodoinjava.com/java/related-concepts/how-to-make-a-java-class-immutable/ "How to make a java class immutable")
看一下这篇在 Java 中[**编写的示例**](//howtodoinjava.com/java/related-concepts/how-to-make-a-java-class-immutable/ "How to make a java class immutable")
## Java 是按引用传递还是按值传递?
Java 规范说 Java 中的 ***都是按值传递*** 。 在 Java 中,没有“ *引用传递*”之类的东西。 这些术语与方法调用关联,并将变量作为方法参数传递。 好吧,原始类型总是按值传递而不会造成任何混淆。 但是,应该在复杂类型的方法参数的上下文中理解该概念。
Java 规范说 Java ***都是按值传递***。 在 Java 中,没有“*引用传递*”之类的东西。 这些术语与方法调用关联,并将变量作为方法参数传递。 好吧,原始类型总是按值传递而不会造成任何混淆。 但是,应该在复杂类型的方法参数的上下文中理解该概念。
在 Java 中,当我们将复杂类型的引用作为任何方法参数传递时,总是将内存地址一点一点地复制到新的引用变量中。 见下图:
![pass-by-value](img/bf3729e69335a6b034e3817adb89a5d0.png)
在上面的示例中,第一个实例的地址位被复制到另一个引用变量,因此导致两个引用都指向存储实际对象的单个存储位置。 请记住,再次引用 null 不会使第一次引用也为 null。 但是,从任一参考变量更改状态也会对其他参考产生影响。
在上面的示例中,第一个实例的地址位被复制到另一个引用变量,因此导致两个引用都指向存储实际对象的单个存储位置。 请记住,再次引用`null`不会使第一次引用也为`null`。 但是,从任一引用变量更改状态也会对其他参考产生影响。
> 在此处详细阅读: [**通过值或引用传递 Java?**](//howtodoinjava.com/java/related-concepts/java-is-pass-by-value-lets-see-how/)
> 在此处详细阅读: [**Java 是值或引用传递?**](//howtodoinjava.com/java/related-concepts/java-is-pass-by-value-lets-see-how/)
## finally 块的用途是什么? Java 中的 finally 块是否可以保证被调用? 最终何时不调用块?
## `finally`块的用途是什么? Java 中的`finally`块是否可以保证被调用? 何时不调用`finally`块?
`try`块退出时,`finally`块总是执行。 这样可以确保即使发生意外异常也执行`finally`块。 但是`finally`不仅可以用于异常处理,还可以使清除代码意外地被`return``continue``break`绕过。 将清除代码放在`finally`块中始终是一个好习惯,即使没有异常的情况也是如此。
如果在执行`try``catch`代码时退出 JVM,则`finally`块可能不会执行。 同样,如果执行`try``catch`代码的线程被中断或杀死,则即使整个应用继续运行,`finally`块也可能不会执行。
## 为什么有两个 Date 类; 一个在 java.util 包中,另一个在 java.sql 中?
## 为什么有两个`Date`类; 一个在`java.util`包中,另一个在`java.sql`中?
`java.util.Date`代表一天中的日期和时间,`java.sql.Date`仅代表日期。 `java.sql.Date`的补码为`java.sql.Time`,仅代表一天中的某个时间。
`java.sql.Date``java.util.Date`的子类(扩展)。 因此,`java.sql.Date`中发生了什么变化:
`toString()`生成不同的字符串表示形式: **yyyy-mm-dd**
`toString()`生成不同的字符串表示形式:`yyyy-mm-dd`
– 一种`static valueOf(String)`方法,从具有上述表示形式的字符串中创建日期
吸气器和设置器数小时 ,不建议使用分钟和秒
获取器和设置器数小时 ,不建议使用分钟和秒
`java.sql.Date`类与 JDBC 一起使用,并且不应包含时间部分,即小时,分钟,秒和毫秒应为零…但是该类未强制执行。
## 解释标记界面
## 解释标记接口
标记接口模式是计算机科学中的一种设计模式,与**提供有关对象**的运行时类型信息的语言一起使用。 它为**提供了一种方法,可将元数据与该语言不明确支持此类的类相关联。** 在 Java 中,它用作未指定方法的接口。
标记接口模式是计算机科学中的一种设计模式,与**提供有关对象**的运行时类型信息的语言一起使用。 它为**提供了一种方法,可将元数据与该语言不明确支持此类的类相关联。** 在 Java 中,它用作未指定方法的接口。
在 Java 中使用标记接口的一个很好的例子是[可序列化的](//howtodoinjava.com/java/serialization/a-mini-guide-for-implementing-serializable-interface-in-java/ "A mini guide for implementing serializable interface in java")接口。 一个类实现此接口,以指示可以将其非瞬态数据成员写入字节流或文件系统。
在 Java 中使用标记接口的一个很好的例子是[Serializable](//howtodoinjava.com/java/serialization/a-mini-guide-for-implementing-serializable-interface-in-java/ "A mini guide for implementing serializable interface in java")接口。 一个类实现此接口,以指示可以将其非瞬态数据成员写入字节流或文件系统。
标记接口的*主要问题*是,接口定义用于实现类的协定,并且该协定被所有子类继承。 这意味着**您不能“取消实现”标记**。 在给定的示例中,如果创建不想序列化的子类(可能是因为它依赖于瞬态),则必须诉诸显式抛出 NotSerializableException
标记接口的*主要问题*是,接口定义用于实现类的协定,并且该协定被所有子类继承。 这意味着**您不能“取消实现”标记**。 在给定的示例中,如果创建不想序列化的子类(可能是因为它依赖于瞬态),则必须诉诸显式抛出`NotSerializableException`
## 为什么将 Java 中的 main()声明为 public static void
## 为什么将 Java 中的`main()`声明为`public static void`
***为什么公开*?** 的主要方法是`public`,因此它可以在任何地方访问,并且对于可能希望使用它启动应用的每个对象都可以访问。 在这里,我并不是说 JDK / JRE 具有类似的原因,因为 java.exe 或 javaw.exe(对于 Windows)使用 Java 本机接口(JNI)调用来调用方法,因此,无论使用哪种访问修饰符,他们都可以通过任何一种方式来调用它。
***为什么公开?*** `main`方法是`public`,因此它可以在任何地方访问,并且对于可能希望使用它启动应用的每个对象都可以访问。 在这里,我并不是说 JDK / JRE 具有类似的原因,因为`java.exe``javaw.exe`(对于 Windows)使用 Java 本机接口(JNI)调用来调用方法,因此,无论使用哪种访问修饰符,他们都可以通过任何一种方式来调用它
***为什么是静态*?** 假设我们没有像`static`那样的主要方法。 现在,要调用任何方法,您需要它的一个实例。 对? 众所周知,Java 可以有重载的构造器。 现在,应该使用哪一个,重载的构造器的参数从何而来。
***为什么是静态?*** 假设我们没有像`static`那样的主要方法。 现在,要调用任何方法,您需要它的一个实例。 对? 众所周知,Java 可以有重载的构造器。 现在,应该使用哪一个,重载的构造器的参数从何而来。
***为什么无效*?** 因此,没有任何将值返回给实际调用此方法的 JVM 的用途。 应用唯一想与调用过程进行通信的是:正常终止或异常终止。 使用`System.exit(int)`已经可以实现。 非零值表示异常终止,否则一切正常。
***为什么`void`?*** 因此,没有任何将值返回给实际调用此方法的 JVM 的用途。 应用唯一想与调用过程进行通信的是:正常终止或异常终止。 使用`System.exit(int)`已经可以实现。 非零值表示异常终止,否则一切正常。
## 将 String 创建为 new()和字面值之间有什么区别?
## 将 String 创建为`new()`和字面值之间有什么区别?
当我们使用`new()`创建`String`时,它会在堆中创建并添加到字符串池中,而使用字面值创建的`String`仅在字符串池中创建,而字符串池仅存在于堆的 Perm 区域中。
当我们使用`new()`创建`String`时,它会在堆中创建并添加到字符串池中,而使用字面值创建的`String`仅在字符串池中创建,而字符串池仅存在于堆的永久区域中。
那么,您真的需要非常深入地了解字符串池的概念,才能回答此问题或类似问题。 我的建议..关于[字符串类和字符串池](//howtodoinjava.com/java/string/interview-stuff-about-string-class-in-java/ "String pool concepts")的“认真学习”
那么,您真的需要非常深入地了解字符串池的概念,才能回答此问题或类似问题。 我的建议...“认真学习”[字符串类和字符串池](//howtodoinjava.com/java/string/interview-stuff-about-string-class-in-java/ "String pool concepts")
## String 中的 substring()如何工作?
## `String`中的`substring()`如何工作?
Java 中的`String`与其他任何编程语言一样,都是字符序列。 这更像是用于该 char 序列的工具类。 此 char 序列在以下变量中维护:
Java 中的`String`与其他任何编程语言一样,都是字符序列。 这更像是用于该`char`序列的工具类。 此`char`序列在以下变量中维护:
`/** The value is used for character storage. */
**private final char value[];**`
```java
/** The value is used for character storage. */
private final char value[];
```
要在不同情况下访问此数组,请使用以下变量:
`/** The offset is the first index of the storage that is used. */
**private final int offset;**`
```java
/** The offset is the first index of the storage that is used. */
private final int offset;
/** The count is the number of characters in the String. */
private final int count;
```
/ **计数是字符串中的字符数。 * /
**私有最终 int 计数;**
每当我们从任何现有的字符串实例创建子字符串时,`substring()`方法都只会设置`offset``count`变量的新值。 内部 char 数组不变。 如果不小心使用`substring()`方法,这可能是内存泄漏的原因。 [在此处了解更多信息](//howtodoinjava.com/java/string/interview-stuff-about-string-class-in-java/ "interview stuff about string class")
每当我们从任何现有的字符串实例创建子字符串时,`substring()`方法都只会设置`offset``count`变量的新值。 内部`char`数组不变。 如果不小心使用`substring()`方法,这可能是内存泄漏的原因。 [在此处了解更多信息](//howtodoinjava.com/java/string/interview-stuff-about-string-class-in-java/ "interview stuff about string class")
## 解释 HashMap 的工作。 如何解决重复冲突?
## 解释`HashMap`的工作。 如何解决重复冲突?
你们大多数人都会同意,HashMap 是当今面试中最喜欢讨论的话题。 如果有人要我描述“ HashMap 如何工作?”,我只是回答:“ **关于哈希**的原理”。 就这么简单。
你们大多数人都会同意,`HashMap`是当今面试中最喜欢讨论的话题。 如果有人要我描述“`HashMap`如何工作?”,我只是回答:“**关于哈希**的原理”。 就这么简单。
现在,以最简单的形式进行哈希处理是一种在对属性应用任何公式/算法之后为任何变量/对象分配唯一代码的方法。
**定义的映射是:“将键映射到值的对象”** 。 很容易..对吗? 因此,`HashMap`有一个内部类`Entry`,它看起来像这样:
**定义的映射是:“将键映射到值的对象”**。 很容易..对吗? 因此,`HashMap`有一个内部类`Entry`,它看起来像这样:
```java
static class Entry<k ,V> implements Map.Entry<k ,V>
......@@ -134,16 +139,16 @@ final int hash;
当某人尝试将键值对存储在`HashMap`中时,会发生以下情况:
* 首先,检查键对象是否为空。 如果 key 为 null,则值存储在 table [0]位置。 因为 null 的哈希码始终为 0。
* 首先,检查键对象是否为空。 如果`key``null`,则值存储在`table[0]`位置。 因为`null`的哈希码始终为 0。
* 然后,下一步,通过调用键的`hashCode()`方法,使用键的哈希码计算哈希值。 该哈希值用于计算数组中用于存储`Entry`对象的索引。 JDK 设计人员很好地假设可能存在一些编写不当的`hashCode()`函数,它们可能返回非常高或很低的哈希码值。 为解决此问题,他们引入了另一个`hash()`函数,并将对象的哈希码传递给此`hash()`函数,以将哈希值带入数组索引大小的范围内。
* 现在,调用`indexFor(hash, table.length)`函数来计算用于存储 Entry 对象的精确索引位置。
* Here comes the main part. Now, as we know that two unequal objects can have same hash code value, how two different objects will be stored in same array location [called bucket]. Answer is `LinkedList`. If you remember, `Entry` class had an attribute “`next`”. This attribute always points to next object in chain. This is exactly the behavior of `LinkedList`.
* 现在,调用`indexFor(hash, table.length)`函数来计算用于存储`Entry`对象的精确索引位置。
* 这是主要部分。 现在,我们知道两个不相等的对象可以具有相同的哈希码值,如何将两个不同的对象存储在相同的数组位置(称为存储桶)中。 答案是`LinkedList`。 如果您还记得的话,`Entry`类的属性为`next`。 此属性始终指向链中的下一个对象。 这正是`LinkedList`的行为。
因此,在发生碰撞的情况下,`Entry`对象以`LinkedList`形式存储。 当`Entry`对象需要存储在特定索引中时,`HashMap`检查是否已经有一个项目? 如果尚无项目,则`Entry`对象存储在此位置。
如果已经有一个对象位于计算索引上,则检查其`next`属性。 如果为**,则为**,并且当前`Entry`对象成为`LinkedList`中的`next`节点。 如果`next`变量不为空,则遵循步骤直到`next`被求值为空。
如果已经有一个对象位于计算索引上,则检查其`next`属性。 如果为`null`,则当前`Entry`对象成为`LinkedList`中的`next`节点。 如果`next`变量不为空,则遵循步骤直到`next`被求值为空。
如果我们添加另一个具有与之前输入相同的键的值对象,该怎么办。 从逻辑上讲,它应该替换旧值。 怎么做的? 好吧,在确定`Entry`对象的`index`位置之后,在对计算索引上的`LinkedList`进行迭代时,`HashMap`为每个`Entry`对象调用关键对象上的`equals()`方法。 `LinkedList`中的所有这些`Entry`对象将具有相似的哈希码,但`equals()`方法将测试真实相等性。 如果 **key.equals(k)**为 true,则两个键都被视为相同的键对象。 这将仅导致替换`Entry`对象中的 value 对象。
如果我们添加另一个具有与之前输入相同的键的值对象,该怎么办。 从逻辑上讲,它应该替换旧值。 怎么做的? 好吧,在确定`Entry`对象的`index`位置之后,在对计算索引上的`LinkedList`进行迭代时,`HashMap`为每个`Entry`对象调用关键对象上的`equals()`方法。 `LinkedList`中的所有这些`Entry`对象将具有相似的哈希码,但`equals()`方法将测试真实相等性。 如果`key.equals(k)`为`true`,则两个键都被视为相同的键对象。 这将仅导致替换`Entry`对象中的`value`对象。
这样,`HashMap`确保键的唯一性。
......@@ -153,20 +158,20 @@ final int hash;
* 在 Java 接口中声明的变量默认为`final`。 抽象类可能包含非最终变量。
* Java 接口是隐式`abstract`,不能具有实现。 Java 抽象类可以具有实现默认行为的实例方法。
* 默认情况下,Java 接口的成员是公的。 Java 抽象类可以具有类成员通常的风格,例如`private``abstract`等。
* Java 接口应使用关键字“ **实现**”实现; Java 抽象类应使用关键字“ **extended** ”来扩展。
* 默认情况下,Java 接口的成员是公的。 Java 抽象类可以具有类成员通常的风格,例如`private``abstract`等。
* Java 接口应使用关键字“`implements`”实现; Java 抽象类应使用关键字“`extends`”来扩展。
* Java 类可以实现多个接口,但只能扩展一个抽象类。
* 接口是~~的绝对抽象,~~不能实例化; Java 抽象类也无法实例化,但是可以在存在 main()的情况下调用。 从 Java8 开始,您可以在接口 中定义 [**默认方法。**](//howtodoinjava.com/java8/default-methods-in-java-8/)
* 接口是绝对抽象,不能实例化; Java 抽象类也无法实例化,但是可以在存在`main()`的情况下调用。 从 Java8 开始,您可以在接口中定义[**默认方法**](//howtodoinjava.com/java8/default-methods-in-java-8/)
* 抽象类比接口要快一些,因为接口涉及在 Java 中调用任何重写方法之前进行的搜索。 在大多数情况下,这并不是显着的差异,但是如果您正在编写时间紧迫的应用,那么您可能不想无所事事。
## 何时覆盖 hashCode()和 equals()
## 何时覆盖`hashCode()`和`equals()`
`hashCode()``equals()`方法已在`Object`类中定义,该类是 Java 对象的父类。 因此,所有 java 对象都继承这些方法的默认实现。
`hashCode()`方法用于获取给定对象的唯一整数。 当此对象需要存储在类似数据结构的`HashTable`中时,该整数用于确定存储桶位置。 默认情况下,对象的`hashCode()`方法返回并以整数形式表示存储对象的内存地址。 顾名思义,
`equals()`方法用于简单地验证两个对象的相等性。 默认实现只是检查两个对象的对象引用以验证它们的相等性。
请注意,通常有必要在每次重写此方法时都重写 hashCode 方法,以维护`hashCode()`方法的常规约定,该约定规定相等的对象必须具有相等的哈希码。
请注意,通常有必要在每次重写此方法时都重写`hashCode`方法,以维护`hashCode()`方法的常规约定,该约定规定相等的对象必须具有相等的哈希码。
* `equals()`必须定义一个相等关系(它必须是**自反,对称和可传递**)。 另外,它必须是一致的(如果未修改对象,则它必须保持返回相同的值)。 此外,`o.equals(null)`必须始终返回`false`
* `hashCode()`也必须保持一致(如果未根据`equals()`修改对象,则它必须保持返回相同的值)。
......
......@@ -17,23 +17,23 @@ Explain transient and volatile keywords in java?
Difference between Iterator and ListIterator?
```
## 为什么要避免使用 finalize()方法?
## 为什么要避免使用`finalize()`方法?
我们都知道,在回收分配给对象的内存之前,垃圾收集器线程会调用[`finalize()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#finalize--)方法的基本声明。 请参阅此程序的[,该程序证明根本不能保证`finalize()`调用。 其他原因可能是:](//howtodoinjava.com/java/related-concepts/why-not-to-use-finalize-method-in-java/ "Why not to use finalize() method in java")
我们都知道,在回收分配给对象的内存之前,垃圾收集器线程会调用[`finalize()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#finalize--)方法的基本声明。 请参阅[这篇文章](//howtodoinjava.com/java/related-concepts/why-not-to-use-finalize-method-in-java/ "Why not to use finalize() method in java"),证明根本不能保证`finalize()`调用。 其他原因可能是:
1. `finalize()`方法无法像构造器一样在链接中工作。 这意味着就像您调用构造器时一样,所有超类的构造器都将被隐式调用。 但是,在使用 finalize 方法的情况下,则不遵循此方法。 超类的 finalize()应该显式调用。
2. finalize 方法引发的任何异常都将被 GC 线程忽略,并且不会进一步传播,实际上不会记录在日志文件中。 真糟糕,不是吗?
3. Also, There is some performance penalty when finalize() in included in your class. In Effective java (2nd edition ) Joshua bloch says,
1. `finalize()`方法无法像构造器一样在链接中工作。 这意味着就像您调用构造器时一样,所有超类的构造器都将被隐式调用。 但是,在使用`finalize`方法的情况下,则不遵循此方法。 超类的`finalize()`应该显式调用。
2.`finalize`方法引发的任何异常都将被 GC 线程忽略,并且不会进一步传播,实际上不会记录在日志文件中。 真糟糕,不是吗?
3. 另外,当您的类中包含`finalize()`时,也会影响性能。 Joshua bloch 在《Effective Java》(第 2 版)中说,
“哦,还有一件事:使用终结器会严重影响性能。 在我的机器上,创建和销毁简单对象的时间约为 5.6 ns。 添加终结器会将时间增加到 2,400 ns。 换句话说,使用终结器创建和销毁对象要慢 430 倍。”
## 为什么不应该在多线程环境中使用 HashMap? 它也会引起无限循环吗?
## 为什么不应该在多线程环境中使用`HashMap`? 它也会引起无限循环吗?
我们知道`HashMap`是非同步集合,因为它的同步计数器是`HashTable`。 因此,当您在多线程环境中访问集合时,所有线程都在访问集合的单个实例时,出于各种明显的原因,例如`HashTable`,使用`HashTable`更安全。 以避免脏读并保持数据一致性。 在最坏的情况下,这种多线程环境也可能导致无限循环。
是的,它是真实的。 `HashMap.get()`可能导致无限循环。 让我们看看如何?
如果查看源代码 [HashMap.get(Object key)](http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/util/HashMap.java)方法,则如下所示:
如果查看[`HashMap.get(Object key)`](http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/util/HashMap.java)方法的源代码,则如下所示:
```java
public Object get(Object key) {
......@@ -52,7 +52,7 @@ public Object get(Object key) {
```
在多线程环境 IF 中,`while(true){...}`始终是运行时无限循环的受害者,因此`e.next`可以指向自身。 这将导致无限循环。 但是,`e.next`将如何指向自身(即)。
在多线程环境中,`while(true){...}`始终是运行时无限循环的受害者,因此`e.next`可以指向自身。 这将导致无限循环。 但是,`e.next`将如何指向自身(即)。
这可能在`void transfer(Entry[] newTable)`方法中发生,该方法在`HashMap`调整大小时调用。
......@@ -73,40 +73,40 @@ do {
## 解释抽象和封装? 它们有什么关系?
#### 抽象
#### 抽象
[Abstraction](//howtodoinjava.com/object-oriented/understanding-abstraction-in-java/) captures only those details about an object that are relevant to the current perspective.
[抽象](//howtodoinjava.com/object-oriented/understanding-abstraction-in-java/)仅捕获与当前视角有关的那些对象的详细信息。
[面向对象编程](//howtodoinjava.com/object-oriented/object-oriented-principles/)理论中,抽象涉及定义定义代表抽象“角色”的对象的功能,这些抽象“角色”可以执行工作,报告和更改其状态,并与系统中的其他对象“通信”。
任何编程语言中的抽象都可以通过多种方式工作。 从创建子例程到定义用于进行低级语言调用的接口可以看出。 一些抽象试图通过完全隐藏它们依次建立在其上的抽象来限制程序员所需概念的广度。 设计模式。
任何编程语言中的抽象都可以通过多种方式工作。 从创建子例程到定义用于进行低级语言调用的接口可以看出。 一些抽象试图通过完全隐藏它们依次建立在其上的抽象,来限制程序员所需概念的广度。 例如设计模式。
通常,可以通过两种方式查看抽象:
**数据抽象**是创建复杂数据类型并仅公开有意义的操作以与数据类型进行交互的方法,其中隐藏了外部工作中的所有实现细节。
**控抽象**是识别所有此类语句并将其作为工作单元公开的过程。 我们通常在创建函数来执行任何工作时使用此功能。
**控抽象**是识别所有此类语句并将其作为工作单元公开的过程。 我们通常在创建函数来执行任何工作时使用此功能。
#### 封装形式
#### 封装
Wrapping data and methods within classes in combination with implementation hiding (through access control) is often called encapsulation. The result is a data type with characteristics and behaviors. Encapsulation essentially has both i.e. information hiding and implementation hiding.
将类中的数据和方法与实现隐藏(通过访问控制)结合起来通常称为封装。 结果是具有特征和行为的数据类型。 封装本质上既具有信息隐藏又具有实现隐藏。
***进行任何更改,将其封装为*** ”。 它被引用为著名的设计原则。 因此,在任何类中,运行时中的数据都可能发生更改,将来的发行版中可能会更改实现。 因此,封装既适用于数据也适用于实现。
***无论进行任何更改,都封装它***”。 它被引用为著名的设计原则。 因此,在任何类中,运行时中的数据都可能发生更改,将来的发行版中可能会更改实现。 因此,封装既适用于数据也适用于实现。
因此,它们可以像下面这样关联:
– 抽象更多是关于“类可以做什么”。 [想法]
– 封装更多地是关于“如何”实现该功能。 [实现]
- 抽象更多是关于“类可以做什么”。(想法)
- 封装更多地是关于“如何”实现该功能。(实现)
## 接口和抽象类之间的区别?
接口和抽象类之间的基本区别可以算作如下:
* ~~接口不能有任何方法,而抽象类可以~~ [在 [Java8 默认方法](//howtodoinjava.com/java8/default-methods-in-java-8/)之后不正确)
* 接口不能有任何方法,而抽象类可以([Java8 默认方法](//howtodoinjava.com/java8/default-methods-in-java-8/)之后不正确)
* 一个类可以实现许多接口,但只能有一个超类(是否抽象)
* 接口不属于类层次结构。 不相关的类可以实现相同的接口
您应该记住:“当您可以用[ ***来做什么*** 来充分描述该概念时,而无需指定任何[ ***它是如何工作的*** ”,那么您应该使用一个接口。 如果您需要包括一些实现细节,那么您将需要在抽象类中表示您的概念。”
您应该记住:“当您可以用***做什么***充分描述该概念时,而无需指定任何***它是如何工作的***,那么您应该使用一个接口。 如果您需要包括一些实现细节,那么您将需要在抽象类中表示您的概念。”
另外,如果我说的不同:是否可以将许多*分组在一起并用一个名词描述的类? 如果是这样,请以该名词的名称创建一个抽象类,并从其继承这些类。 例如,`Cat`和`Dog`都可以从抽象类`Animal`继承,并且此抽象基类将实现方法`void breathe()`,所有动物都将以完全相同的方式执行该方法。*
......@@ -114,22 +114,22 @@ Wrapping data and methods within classes in combination with implementation hidi
正如某人所说:主要区别在于您想要实现的地方。 通过创建接口,可以将实现移动到实现接口的任何类。 通过创建一个抽象类,您可以在一个中央位置共享所有派生类的实现,并且避免了很多不好的事情,例如代码重复。
## StringBuffer 如何节省内存?
## `StringBuffer`如何节省内存?
[字符串](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html)被实现为[不变对象](//howtodoinjava.com/java/related-concepts/how-to-make-a-java-class-immutable/); 也就是说,当您最初决定将某些内容放入`String`对象时,JVM 会分配一个与初始值大小正好相等的固定宽度数组。 然后将其视为 JVM 内部的常量,在不更改 String 值的情况下,可以大大节省性能。 但是,如果您决定以任何方式更改 String 的内容,那么 JVM 实质上要做的就是将原始 String 的内容复制到一个临时空间中,进行更改,然后将这些更改保存到一个全新的内存阵列中。 因此,在初始化后更改 String 的值是一项相当昂贵的操作。
[字符串](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html)被实现为[不变对象](//howtodoinjava.com/java/related-concepts/how-to-make-a-java-class-immutable/); 也就是说,当您最初决定将某些内容放入`String`对象时,JVM 会分配一个与初始值大小正好相等的固定宽度数组。 然后将其视为 JVM 内部的常量,在不更改`String`值的情况下,可以大大节省性能。 但是,如果您决定以任何方式更改`String`的内容,那么 JVM 实质上要做的就是将原始`String`的内容复制到一个临时空间中,进行更改,然后将这些更改保存到一个全新的内存阵列中。 因此,在初始化后更改`String`的值是一项相当昂贵的操作。
[StringBuffer](https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html) 在 JVM 内部被实现为可动态增长的数组,这意味着任何更改操作都可以在现有内存位置上进行,而新内存仅按需分配。 但是,JVM 没有机会围绕`StringBuffer`进行优化,因为假定其内容在任何情况下都是可更改的。
[`StringBuffer`](https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html)在 JVM 内部被实现为可动态增长的数组,这意味着任何更改操作都可以在现有内存位置上进行,而新内存仅按需分配。 但是,JVM 没有机会围绕`StringBuffer`进行优化,因为假定其内容在任何情况下都是可更改的。
## 为什么在对象类而不是线程中声明了 wait and notify
## 为什么在对象类而不是线程中声明了`wait`和`notify`
[等待,通知,notifyAll 方法](//howtodoinjava.com/java/multi-threading/how-to-work-with-wait-notify-and-notifyall-in-java/)仅在您希望线程访问共享资源并且共享资源可以是堆上的任何 Java 对象时才需要。 因此,这些方法是在核心 Object 类上定义的,因此每个对象都可以控制允许线程在其监视器上等待。 Java 没有用于共享公共资源的任何特殊对象。 没有定义这样的数据结构。因此,在 Object 类上有责任成为共享资源,条件是它可以使用`wait()``notify()``notifyAll()`之类的辅助方法。
[`wait`,`notify`,`notifyAll`方法](//howtodoinjava.com/java/multi-threading/how-to-work-with-wait-notify-and-notifyall-in-java/)仅在您希望线程访问共享资源并且共享资源可以是堆上的任何 Java 对象时才需要。 因此,这些方法是在核心`Object`类上定义的,因此每个对象都可以控制允许线程在其监视器上等待。 Java 没有用于共享公共资源的任何特殊对象。 没有定义这样的数据结构。因此,在`Object`类上有责任成为共享资源,条件是它可以使用`wait()``notify()``notifyAll()`之类的辅助方法。
Java 基于 [Hoare](https://en.wikipedia.org/wiki/Tony_Hoare) 的监视器概念。 在 Java 中,所有对象都有一个监视器。 线程在监视器上等待,因此要执行等待,我们需要 2 个参数:
– 线程
– 监视器(任何对象)
在 Java 设计中,无法指定线程,它始终是当前运行代码的线程。 但是,我们可以指定监视器(这是我们称为 wait 的对象)。 这是一个很好的设计,因为如果我们可以让任何其他线程在所需的监视器上等待,则会导致“入侵”,给设计/编程并发程序带来了困难。 请记住,在 Java 中,不推荐使用会干扰另一个线程执行的所有操作(例如 stop())。
在 Java 设计中,无法指定线程,它始终是当前运行代码的线程。 但是,我们可以指定监视器(这是我们称为`wait`的对象)。 这是一个很好的设计,因为如果我们可以让任何其他线程在所需的监视器上等待,则会导致“入侵”,给设计/编程并发程序带来了困难。 请记住,在 Java 中,不推荐使用会干扰另一个线程执行的所有操作(例如`stop()`)。
## 编写 Java 程序以在 Java 中创建死锁并修复死锁?
......@@ -137,35 +137,35 @@ Java 基于 [Hoare](https://en.wikipedia.org/wiki/Tony_Hoare) 的监视器概念
> 阅读更多:[编写死锁并使用 Java 解决](//howtodoinjava.com/java/multi-threading/writing-a-deadlock-and-resolving-in-java/ "Writing a deadlock and resolving in java")
## 如果您的 Serializable 类包含一个不可序列化的成员,该怎么办? 您如何解决?
## 如果您的`Serializable`类包含一个不可序列化的成员,该怎么办? 您如何解决?
在这种情况下,将在运行时引发 **NotSerializableException** 。 要解决此问题,一个非常简单的解决方案是将此类字段标记为瞬态。 这意味着这些字段将不会被序列化。 如果还要保存这些字段的状态,则应考虑已经实现[可序列化](https://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html)接口的参考变量。
在这种情况下,将在运行时引发`NotSerializableException`。 要解决此问题,一个非常简单的解决方案是将此类字段标记为瞬态。 这意味着这些字段将不会被序列化。 如果还要保存这些字段的状态,则应考虑已经实现[`Serializable`](https://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html)接口的引用变量。
您可能还需要使用`readResolve()``writeResolve()`方法。 让我们总结一下:
* 首先,设置您的不可序列化字段`transient`
*`writeObject()`中,首先在流上调用`defaultWriteObject()`来存储所有非瞬态字段,然后调用其他方法来序列化不可序列化对象的各个属性。
*`readObject()`中,首先在流上调用`defaultReadObject()`以读回所有非瞬态字段,然后调用其他方法(与您添加到 writeObject 的方法相对应)来反序列化不可序列化的对象。
*`readObject()`中,首先在流上调用`defaultReadObject()`以读回所有非瞬态字段,然后调用其他方法(与您添加到`writeObject`的方法相对应)来反序列化不可序列化的对象。
另外,我强烈建议阅读 [**关于 Java**](//howtodoinjava.com/java/serialization/a-mini-guide-for-implementing-serializable-interface-in-java/ "A mini guide for implementing serializable interface in java") 中序列化的完整指南。
另外,我强烈建议阅读[**关于 Java**](//howtodoinjava.com/java/serialization/a-mini-guide-for-implementing-serializable-interface-in-java/ "A mini guide for implementing serializable interface in java") 中序列化的完整指南。
## 解释 Java 中的瞬态和 volatile 关键字?
## 解释 Java 中的`transient`和`volatile`关键字?
#### 短暂的
#### `transient`
*Java 中的**瞬态**关键字用于指示不应序列化字段。* ”根据语言规范:可以将变量标记为`transient`,以指示它们不是对象持久状态的一部分。 例如,您可能具有从其他字段派生的字段,并且仅应以编程方式进行操作,而不要通过序列化来保持状态。
*Java 中的`transient`关键字用于指示不应序列化字段。*”根据语言规范:可以将变量标记为`transient`,以指示它们不是对象持久状态的一部分。 例如,您可能具有从其他字段派生的字段,并且仅应以编程方式进行操作,而不要通过序列化来保持状态。
例如,在`BankPayment.java`类中,可以对`principal``rate`之类的字段进行序列化,而即使在反序列化之后也可以随时计算`interest`
回想一下,java 中的每个线程也都有自己的本地内存空间,并且它在本地内存中执行所有读/写操作。 完成所有操作后,它将所有线程访问该变量的位置写回主存储器中变量的修改状态。 通常,这是 JVM 内部的默认流程。 但是,`volatile`修饰符告诉 JVM,访问该变量的线程必须始终将其自身的变量私有副本与内存中的主副本进行协调。 这意味着每次线程想要读取变量的状态时,它都必须刷新其本地内存状态并从主内存中更新变量。
#### 易挥发的
#### `volatile`
`volatile`在无锁算法中最有用。 当您不使用锁定来访问该变量并且希望一个线程所做的更改在另一个线程中可见时,或者您要创建“后接”关系以确保计算无需重新排序,以确保更改在适当的时间可见。
`volatile`在无锁算法中最有用。 当您不使用锁定来访问该变量并且希望一个线程所做的更改在另一个线程中可见时,或者您要创建“后接”关系以确保计算无需重新排序,以确保更改在适当的时间可见。
`volatile`应该用于在多线程环境中安全发布不可变对象。 声明诸如 public `volatile` ImmutableObject foo 之类的字段可确保所有线程始终看到当前可用的实例引用。
`volatile`应该用于在多线程环境中安全发布不可变对象。 声明诸如`public volatile ImmutableObject foo`之类的字段可确保所有线程始终看到当前可用的实例引用。
## Iterator 和 ListIterator 之间的区别?
## `Iterator`和`ListIterator`之间的区别?
我们可以使用`Iterator`遍历`Set``List``Map`。 但是`ListIterator`仅可用于遍历`List`。 其他差异如下所示。
......@@ -174,7 +174,7 @@ Java 基于 [Hoare](https://en.wikipedia.org/wiki/Tony_Hoare) 的监视器概念
1. 向后迭代。
2. 随时获取索引。
3. 随时添加新值。
4. 在这一点上设置一个新值。
4. 在这个时间设置一个新值。
例如:
......
......@@ -2,7 +2,7 @@
> 原文: [https://howtodoinjava.com/interview-questions/core-java-interview-questions-series-part-3/](https://howtodoinjava.com/interview-questions/core-java-interview-questions-series-part-3/)
[**面试问题系列中:第 1 部分**](//howtodoinjava.com/java/interviews-questions/core-java-interview-questions-series-part-1/ "Core java interview questions series : Part 1")[**第 2 部分**](//howtodoinjava.com/java/interviews-questions/core-java-interview-questions-series-part-2/ "Core java interview questions series : Part 2") ,我们讨论了面试官通常会问的一些重要问题。 现在是推进该讨论的时候了。 在这篇文章中,我将在下面给出的问题列表中进行讨论。
[**面试问题系列中:第 1 部分**](//howtodoinjava.com/java/interviews-questions/core-java-interview-questions-series-part-1/ "Core java interview questions series : Part 1")[**第 2 部分**](//howtodoinjava.com/java/interviews-questions/core-java-interview-questions-series-part-2/ "Core java interview questions series : Part 2"),我们讨论了面试官通常会问的一些重要问题。 现在是推进该讨论的时候了。 在这篇文章中,我将在下面给出的问题列表中进行讨论。
```java
Deep copy and shallow copy?
......@@ -19,9 +19,9 @@ Deep copy and shallow copy?
## 深拷贝和浅拷贝?
克隆是原始副本的精确副本。 在 Java 中,它实质上意味着能够创建状态与原始对象相似的对象。 clone()方法提供了此功能。
克隆是原始副本的精确副本。 在 Java 中,它实质上意味着能够创建状态与原始对象相似的对象。`clone()`方法提供了此功能。
浅拷贝应尽可能少地重复。 默认情况下,Java 克隆是浅表复制或“逐字段复制”,即,由于 Object 类不了解将在其上调用 clone()方法的类的结构。 因此,JVM 被要求克隆时,请执行以下操作:
浅拷贝应尽可能少地重复。 默认情况下,Java 克隆是浅表复制或“逐字段复制”,即,由于`Object`类不了解将在其上调用`clone()`方法的类的结构。 因此,JVM 被要求克隆时,请执行以下操作:
1)如果该类只有原始数据类型成员,则将创建该对象的全新副本,并返回对该新对象副本的引用。
......@@ -31,64 +31,64 @@ Deep copy and shallow copy?
*深度克隆要求满足以下规则。*
1. 无需单独复制基元
2. 原始类中的所有成员类都应支持克隆,而上下文中原始类的 clone 方法应在所有成员类上调用 super.clone()
1. 无需单独复制原始类型
2. 原始类中的所有成员类都应支持克隆,而上下文中原始类的`clone`方法应在所有成员类上调用`super.clone()`
3. 如果任何成员类不支持克隆,则必须在克隆方法中创建该成员类的新实例,并将其所有属性一一复制到新的成员类对象中。 这个新的成员类对象将在克隆对象中设置。
[在此处详细了解克隆](//howtodoinjava.com/java/cloning/a-guide-to-object-cloning-in-java/ "A guide to object cloning in java")
## 什么是同步? 对象级锁定和类级锁定?
***同步*** 是指多线程。 同步的代码块一次只能由一个线程执行。 Java 支持执行多个线程。 这可能会导致两个或多个线程访问相同的字段或对象。 同步是使所有并发线程在执行中保持同步的过程。 同步避免了由于共享内存视图不一致而导致的内存一致性错误。 当方法声明为已同步时; 该线程持有该方法对象的监视器。如果另一个线程正在执行同步方法,则该线程将被阻塞,直到该线程释放监视器。
***同步***是指多线程。 同步的代码块一次只能由一个线程执行。 Java 支持执行多个线程。 这可能会导致两个或多个线程访问相同的字段或对象。 同步是使所有并发线程在执行中保持同步的过程。 同步避免了由于共享内存视图不一致而导致的内存一致性错误。 当方法声明为已同步时; 该线程持有该方法对象的监视器。如果另一个线程正在执行同步方法,则该线程将被阻塞,直到该线程释放监视器。
Java 中的同步是使用 synced 关键字实现的。 您可以在类中的已定义方法或块上使用 synced 关键字。 关键字不能与类定义中的变量或属性一起使用。
Java 中的同步是使用`syncronized`关键字实现的。 您可以在类中的已定义方法或块上使用`syncronized`关键字。 关键字不能与类定义中的变量或属性一起使用。
***对象级别锁定*** 是一种机制,当您要同步非静态方法或非静态代码块,以便仅一个线程将能够在给定实例的代码上执行代码块时, 类。 应该始终这样做以确保实例级数据线程安全。
***对象级别锁定***是一种机制,当您要同步非静态方法或非静态代码块,以便仅一个线程将能够在给定实例的代码上执行代码块时, 类。 应该始终这样做以确保实例级数据线程安全。
***类级别锁定*** 可防止多个线程在运行时进入所有可用实例中的任何同步块。 这意味着,如果在运行时有 100 个 DemoClass 实例,则一次只能在一个实例中的任何一个线程上执行 demoMethod(),而所有其他实例将被其他线程锁定。 为了确保静态数据线程的安全,应该始终这样做。
***类级别锁定***可防止多个线程在运行时进入所有可用实例中的任何同步块。 这意味着,如果在运行时有 100 个`DemoClass`实例,则一次只能在一个实例中的任何一个线程上执行`demoMethod()`,而所有其他实例将被其他线程锁定。 为了确保静态数据线程的安全,应该始终这样做。
[在此处了解有关同步的更多信息。](//howtodoinjava.com/java/multi-threading/thread-synchronization-object-level-locking-and-class-level-locking/ "Thread synchronization, object level locking and class level locking")
## sleep()和 wait()之间的区别?
## `sleep()`和`wait()`之间的区别?
sleep()是一种用于将进程保留几秒钟或所需时间的方法,但是如果使用 wait()方法,线程将进入等待状态,直到我们调用 notify()或 notifyAll()
`sleep()`是一种用于将进程保留几秒钟或所需时间的方法,但是如果使用`wait()`方法,线程将进入等待状态,直到我们调用`notify()``notifyAll()`
主要区别在于,wait()释放锁定或监视器,而 sleep()不在等待期间释放任何锁或监视器。 通常,“等待”用于线程间通信,而“睡眠”用于引入执行暂停。
主要区别在于,`wait()`释放锁定或监视器,而`sleep()`不在等待期间释放任何锁或监视器。 通常,“等待”用于线程间通信,而“睡眠”用于引入执行暂停。
Thread.sleep()在一段时间内将当前线程发送到“不可运行”状态。 该线程将保留其已获取的监视器 - 即,如果该线程当前处于同步块或方法中,则其他线程无法进入该块或方法。 如果另一个线程调用 t.interrupt(),它将唤醒睡眠线程。 请注意,sleep 是一种静态方法,这意味着它始终会影响当前线程(正在执行 sleep 方法的线程)。 一个常见的错误是调用 t.sleep(),其中 t 是一个不同的线程。 即使这样,当前线程仍将 Hibernate,而不是 t 线程。
`Thread.sleep()`在一段时间内将当前线程发送到“不可运行”状态。 该线程将保留其已获取的监视器 - 即,如果该线程当前处于同步块或方法中,则其他线程无法进入该块或方法。 如果另一个线程调用`t.interrupt()`,它将唤醒睡眠线程。 请注意,`sleep`是一种静态方法,这意味着它始终会影响当前线程(正在执行`sleep`方法的线程)。 一个常见的错误是调用`t.sleep()`,其中`t`是一个不同的线程。 即使这样,当前线程仍将睡眠,而不是`t`线程。
object.wait()将当前线程发送到“ Not Runnable”状态,就像 sleep()一样,但要稍加调整。 Wait 是在对象而不是线程上调用的; 我们将此对象称为“锁定对象”。 在调用 lock.wait()之前,当前线程必须在锁对象上进行同步。 然后,wait()释放此锁定,并将线程添加到与该锁定关联的“等待列表”。 稍后,另一个线程可以在同一个锁对象上同步并调用 lock.notify()。 这将唤醒原始的等待线程。 基本上,wait()/ notify()就像 sleep()/ interrupt()一样,仅活动线程不需要直接指针指向睡眠线程,而仅需要指向共享锁对象的指针。
`object.wait()`将当前线程发送到“不可运行”状态,就像`sleep()`一样,但要稍加调整。 `Wait`是在对象而不是线程上调用的; 我们将此对象称为“锁定对象”。 在调用`lock.wait()`之前,当前线程必须在锁对象上进行同步。 然后,`wait()`释放此锁定,并将线程添加到与该锁定关联的“等待列表”。 稍后,另一个线程可以在同一个锁对象上同步并调用`lock.notify()`。 这将唤醒原始的等待线程。 基本上,`wait()`/`notify()`就像`sleep()`/`interrupt()`一样,仅活动线程不需要直接指针指向睡眠线程,而仅需要指向共享锁对象的指针。
[在此处详细阅读区别。](//howtodoinjava.com/java/multi-threading/difference-between-sleep-and-wait/ "Difference between sleep() and wait()?")
## 可以为该参考变量分配 null 吗?
## 可以为`this`引用变量分配`null`吗?
没有。 你不能 在 Java 中,赋值语句的左侧必须是变量。 “ this”是一个特殊的关键字,始终代表当前实例。 这不是任何变量。
没有。 你不能。在 Java 中,赋值语句的左侧必须是变量。 “`this`”是一个特殊的关键字,始终代表当前实例。 这不是任何变量。
同样,不能将 null 分配给“ super”或任何此类关键字。
同样,不能将`null`分配给“`super`”或任何此类关键字。
## 如果& &和&之间有区别怎么办
## `&&`和`&`之间是否有区别
&是按位的,& &是逻辑的。
`&`是按位的,`&&`是逻辑的。
* &求值操作的双方。
* & &求值操作的左侧,如果是,则继续并求值右侧。
* `&`求值操作的双方。
* `&&`求值操作的左侧,如果为真,则继续并求值右侧。
[请阅读此处以深入了解。](https://en.wikipedia.org/wiki/Bitwise_operation "bitwise operations")
## 如何覆盖 equals 和 hashCode()方法?
## 如何覆盖`equals`和`hashCode()`方法?
hashCode()和 equals()方法已在 Object 类中定义,Object 类是 Java 对象的父类。 因此,所有 java 对象都继承这些方法的默认实现。
`hashCode()``equals()`方法已在`Object`类中定义,`Object`类是 Java 对象的父类。 因此,所有 java 对象都继承这些方法的默认实现。
hashCode()方法用于获取给定对象的唯一整数。 当此对象需要存储在类似数据结构的 HashTable 中时,此整数用于确定存储桶位置。 默认情况下,对象的 hashCode()方法返回存储对象的内存地址的整数表示形式。
`hashCode()`方法用于获取给定对象的唯一整数。 当此对象需要存储在类似数据结构的`HashTable`中时,此整数用于确定存储桶位置。 默认情况下,对象的`hashCode()`方法返回存储对象的内存地址的整数表示形式。
顾名思义,equals()方法用于简单地验证两个对象的相等性。 默认实现只是检查两个对象的对象引用以验证它们的相等性。
顾名思义,`equals()`方法用于简单地验证两个对象的相等性。 默认实现只是检查两个对象的对象引用以验证它们的相等性。
以下是在覆盖这些功能时要记住的要点。
1. 始终使用对象的相同属性来生成 hashCode()和 equals()两者。 在本例中,我们使用了员工 ID。
2. equals()必须一致(如果未修改对象,则必须保持返回相同的值)。
3. 只要 a.equals(b),则 a.hashCode()必须与 b.hashCode()相同。
1. 始终使用对象的相同属性来生成`hashCode()``equals()`两者。 在本例中,我们使用了员工 ID。
2. `equals(`)必须一致(如果未修改对象,则必须保持返回相同的值)。
3. 只要`a.equals(b)`,则`a.hashCode()`必须与`b.hashCode()`相同。
4. 如果覆盖一个,则应覆盖另一个。
[在此处阅读更多有趣的事实以及指南。](//howtodoinjava.com/java/related-concepts/working-with-hashcode-and-equals-methods-in-java/ "Working with hashCode and equals methods in java")
......@@ -97,10 +97,10 @@ hashCode()方法用于获取给定对象的唯一整数。 当此对象需要存
Java 类,字段,构造器和方法可以具有四种不同的访问修饰符之一:
***私有***
***`private`***
如果将方法或变量标记为私有,则只有同一类内的代码才能访问该变量或调用该方法。 子类中的代码无法访问变量或方法,也不能从任何外部类中进行代码。
如果将一个类标记为私有,则没有外部类可以访问该类。 不过,对于类来说,这实际上没有多大意义。 因此,访问修饰符 private 主要用于字段,构造器和方法。
如果将一个类标记为私有,则没有外部类可以访问该类。 不过,对于类来说,这实际上没有多大意义。 因此,访问修饰符`private`主要用于字段,构造器和方法。
***默认***
......@@ -108,31 +108,32 @@ Java 类,字段,构造器和方法可以具有四种不同的访问修饰符
如果子类声明了默认的可访问性,则子类不能访问父类中的方法和成员变量,除非子类与父类位于同一包中。
***受保护的***
***`protected`***
protected acces 修饰符的作用与默认访问权限相同,除了子类还可以访问超类的受保护方法和成员变量。 即使子类与超类不在同一个包中,也是如此。
`protected`访问修饰符的作用与默认访问权限相同,除了子类还可以访问超类的受保护方法和成员变量。 即使子类与超类不在同一个包中,也是如此。
***公开***
***`public`***
访问修饰符意味着所有代码都可以访问类,字段,构造器或方法,无论访问代码位于何处。
访问修饰符意味着所有代码都可以访问类,字段,构造器或方法,无论访问代码位于何处。
| ***修饰符*** | *相同的类别* | *相同的包* | *子类* | *其他包* |
| 上市 | 和 | Y | Y | Y |
| 受保护的 | Y | Y | Y | ñ |
| ***修饰符*** | *相同的类* | *相同的包* | *子类* | *其他包* |
| --- | --- | --- |
| `public` | Y | Y | Y | Y |
| `protected` | Y | Y | Y | N |
| 默认 | Y | Y | N | N |
| 私人的 | Y | N | N | N |
| `private` | Y | N | N | N |
## 什么是垃圾回收? 我们可以执行吗?
垃圾回收是许多现代编程语言(例如 Java 和.NET 框架中的语言)中的自动内存管理功能。 使用垃圾回收的语言通常在 JVM 之类的虚拟机中解释或运行。 在每种情况下,运行代码的环境还负责垃圾回收。 GC 具有两个目标:应释放所有未使用的内存,并且除非程序不再使用它,否则不应释放任何内存。
垃圾回收是许多现代编程语言(例如 Java 和 .NET 框架中的语言)中的自动内存管理功能。 使用垃圾回收的语言通常在 JVM 之类的虚拟机中解释或运行。 在每种情况下,运行代码的环境还负责垃圾回收。 GC 具有两个目标:应释放所有未使用的内存,并且除非程序不再使用它,否则不应释放任何内存。
你能强迫垃圾收集吗? 不,System.gc()尽可能接近。 最好的选择是调用 System.gc(),这只是向垃圾收集器提示您要它进行收集。 由于垃圾收集器是不确定的,因此无法强制立即收集。 另外,在 OutOfMemoryError 文档下,它声明除非 VM 在完全垃圾回收后未能回收内存,否则不会抛出该错误。 因此,如果在出现错误之前一直分配内存,那么您将已经强制执行完整的垃圾回收。
你能强迫垃圾收集吗? 不,`System.gc()`尽可能接近。 最好的选择是调用`System.gc()`,这只是向垃圾收集器提示您要它进行收集。 由于垃圾收集器是不确定的,因此无法强制立即收集。 另外,在`OutOfMemoryError`文档下,它声明除非 VM 在完全垃圾回收后未能回收内存,否则不会抛出该错误。 因此,如果在出现错误之前一直分配内存,那么您将已经强制执行完整的垃圾回收。
[在此处详细了解垃圾收集。](//howtodoinjava.com/java/garbage-collection/revisiting-memory-management-and-garbage-collection-mechanisms-in-java/ "Revisiting memory management and garbage collection mechanisms in java")
## 什么是原生关键字? 详细解释?
## 什么是`native关键字? 详细解释?
native 关键字应用于方法,以指示该方法是使用 JNI 在本地代码中实现的。 它标记了一种方法,它将以其他语言而不是 Java 来实现。
`native`关键字应用于方法,以指示该方法是使用 JNI 在本地代码中实现的。 它标记了一种方法,它将以其他语言而不是 Java 来实现。
过去曾使用本机方法来编写对性能至关重要的部分,但随着 Java 变得越来越快,这种方法现在已不那么普遍了。 当前需要本机方法
......@@ -141,38 +142,38 @@ protected acces 修饰符的作用与默认访问权限相同,除了子类还
使用本机代码库的缺点也很重要:
1. JNI / JNA 倾向于破坏 JVM 的稳定性,尤其是当您尝试做一些复杂的事情时。 如果您的本机代码错误地执行了本机代码内存管理,则很有可能会使 JVM 崩溃。 如果您的本机代码是不可重入的,并且从多个 Java 线程中调用,则坏事……会偶尔发生。 等等。
2. 带有本机代码的 Java 比纯 Java 或纯 C / C++ 更难调试。
1. JNI/JNA 倾向于破坏 JVM 的稳定性,尤其是当您尝试做一些复杂的事情时。 如果您的本机代码错误地执行了本机代码内存管理,则很有可能会使 JVM 崩溃。 如果您的本机代码是不可重入的,并且从多个 Java 线程中调用,则坏事……会偶尔发生。 等等。
2. 带有本机代码的 Java 比纯 Java 或纯 C/C++ 更难调试。
3. 本机代码可能为其他平台无关的 Java 应用引入重要的平台依赖项/问题。
4. 本机代码需要一个单独的构建框架,并且也可能存在平台/可移植性问题。
## 什么是序列化? 解释渔获物?
在计算机科学中,在数据存储和传输的上下文中,序列化是将数据结构或对象状态转换为一种格式的过程,该格式可以稍后在相同或另一台计算机环境中存储和``恢复''。 当根据序列化格式重新读取生成的一系列位时,可以使用它来创建原始对象的语义相同的克隆。
在计算机科学中,在数据存储和传输的上下文中,序列化是将数据结构或对象状态转换为一种格式的过程,该格式可以稍后在相同或另一台计算机环境中存储和恢复。 当根据序列化格式重新读取生成的一系列位时,可以使用它来创建原始对象的语义相同的克隆。
Java 提供了自动序列化,该序列化要求通过实现 java.io.Serializable 接口来标记对象。 实现该接口会将类标记为“可以序列化”,然后 Java 将在内部处理序列化。 在可序列化接口上没有定义任何序列化方法,但是可序列化类可以选择定义具有某些特殊名称和签名的方法,如果定义了这些特殊名称和签名,这些方法将在序列化/反序列化过程中被调用。
Java 提供了自动序列化,该序列化要求通过实现`java.io.Serializable`接口来标记对象。 实现该接口会将类标记为“可以序列化”,然后 Java 将在内部处理序列化。 在`Serializable`接口上没有定义任何序列化方法,但是可序列化类可以选择定义具有某些特殊名称和签名的方法,如果定义了这些特殊名称和签名,这些方法将在序列化/反序列化过程中被调用。
对象序列化后,其类中的更改会破坏反序列化过程。 要确定您的类中将来的变化,这些变化将是兼容的,而其他变化将被证明是不兼容的,请在此处 阅读完整的 [**指南。 简而言之,我在这里列出:**](//howtodoinjava.com/java/serialization/a-mini-guide-for-implementing-serializable-interface-in-java/ "A mini guide for implementing serializable interface in java")
对象序列化后,其类中的更改会破坏反序列化过程。 要确定您的类中将来的变化,这些变化将是兼容的,而其他变化将被证明是不兼容的,请在此处阅读完整的[**指南**](//howtodoinjava.com/java/serialization/a-mini-guide-for-implementing-serializable-interface-in-java/ "A mini guide for implementing serializable interface in java")。 简而言之,我在这里列出:
**不兼容的更改**
* 删除栏位
* 删除字段
* 将类上移或下移
* 将非静态字段更改为静态或将非瞬态字段更改为瞬态
* 更改原始字段的声明类型
* 更改 writeObject 或 readObject 方法,使其不再写入或读取默认字段数据
* 更改`writeObject``readObject`方法,使其不再写入或读取默认字段数据
* 将类从可序列化更改为可外部化,反之亦然
* 将类从非枚举类型更改为枚举类型,反之亦然
* 删除可序列化或可外部化的
* writeReplace 或 readResolve 方法添加到类
* 删除`Serializable``Externalizable`
*`writeReplace``readResolve`方法添加到类
**兼容的更改**
* 新增栏位
* 新增字段
* 添加/删除类
* 添加 writeObject / readObject 方法[首先应调用 defaultReadObject 或 defaultWriteObject]
* 删除 writeObject / readObject 方法
* 添加 java.io.Serializable
* 添加`writeObject`/`readObject`方法(首先应调用`defaultReadObject``defaultWriteObject`)
* 删除`writeObject`/`readObject`方法
* 添加`java.io.Serializable`
* 更改对字段的访问
* 将字段从静态更改为非静态或将瞬态更改为非瞬态
......
......@@ -2,7 +2,7 @@
> 原文: [https://howtodoinjava.com/interview-questions/useful-java-collection-interview-questions/](https://howtodoinjava.com/interview-questions/useful-java-collection-interview-questions/)
毫无疑问,java 集合是最重要的领域之一,无论您是初级还是高级,您都可以在任何位置对其进行测试。 范围如此之广,几乎不可能涵盖所有问题。 但是,根据我以前的面试,我尝试提出您必须知道的尽可能多的 GOOD **java 集合面试问题**
毫无疑问,java 集合是最重要的领域之一,无论您是初级还是高级,您都可以在任何位置对其进行测试。 范围如此之广,几乎不可能涵盖所有问题。 但是,根据我以前的面试,我尝试提出您必须知道的尽可能多的优秀的 **java 集合面试问题**
我的目标是初学者和高级问题,所以如果您发现一些基本问题,请多多包涵,因为它们对某些初级开发人员可能有用。
......@@ -70,30 +70,30 @@ More questions
不要浪费时间,让我们深入研究 Java 集合的概念。
## Java Collection 面试一般问题
## Java 集合面试一般问题
#### 1)什么是 Java Collection 框架? 列出其优势?
#### 1)什么是 Java 集合框架? 列出其优势?
根据定义,集合是**代表一组对象**的对象。 像集合论一样,集合是一组元素。 很简单!
在 JDK 1.2 之前,JDK 具有一些工具类,例如 Vector 和 HashTable,但是没有 Collection 框架的概念。 从 JDK 1.2 以后,JDK 感到需要对可重用数据结构提供一致的支持。 最后,集合框架主要由 Joshua Bloch 设计和开发,并在 JDK 1.2 中引入了**。**
在 JDK 1.2 之前,JDK 具有一些工具类,例如`Vector``HashTable`,但是没有集合框架的概念。 从 JDK 1.2 以后,JDK 感到需要对可重用数据结构提供一致的支持。 最后,集合框架主要由 Joshua Bloch 设计和开发,并在 JDK 1.2 中引入。
Java 集合的最明显的**优点可以列出为:**
Java 集合的最明显的**优点可以列出为**
* 随时可用的代码,减少了编程工作
* 由于数据结构和算法的高性能实现而提高了性能
* 通过建立公共语言来回传递集合,从而在不相关的 API 之间提供互操作性
* 通过仅学习一些顶级接口和受支持的操作,易于学习的 API
#### 2)解释集合的等级
#### 2)解释集合的层次结构
![Java Collection Hierarchy](img/4d680a6ab9e27aa22e1a05cb1cc772fd.png "Java Collection Hierarchy")
Java Collection Hierarchy
Java 集合的层次结构
如上图所示,集合框架顶部有一个接口,即**集合**。 通过设置,列表和队列接口对其进行了扩展。 然后在这 3 个分支中还有其他类别的负载,我们将在以下问题中学习。
如上图所示,集合框架顶部有一个接口,即**集合**。 通过,列表和队列接口对其进行了扩展。 然后在这 3 个分支中还有其他类别的负载,我们将在以下问题中学习。
记住`Collection`接口的签名。 它会在很多问题上帮助您。
......@@ -104,33 +104,33 @@ public interface Collection extends Iterable {
```
框架还包含`Map`接口,它是集合框架的一部分。 但它不会扩展 Collection 接口。 我们将在此问题库中的第四个问题中看到原因。
框架还包含`Map`接口,它是集合框架的一部分。 但它不会扩展`Collection`接口。 我们将在此问题库中的第四个问题中看到原因。
#### 3)为什么 Collection 接口没有扩展 Cloneable 和 Serializable 接口?
#### 3)为什么`Collection`接口没有扩展`Cloneable`和`Serializable`接口?
好吧,最简单的答案是“ **不需要这样做**”。 扩展接口仅表示您正在创建接口的子类型,换句话说,不希望使用更专门的行为和 Collection 接口来实现 Cloneable 和 Serializable 接口。
好吧,最简单的答案是“**不需要这样做**”。 扩展接口仅表示您正在创建接口的子类型,换句话说,不希望使用更专门的行为和`Collection`接口来实现`Cloneable``Serializable`接口。
另一个原因是并非每个人都有理由拥有 Cloneable 集合,因为如果它具有非常大的数据,那么每个**不必要的克隆操作都将消耗大量内存**。 初学者可能在不知道后果的情况下使用它。
另一个原因是并非每个人都有理由拥有`Cloneable`集合,因为如果它具有非常大的数据,那么每个**不必要的克隆操作都将消耗大量内存**。 初学者可能在不知道后果的情况下使用它。
另一个原因是 **Cloneable 和 Serializable 是非常专门的行为**,因此仅在需要时才应实现。 例如,集合中的许多具体类都实现了这些接口。 因此,如果您想要此功能。 使用这些集合类,否则使用其替代类。
另一个原因是`Cloneable``Serializable`是非常专门的行为,因此仅在需要时才应实现。 例如,集合中的许多具体类都实现了这些接口。 因此,如果您想要此功能。 使用这些集合类,否则使用其替代类。
#### 4)为什么 Map 接口没有扩展 Collection 接口?
#### 4)为什么`Map`接口没有扩展`Collection`接口?
这个面试问题的一个很好的答案是“ **,因为它们不兼容**”。 集合具有方法 add(Object o)。 Map 无法使用这种方法,因为它需要键值对。 还有其他原因,例如 Map 支持 keySet,valueSet 等。Collection 类没有此类视图。
这个面试问题的一个很好的答案是“**因为它们不兼容**”。 集合具有方法`add(Object o)`。 Map 无法使用这种方法,因为它需要键值对。 还有其他原因,例如`Map`支持`keySet``valueSet`等。`Collection`类没有此类视图。
由于存在如此大的差异,因此在 Map 界面中未使用 Collection 界面,而是在单独的层次结构中构建。
由于存在如此大的差异,因此在`Map`界面中未使用`Collection`界面,而是在单独的层次结构中构建。
## Java 集合面试 – 列出接口问题
#### 5)为什么要使用 List 接口? 什么是实现 List 接口的主要类?
#### 5)为什么要使用`List`接口? 什么是实现`List`接口的主要类?
Java 列表是元素的**“有序”集合。 该排序是基于**零的索引**。 它不关心重复项。 除了在 Collection 接口中定义的方法外,它**确实有自己的方法**,它们在很大程度上也要根据元素**的索引位置来操作集合**。 这些方法可以分为搜索,获取,迭代和范围视图。 以上所有操作均支持索引位置。**
Java 列表是元素的“有序”集合。 该排序是基于**零的索引**。 它不关心重复项。 除了在`Collection`接口中定义的方法外,它**确实有自己的方法**,它们在很大程度上也要根据元素**的索引位置来操作集合**。 这些方法可以分为搜索,获取,迭代和范围视图。 以上所有操作均支持索引位置。
实现 List 接口的主要类为: **Stack,Vector,ArrayList 和 LinkedList** 。 在 Java 文档中阅读有关它们的更多信息。
实现`List`接口的主要类为: `Stack``Vector``ArrayList``LinkedList`。 在 Java 文档中阅读有关它们的更多信息。
#### 6)如何将 String 数组转换为 arraylist
#### 6)如何将`String`数组转换为`arraylist`
这更多是一个程序性问题,在初学者水平上可以看到。 目的是检查集合工具类中申请人的知识。 现在,让我们了解 Collection 框架中有两个工具类,它们大多数在面试中看到,即 **Collections 和 Arrays**
这更多是一个程序性问题,在初学者水平上可以看到。 目的是检查集合工具类中申请人的知识。 现在,让我们了解`Collection`框架中有两个工具类,它们大多数在面试中看到,即`Collections``Arrays`
集合类提供了一些静态函数来对集合类型执行特定操作。 数组提供了要在数组类型上执行的工具功能。
......@@ -143,7 +143,7 @@ List wordList = Arrays.asList(words);
```
请注意,此函数并非特定于 String 类,它将返回数组属于任何类型的元素的 List。 例如:
请注意,此函数并非特定于`String`类,它将返回数组属于任何类型的元素的`List`。 例如:
```java
//String array
......@@ -155,28 +155,28 @@ List numsList = Arrays.asList(nums);
#### 7)如何反转列表?
这个问题就像上面的测试您对**集合**工具类的了解。 使用它 **reverse()**方法可以反转列表。
这个问题就像上面的测试您对**集合**工具类的了解。 使用它`reverse()`方法可以反转列表。
```java
Collections.reverse(list);
```
## Java 集合面试 – 设置接口问题
## Java 集合面试 – `Set``接口问题
#### 8)为什么要使用 Set 接口? 什么是实现 Set 接口的主要类?
#### 8)为什么要使用`Set`接口? 什么是实现`Set`接口的主要类?
**对集合论**中的数学集合进行建模。 Set 接口类似于 List 接口,但有一些区别。 首先,它是**未排序的集合**。 因此,添加或删除元素时不会保留任何顺序。 它提供的主要功能是“ **元素**的唯一性”。 它不支持重复元素。
**对集合论**中的数学集合进行建模。 `Set`接口类似于`List`接口,但有一些区别。 首先,它是**未排序的集合**。 因此,添加或删除元素时不会保留任何顺序。 它提供的主要功能是“**元素**的唯一性”。 它不支持重复元素。
Set 还对 equals 和 hashCode 操作的行为增加了更强的约定,从而即使它们的实现类型不同,也可以有意义地比较 Set 实例。 如果两个 Set 实例包含相同的元素,则它们相等。
`Set`还对`equals``hashCode`操作的行为增加了更强的约定,从而即使它们的实现类型不同,也可以有意义地比较`Set`实例。 如果两个`Set`实例包含相同的元素,则它们相等。
基于上述原因,它**没有基于列表**之类的元素的索引进行的操作。 它只有由 Collection 接口继承的方法。
基于上述原因,它**没有基于列表**之类的元素的索引进行的操作。 它只有由`Collection`接口继承的方法。
实现 Set 接口的主要类为: **EnumSet,HashSet,LinkedHashSet,TreeSet** 。 阅读更多有关 Java 文档的信息。
实现`Set`接口的主要类为:`EnumSet``HashSet``LinkedHashSet``TreeSet`。 阅读更多有关 Java 文档的信息。
#### 9)HashSet 如何存储元素?
#### 9)`HashSet`如何存储元素?
您必须知道 HashMap 存储具有一个条件的键值对,即键将是唯一的。 HashSet 使用映射的此功能来确保元素的唯一性。 在 HashSet 类中,映射声明如下:
您必须知道`HashMap`存储具有一个条件的键值对,即键将是唯一的。 `HashSet`使用映射的此功能来确保元素的唯一性。 在`HashSet`类中,映射声明如下:
```java
private transient HashMap<E,Object> map;
......@@ -186,7 +186,7 @@ private static final Object PRESENT = new Object();
```
因此,**将元素存储在 HashSet 中时,会将元素存储为 map 中的键,将“ PRESENT”对象存储为值**。 (请参见上面的声明)。
因此,**将元素存储在`HashSet`中时,会将元素存储为映射中的键,将“`PRESENT`”对象存储为值**。 (请参见上面的声明)。
```java
public boolean add(E e) {
......@@ -195,13 +195,13 @@ return map.put(e, PRESENT)==null;
```
我强烈建议您阅读这篇文章: [**HashMap 如何在 Java 中工作?**](//howtodoinjava.com/java/collections/how-hashmap-works-in-java/ "How hashmap works in java") 这篇文章将帮助您轻松地回答所有与 HashMap 相关的问题。
我强烈建议您阅读这篇文章:[**`HashMap`如何在 Java 中工作?**](//howtodoinjava.com/java/collections/how-hashmap-works-in-java/ "How hashmap works in java")这篇文章将帮助您轻松地回答所有与`HashMap`相关的问题。
#### 10)是否可以将 null 元素添加到 TreeSet 或 HashSet 中?
#### 10)是否可以将`null`元素添加到`TreeSet`或 HashSet 中?
如您所见,上一个问题的 add()方法中没有 null 检查。 并且 HashMap 还允许一个 null 键,因此**在 HashSet** 中允许一个“ null”。
如您所见,上一个问题的`add()`方法中没有`null`检查。 并且`HashMap`还允许一个`null`键,因此在`HashSet`中允许一个“`null`”。
TreeSet 使用与 HashSet 相同的概念进行内部逻辑,但是使用 NavigableMap 来存储元素。
`TreeSet`使用与`HashSet`相同的概念进行内部逻辑,但是使用`NavigableMap`来存储元素。
```java
private transient NavigableMap<E,Object> m;
......@@ -211,35 +211,35 @@ private static final Object PRESENT = new Object();
```
NavigableMap 是 SortedMap 的子类型,不允许使用 null 键。 因此,本质上, **TreeSet 也不支持空键**。 如果您尝试在 TreeSet 中添加 null 元素,它将抛出 NullPointerException
`NavigableMap``SortedMap`的子类型,不允许使用`null`键。 因此,本质上,`TreeSet`也不支持空键。 如果您尝试在`TreeSet`中添加`null`元素,它将抛出`NullPointerException`
## Java 集合面试 – Map 接口问题
## Java 集合面试 – `Map`接口问题
#### 11)为什么要使用 Map 界面? 什么是实现 Map 接口的主要类?
#### 11)为什么要使用`Map`界面? 什么是实现`Map`接口的主要类?
Map 接口是一种特殊的集合类型,它是**,用于存储键值对**。 因此,它不会扩展 Collection 接口。 该界面提供了在映射的各种视图上添加,删除,搜索或迭代的方法。
`Map`接口是一种特殊的集合类型,它用于存储键值对。 因此,它不会扩展`Collection`接口。 该界面提供了在映射的各种视图上添加,删除,搜索或迭代的方法。
实现 Map 接口的主要类有: **HashMap,Hashtable,EnumMap,IdentityHashMap,LinkedHashMap 和 Properties。**
实现`Map`接口的主要类有:`HashMap``Hashtable``EnumMap``IdentityHashMap``LinkedHashMap``Properties`
#### 12)什么是 IdentityHashMap 和 WeakHashMap
#### 12)什么是 `IdentityHashMap`和`WeakHashMap`
**IdentityHashMap** 与 HashMap 相似,不同之处在于**在比较元素**时使用引用相等性。 IdentityHashMap 类不是一种广泛使用的 Map 实现。 尽管此类实现了 Map 接口,但它有意违反 Map 的一般协定,该协定要求在比较对象时必须使用 equals()方法。 IdentityHashMap 设计为仅在少数情况下使用,其中需要引用相等语义。
`IdentityHashMap``HashMap`相似,不同之处在于**在比较元素**时使用引用相等性。 `IdentityHashMap`类不是一种广泛使用的`Map`实现。 尽管此类实现了`Map`接口,但它有意违反`Map`的一般协定,该协定要求在比较对象时必须使用`equals()`方法。 `IdentityHashMap`设计为仅在少数情况下使用,其中需要引用相等语义。
**WeakHashMap** 是 Map 接口**的实现,该接口仅存储对其键**的弱引用。 当不再在 WeakHashMap 外部引用键值对时,仅存储弱引用将允许对键值对进行垃圾回收。 该类主要用于与 equals 方法使用==运算符测试对象标识的键对象一起使用。 一旦丢弃了这样的键,就永远无法重新创建它,因此以后不可能在 WeakHashMap 中对该键进行查找,并且会惊讶地发现它的项目已被删除。
`WeakHashMap``Map`接口**的实现,该接口仅存储对其键**的弱引用。 当不再在`WeakHashMap`外部引用键值对时,仅存储弱引用将允许对键值对进行垃圾回收。 该类主要用于与`equals`方法使用`==`运算符测试对象标识的键对象一起使用。 一旦丢弃了这样的键,就永远无法重新创建它,因此以后不可能在`WeakHashMap`中对该键进行查找,并且会惊讶地发现它的项目已被删除。
#### 13)解释 ConcurrentHashMap 吗? 怎么运行的?
#### 13)解释`ConcurrentHashMap`吗? 怎么运行的?
*来自 Java 文档:*
**支持检索的完全并发和用于更新**的可调整预期并发的哈希表。 此类遵循与 Hashtable 相同的功能规范,并且包括与 Hashtable 的每个方法相对应的方法的版本。 但是,即使所有操作都是线程安全的,检索操作也不需要进行锁定,并且不支持以阻止所有访问的方式锁定整个表。 在依赖于其线程安全性但不依赖于其同步详细信息的程序中,此类可与 Hashtable 完全互操作。
**支持检索的完全并发和用于更新**的可调整预期并发的哈希表。 此类遵循与`Hashtable`相同的功能规范,并且包括与`Hashtable`的每个方法相对应的方法的版本。 但是,即使所有操作都是线程安全的,检索操作也不需要进行锁定,并且不支持以阻止所有访问的方式锁定整个表。 在依赖于其线程安全性但不依赖于其同步详细信息的程序中,此类可与`Hashtable`完全互操作。
阅读有关 [**ConcurrentHashMap 面试问题**](//howtodoinjava.com/java/collections/popular-hashmap-and-concurrenthashmap-interview-questions/ "Popular HashMap and ConcurrentHashMap interview questions") 的更多信息。
阅读有关[**`ConcurrentHashMap`面试问题**](//howtodoinjava.com/java/collections/popular-hashmap-and-concurrenthashmap-interview-questions/ "Popular HashMap and ConcurrentHashMap interview questions")的更多信息。
#### 14)`HashMap`如何工作?
**最重要的问题**在每个工作面试中最有可能出现。 您必须在这个主题上非常清楚。,不仅因为它是最常被问到的问题,而且会让您对与集合 API 相关的其他问题敞开心 mind
**最重要的问题**在每个工作面试中最有可能出现。 您必须在这个主题上非常清楚。不仅因为它是最常被问到的问题,而且会让您对与集合 API 相关的其他问题打开思路
这个问题的答案非常大,您应该阅读我的文章: [**HashMap 如何工作?**](//howtodoinjava.com/java/collections/how-hashmap-works-in-java/ "How hashmap works in java") 现在,让我们记住 HashMap 在[Hashing ]原理上工作**。 根据定义,映射是:“将键映射到值的对象”。 为了存储这种结构,**使用了内部类 Entry** :**
这个问题的答案非常大,您应该阅读我的文章:[**`HashMap`如何工作?**](//howtodoinjava.com/java/collections/how-hashmap-works-in-java/ "How hashmap works in java") 现在,让我们记住`HashMap`在哈希原理上工作。 根据定义,映射是:“将键映射到值的对象”。 为了存储这种结构,**使用了内部类`Entry`**
```java
static class Entry implements Map.Entry
......@@ -253,7 +253,7 @@ final int hash;
```
此处,键和值变量用于存储键 - 值对。 整个项目对象存储在数组中。
此处,键和值变量用于存储键值对。 整个项目对象存储在数组中。
```java
/**
......@@ -263,200 +263,201 @@ transient Entry[] table;
```
数组的索引是根据 Key 对象的哈希码计算的。 阅读更多链接主题。
数组的索引是根据`Key`对象的哈希码计算的。 阅读更多链接主题。
#### 15)如何为哈希表设计一个好的键?
在回答`HashMap`如何工作后,通常会跟进另一个好问题。 好吧,最重要的约束是**,您将来必须能够取回值对象**。 否则,没有使用这种数据结构。 如果您了解 hashmap 的工作原理,将会发现它很大程度上取决于 Key 对象的 hashCode()和 equals()方法。
在回答`HashMap`如何工作后,通常会跟进另一个好问题。 好吧,最重要的约束是,您将来必须能够取回值对象。 否则,没有使用这种数据结构。 如果您了解`hashmap`的工作原理,将会发现它很大程度上取决于`Key`对象的`hashCode()``equals()`方法。
因此,好的键对象**必须一次又一次提供相同的 hashCode()**,无论它被获取了多少次。 同样,与 equals()方法比较时,相同的键**必须返回 true,而不同的键必须返回 false**
因此,好的键对象必须一次又一次提供相同的`hashCode()`,无论它被获取了多少次。 同样,与`equals()`方法比较时,相同的键必须返回`true`,而不同的键必须返回`false`
因此,**不变类被认为是 HashMap 键**的最佳候选者。
因此,**不变类被认为是`HashMap`键**的最佳候选者。
阅读更多: [**如何为 HashMap 设计一个好的键?**](//howtodoinjava.com/java/collections/how-to-design-a-good-key-for-hashmap/ "How to design a good key for HashMap")
阅读更多:[**如何为`HashMap`设计一个好的键?**](//howtodoinjava.com/java/collections/how-to-design-a-good-key-for-hashmap/ "How to design a good key for HashMap")
#### 16)Map 界面提供哪些不同的 Collection 视图?
#### 16)`Map`界面提供哪些不同的集合视图?
Map 界面提供了 3 个存储在其中的键值对的视图:
`Map`界面提供了 3 个存储在其中的键值对的视图:
* 键集视图
* 值集视图
*集视图
* 项集视图
可以使用迭代器浏览所有视图。
#### 17)什么时候使用 HashMap 或 TreeMap
#### 17)什么时候使用`HashMap`或`TreeMap`
HashMap 是众所周知的类,我们所有人都知道。 因此,我将离开这部分,说它用于存储键值对,并允许对这样的对集合执行许多操作。
`HashMap`是众所周知的类,我们所有人都知道。 因此,我将离开这部分,说它用于存储键值对,并允许对这样的对集合执行许多操作。
TreeMap 是 HashMap 的特殊形式。 **它维护 HashMap 类中缺少的键**的顺序。 默认情况下,此排序为**“自然排序”** 。 通过提供 Comparator 类的实例,可以覆盖默认顺序,该类的 compare 方法将用于维护键的顺序。
`TreeMap``HashMap`的特殊形式。 **它维护`HashMap`类中缺少的键的顺序**。 默认情况下,此排序为“自然排序”。 通过提供`Comparator`类的实例,可以覆盖默认顺序,该类的`compare`方法将用于维护键的顺序。
请注意,**所有插入映射的键都必须实现 Comparable 接口**(这是确定顺序的必要条件)。 此外,所有这些键必须相互可比较:k1.compareTo(k2)不得为映射中的任何键 k1 和 k2 抛出 ClassCastException。 如果用户尝试将键放入违反此约束的映射中(例如,用户尝试将字符串键放入其键为整数的映射中),则 put(Object key,Object value)调用将引发 ClassCastException
请注意,**所有插入映射的键都必须实现`Comparable`接口**(这是确定顺序的必要条件)。 此外,所有这些键必须相互可比较:`k1.compareTo(k2)`不得为映射中的任何键`k1``k2`抛出`ClassCastException`。 如果用户尝试将键放入违反此约束的映射中(例如,用户尝试将字符串键放入其键为整数的映射中),则`put(Object key, Object value)`调用将引发`ClassCastException`
## Java 集合面试 – 讲述差异问题
#### 18)Set 和 List 之间的区别?
#### 18)`Set`和`List`之间的区别?
最明显的区别是:
* Set 是无序集合,其中 List 是基于零索引的有序集合。
* 列表允许重复元素,但 Set 不允许重复。
* List 不会阻止插入空元素(随您喜欢),但是 Set 将只允许一个空元素。
* `Set`是无序集合,其中`List`是基于零索引的有序集合。
* 列表允许重复元素,但`Set`不允许重复。
* `List`不会阻止插入空元素(随您喜欢),但是`Set`将只允许一个空元素。
#### 19)列表和映射之间的区别?
也许是最简单的问题。 **列表是元素的集合,而 map 是键 - 值对**的集合。 实际上,有很多差异源自第一个陈述。 它们具有**单独的顶层接口,单独的一组通用方法,不同的受支持方法和不同的集合视图**
也许是最简单的问题。 **列表是元素的集合,而映射是键值对**的集合。 实际上,有很多差异源自第一个陈述。 它们具有**单独的顶层接口,单独的一组通用方法,不同的受支持方法和不同的集合视图**
我会花很多时间来回答这个问题,仅作为第一个区别就足够了。
#### 20)HashMap 和 HashTable 之间的区别?
#### 20)`HashMap`和`HashTable`之间的区别?
Java 中的 HashMap 和 Hashtable 之间有一些区别:
Java 中的`HashMap``Hashtable`之间有一些区别:
* Hashtable 是同步的,而 HashMap 不是同步的。
* 哈希表不允许使用空键或空值。 HashMap 允许一个空键和任意数量的空值。
* HashMap 与 Hashtable 之间的第三个重要区别是 HashMap 中的 Iterator 是快速失​​败的迭代器,而 Hashtable 的枚举器则不是。
* `Hashtable`是同步的,而`HashMap`不是同步的。
* 哈希表不允许使用空键或空值。 `HashMap`允许一个空键和任意数量的空值。
* `HashMap``Hashtable`之间的第三个重要区别是`HashMap`中的`Iterator`是快速失​​败的迭代器,而`Hashtable`的枚举器则不是。
#### 21)Vector 和 ArrayList 之间的区别?
#### 21)`Vector`和`ArrayList`之间的区别?
让我们记下差异:
* Vector 的所有方法都是同步的。 但是,ArrayList 的方法不同步。
* Vector 是在 JDK 的第一个版本中添加的旧类。 当在 Java 中引入集合框架时,ArrayList 是 JDK 1.2 的一部分。
* 默认情况下,Vector 在内部调整大小时会将其数组的大小加倍。 但是,重新调整大小时,ArrayList 的大小增加一半。
* `Vector`的所有方法都是同步的。 但是,`ArrayList`的方法不同步。
* `Vector`是在 JDK 的第一个版本中添加的旧类。 当在 Java 中引入集合框架时,`ArrayList`是 JDK 1.2 的一部分。
* 默认情况下,`Vector`在内部调整大小时会将其数组的大小加倍。 但是,重新调整大小时,`ArrayList`的大小增加一半。
#### 22)迭代器和枚举之间的区别?
#### 22)迭代器和枚举之间的区别?
迭代器与枚举在以下三个方面有所不同:
* 迭代器允许调用方使用其 remove()方法在迭代过程中从基础集合中删除元素。 使用枚举器时,不能从集合中添加/删除元素。
* 枚举在旧类(例如 Vector / Stack 等)中可用,而 Iterator 在所有现代集合类中可用。
* 另一个小的区别是 Iterator 改进了方法名称,例如 Enumeration.hasMoreElement()变为 Iterator.hasNext(),Enumeration.nextElement()变为 Iterator.next()等。
* 迭代器允许调用方使用其`remove()`方法在迭代过程中从基础集合中删除元素。 使用枚举器时,不能从集合中添加/删除元素。
* 枚举器在旧类(例如`Vector`/`Stack`等)中可用,而`Iterator`在所有现代集合类中可用。
* 另一个小的区别是`Iterator`改进了方法名称,例如`Enumeration.hasMoreElement()`变为`Iterator.hasNext()``Enumeration.nextElement()`变为`Iterator.next()`等。
#### 23)HashMap 和 HashSet 之间的区别?
#### 23)`HashMap`和`HashSet`之间的区别?
HashMap 是键值对的集合,而 HashSet 是唯一元素的无序集合。 而已。 无需进一步描述。
`HashMap`是键值对的集合,而`HashSet`是唯一元素的无序集合。 而已。 无需进一步描述。
#### 24)Iterator 和 ListIterator 之间的区别?
#### 24)`Iterator`和`ListIterator`之间的区别?
有三个区别:
* 我们可以使用 Iterator 遍历 Set 和 List 以及 Map 的 Object 类型。 但是列表迭代器可用于遍历列表类型的对象,但不能遍历对象的集合类型。
* 通过使用 Iterator,我们只能从正向检索 Collection 对象中的元素,而 List Iterator 则允许您使用 hasPrevious()和 previous()方法在任一方向上遍历。
* ListIterator 允许您使用 add()remove()方法修改列表。 使用 Iterator 不能添加,只能删除元素。
* 我们可以使用`Iterator`遍历`Set``List`以及`Map``Object`类型。 但是列表迭代器可用于遍历列表类型的对象,但不能遍历对象的集合类型。
* 通过使用`Iterator`,我们只能从正向检索`Collection`对象中的元素,而`List Iterator`则允许您使用`hasPrevious()``previous()`方法在任一方向上遍历。
* `ListIterator`允许您使用`add() remove()`方法修改列表。 使用`Iterator`不能添加,只能删除元素。
#### 25)TreeSet 和 SortedSet 之间的区别?
#### 25)`TreeSet`和`SortedSet`之间的区别?
SortedSet 是 TreeSet 实现的接口。 就是这样!
`SortedSet``TreeSet`实现的接口。 就是这样!
#### 26)ArrayList 和 LinkedList 之间的区别?
#### 26)`ArrayList`和`LinkedList`之间的区别?
* LinkedList 将元素存储在双链列表数据结构中。 ArrayList 将元素存储在动态调整大小的数组中。
* LinkedList 允许进行固定时间的插入或删除,但只允许顺序访问元素。 换句话说,您可以向前或向后浏览列表,但是在中间抓取一个元素所花费的时间与列表的大小成正比。 另一方面,ArrayList 允许随机访问,因此您可以在固定时间内抓取任何元素。 但是,从末端开始的任何地方添加或删除,都需要将后面的所有元素移开,以形成开口或填补空白。
* LinkedList 比 ArrayList 具有更多的内存开销,因为在 ArrayList 中,每个索引仅保存实际的对象(数据),但是在 LinkedList 的情况下,每个节点都保存下一个和上一个节点的数据以及地址。
* `LinkedList`将元素存储在双链列表数据结构中。 `ArrayList`将元素存储在动态调整大小的数组中。
* `LinkedList`允许进行固定时间的插入或删除,但只允许顺序访问元素。 换句话说,您可以向前或向后浏览列表,但是在中间抓取一个元素所花费的时间与列表的大小成正比。 另一方面,`ArrayList`允许随机访问,因此您可以在固定时间内抓取任何元素。 但是,从末端开始的任何地方添加或删除,都需要将后面的所有元素移开,以形成开口或填补空白。
* `LinkedList``ArrayList`具有更多的内存开销,因为在`ArrayList`中,每个索引仅保存实际的对象(数据),但是在`LinkedList`的情况下,每个节点都保存下一个和上一个节点的数据以及地址。
## 更多面试面试问题
#### 27)如何使收藏集只读?
#### 27)如何使集合只读?
使用以下方法:
* Collections.unmodifiableList(list);
* Collections.unmodifiableSet(set);
* Collections.unmodifiableMap(map);
* `Collections.unmodifiableList(list);`
* `Collections.unmodifiableSet(set);`
* `Collections.unmodifiableMap(map);`
这些方法采用 collection 参数,并返回一个具有与原始 collection 中相同的元素的新的只读 collection
这些方法采用集合参数,并返回一个具有与原始集合中相同的元素的新的只读集合
#### 28)如何使集合线程安全?
使用以下方法:
* Collections.synchronizedList(list);
* Collections.synchronizedSet(set);
* Collections.synchronizedMap(map);
* `Collections.synchronizedList(list);`
* `Collections.synchronizedSet(set);`
* `Collections.synchronizedMap(map);`
上面的方法将 collection 作为参数并返回相同类型的 collection,这些类型是同步的且线程安全的。
上面的方法将集合作为参数并返回相同类型的集合,这些类型是同步的且线程安全的。
#### 29)为什么没有像 Iterator.add()这样的方法将元素添加到集合中?
#### 29)为什么没有像`Iterator.add()`这样的方法将元素添加到集合中?
迭代器的唯一目的是通过集合进行枚举。 所有集合都包含 add()方法以实现您的目的。 添加[Iterator]毫无意义,因为**集合可能有序,也可能没有排序。 而且 **add()方法对于有序和无序集合**不能具有相同的实现。**
迭代器的唯一目的是通过集合进行枚举。 所有集合都包含`add()`方法以实现您的目的。 添加`Iterator`毫无意义,因为**集合可能有序,也可能没有排序**。 而且`add()`方法对于有序和无序集合不能具有相同的实现。
#### 30)有哪些不同的方法可以遍历列表?
您可以使用以下方式遍历列表:
* 迭代器循环
* 对于循环
* 对于循环(高级)
* While 循环
* `for`循环
* `for`循环(高级)
* `While`循环
阅读更多: [http://www.mkyong.com/java/how-do-loop-iterate-a-list-in-java/](http://www.mkyong.com/java/how-do-loop-iterate-a-list-in-java/)
#### 31)通过迭代器快速失败属性您了解什么?
**失败快速迭代器一旦意识到自迭代开始以来就已更改 Collection 的结构,便会失败**。 结构更改意味着在一个线程迭代该集合时,从集合中添加,删除或更新任何元素。
**快速失败迭代器一旦意识到自迭代开始以来就已更改集合的结构,便会失败**。 结构更改意味着在一个线程迭代该集合时,从集合中添加,删除或更新任何元素。
通过保留修改计数来实现快速失败行为,如果迭代线程实现了修改计数的更改,则会引发 ConcurrentModificationException
通过保留修改计数来实现快速失败行为,如果迭代线程实现了修改计数的更改,则会引发`ConcurrentModificationException`
#### 32)快速故障和故障安全之间有什么区别?
#### 32)快速失败和故障安全之间有什么区别?
您已经在上一个问题中理解了快速失败。 **故障安全迭代器**与快速故障相反。 **如果您修改要在其上进行迭代的基础集合**,它们将永远不会失败,因为它们在 Collection 的克隆而不是原始集合上起作用,这就是为什么将它们称为故障保护迭代器。
您已经在上一个问题中理解了快速失败。 **故障安全迭代器**与快速失败相反。 **如果您修改要在其上进行迭代的基础集合**,它们将永远不会失败,因为它们在集合的克隆而不是原始集合上起作用,这就是为什么将它们称为故障保护迭代器。
CopyOnWriteArrayList 的迭代器是故障安全迭代器的示例,而且 ConcurrentHashMap keySet 编写的迭代器也是故障安全迭代器,并且永远不会抛出 ConcurrentModificationException
`CopyOnWriteArrayList`的迭代器是故障安全迭代器的示例,而且`ConcurrentHashMap keySet`编写的迭代器也是故障安全迭代器,并且永远不会抛出`ConcurrentModificationException`
#### 33)如何在迭代集合时避免 ConcurrentModificationException
#### 33)如何在迭代集合时避免`ConcurrentModificationException`
您应该首先尝试**查找故障安全**的另一个替代迭代器。 例如,如果您正在使用 List,则可以使用 ListIterator。 如果它是旧式集合,则可以使用枚举。
您应该首先尝试**查找故障安全**的另一个替代迭代器。 例如,如果您正在使用`List`,则可以使用`ListIterator`。 如果它是旧式集合,则可以使用枚举。
如果上述选项不可行,则可以使用以下三种更改之一:
* 如果使用的是 JDK1.5 或更高版本,则可以使用 ConcurrentHashMap 和 CopyOnWriteArrayList 类。 这是推荐的方法。
* 如果使用的是 JDK1.5 或更高版本,则可以使用`ConcurrentHashMap``CopyOnWriteArrayList`类。 这是推荐的方法。
* 您可以将列表转换为数组,然后在数组上进行迭代。
* 您可以通过将列表放在同步块中来在迭代时锁定列表。
请注意,最后两种方法会导致性能下降。
#### 34)什么是 UnsupportedOperationException
#### 34)什么是`UnsupportedOperationException`
实际的集合类型不支持的被调用方法抛出**异常。**
实际的集合类型不支持的被调用方法抛出**异常**
例如,如果您使用“ Collections.unmodifiableList(list)”创建一个只读列表列表,然后调用 add()或 remove()方法,那将会发生什么。 它应该明确抛出 UnsupportedOperationException
例如,如果您使用“`Collections.unmodifiableList(list)`”创建一个只读列表列表,然后调用`add()``remove()`方法,那将会发生什么。 它应该明确抛出`UnsupportedOperationException`
#### 35)哪些集合类可随机访问其元素?
ArrayList,HashMap,TreeMap,Hashtable 类提供对其元素的随机访问。
`ArrayList``HashMap``TreeMap``Hashtable`类提供对其元素的随机访问。
#### 36)什么是 BlockingQueue
#### 36)什么是`BlockingQueue`
**一个队列,它另外支持以下操作:在检索元素时等待队列变为非空,并在存储元素时等待队列中的空间变为可用。**
BlockingQueue 方法有四种形式:一种抛出异常,第二种返回一个特殊值(根据操作的不同,返回 null 或 false),第三种无限期地阻塞当前线程,直到操作成功为止;第四种仅针对 a 在放弃之前给出最大时间限制。
`BlockingQueue`方法有四种形式:一种抛出异常,第二种返回一个特殊值(根据操作的不同,返回`null``false`),第三种无限期地阻塞当前线程,直到操作成功为止;第四种仅在放弃之前给出最大时间限制。
阅读 post 中的阻塞队列示例用法: [**如何使用阻塞队列?**](//howtodoinjava.com/java-5/how-to-use-blockingqueue-and-threadpoolexecutor-in-java/ "How to use BlockingQueue and ThreadPoolExecutor in java")
阅读文章中的阻塞队列示例用法: [**如何使用阻塞队列?**](//howtodoinjava.com/java-5/how-to-use-blockingqueue-and-threadpoolexecutor-in-java/ "How to use BlockingQueue and ThreadPoolExecutor in java")
#### 37)什么是队列和栈,列出它们之间的差异?
**设计用于在处理之前保存元素的集合。** 除了基本的 Collection 操作之外,队列还提供其他插入,提取和检查操作。
**设计用于在处理之前保存元素的集合。** 除了基本的集合操作之外,队列还提供其他插入,提取和检查操作。
**通常但不一定以 FIFO(先进先出)的方式对元素进行排序。**
**栈也是队列的一种形式,但有一个区别,那就是 LIFO(后进先出)。**
无论使用哪种顺序,队列的开头都是该元素,可以通过调用 remove()或 poll()将其删除。 另请注意,栈和向量都已同步。
无论使用哪种顺序,队列的开头都是该元素,可以通过调用`remove()``poll()`将其删除。 另请注意,栈和向量都已同步。
**用法:**如果要按接收顺序处理传入流,请使用队列。适用于工作列表和处理请求。
**用法**如果要按接收顺序处理传入流,请使用队列。适用于工作列表和处理请求。
如果只想从栈顶部推动并弹出,请使用栈。 适用于递归算法。
#### 38)什么是可比较和比较器界面
#### 38)什么是`Comparable`和`Comparator`接口
在 Java 中。 所有具有自动排序功能的集合都使用比较方法来确保元素的正确排序。 例如,使用排序的类为 TreeSet,TreeMap 等。
在 Java 中。 所有具有自动排序功能的集合都使用比较方法来确保元素的正确排序。 例如,使用排序的类为`TreeSet``TreeMap`等。
**为了对一个类需要实现 Comparator 或 Comparable 接口**的数据元素进行排序。 这就是所有 Wrapper 类(例如 Integer,Double 和 String 类)都实现 Comparable 接口的原因。
**为了对一个类的数据元素进行排序,需要实现`Comparator`或`Comparable`接口**。 这就是所有包装器类(例如`Integer``Double``String`类)都实现`Comparable`接口的原因。
**Comparable 帮助保留默认的自然排序,而 Comparator 帮助以某些特殊的必需排序模式对元素进行排序。** 比较器的实例,通常在支持集合时作为集合的构造器参数传递。
**`Comparable`帮助保留默认的自然排序,而`Comparator`帮助以某些特殊的必需排序模式对元素进行排序。** 比较器的实例,通常在支持集合时作为集合的构造器参数传递。
#### 39)什么是 Collections 和 Arrays 类?
#### 39)什么是`Collections`和`Arrays`类?
**Collections 和 Arrays 类是支持集合框架核心类的特殊工具类。** 它们提供工具功能以获取只读/同步集合,以各种方式对集合进行排序等。
**`Collections`和`Arrays`类是支持集合框架核心类的特殊工具类。** 它们提供工具功能以获取只读/同步集合,以各种方式对集合进行排序等。
数组还帮助对象数组转换为集合对象。 数组还具有一些功能,有助于复制或处理部分数组对象。
......
......@@ -57,7 +57,7 @@ private transient String emailAddress;
#### 2.2 其他修饰符
通过使用`GsonBuilder``excludeFieldsWithModifiers()`方法,我们可以排除具有某些公修饰符的字段。
通过使用`GsonBuilder``excludeFieldsWithModifiers()`方法,我们可以排除具有某些公修饰符的字段。
例如,我们要排除一个类的所有`static`成员,我们可以这样创建 Gson 对象:
......
......@@ -52,7 +52,7 @@ public class Employee implements Serializable
* `FIELD` – 绑定到 JAXB 的类中的每个非静态,非瞬态字段都将自动绑定到 XML,除非由`XmlTransient`注释。
* `NONE` – 没有任何字段或属性绑定到 XML,除非使用某些 JAXB 注释专门对其进行注释。
* `PROPERTY` – 绑定到 JAXB 的类中的每个获取器/设置器对将自动绑定到 XML,除非由`XmlTransient`注释。
* `PUBLIC_MEMBER` – 每个公共获取/设置对和每个公共字段都将自动绑定到 XML,除非由`XmlTransient`注释。
* `PUBLIC_MEMBER` – 每个公开获取/设置对和每个公开字段都将自动绑定到 XML,除非由`XmlTransient`注释。
* 默认值为`PUBLIC_MEMBER`
```java
......
......@@ -28,7 +28,7 @@
## 2)映射模型类
我创建了一个模型类“`Employee.java`”,它具有一些公字段。 我想构建可以解析对象映射的代码,其中键是序列码,值是`Employee`对象本身。
我创建了一个模型类“`Employee.java`”,它具有一些公字段。 我想构建可以解析对象映射的代码,其中键是序列码,值是`Employee`对象本身。
```java
@XmlRootElement(name = "employee")
......
......@@ -28,7 +28,7 @@
## 2)模型类
我创建了一个模型类“`Employee`”,它具有一些公字段。 我想构建可以解析一组`employees`的代码。 请注意,JAXB 在最重要的类上需要 [`@XmlRootElement`](https://docs.oracle.com/javaee/5/api/javax/xml/bind/annotation/XmlRootElement.html "XmlRootElement") 注解,我们将对其进行编组或解组。
我创建了一个模型类“`Employee`”,它具有一些公字段。 我想构建可以解析一组`employees`的代码。 请注意,JAXB 在最重要的类上需要 [`@XmlRootElement`](https://docs.oracle.com/javaee/5/api/javax/xml/bind/annotation/XmlRootElement.html "XmlRootElement") 注解,我们将对其进行编组或解组。
`ArrayList`类是集合框架的一部分,它没有任何 JAXB 注解。 因此,我们需要另外一个类别“`Employees`”,该类别将代表一组雇员。 现在,在该类中,我们可以添加任何我们喜欢的注释。
......
......@@ -58,13 +58,13 @@ Class has two properties of the same name "employeeMap"
发生上述异常的主要原因是缺少`@XmlAccessType`注解或对`@XmlAccessType``@XxmlElement`注解的无效使用。 正确的用法是,一个 Java 字段应只包含一个表示其元数据的有效 JAXB 注解。
默认情况下,JAXB 包含所有公字段和用于整理的获取器。 因此,如果您有一个字段及其获取器,那么它将包含两次。 这是错误,需要通过正确使用注释来解决。
默认情况下,JAXB 包含所有公字段和用于整理的获取器。 因此,如果您有一个字段及其获取器,那么它将包含两次。 这是错误,需要通过正确使用注释来解决。
## 解决方案:使用`@XmlAccessType`注解
**1)`@XmlAccessorType(XmlAccessType.FIELD)`**
如果您使用的是`XmlAccessType.FIELD;`那么只有所有公共领域(非静态)将被自动包括在内以进行编组。 不会考虑吸气剂。 因此,如果将消除重复的问题。 例如,在下面的代码中,将同时包含`employee``size`字段。
如果您使用的是`XmlAccessType.FIELD;`那么只有所有公开字段(非静态)将被自动包括在内以进行编组。 不会考虑吸气剂。 因此,如果将消除重复的问题。 例如,在下面的代码中,将同时包含`employee``size`字段。
请注意,“`@XmlElement(name="employee")`”是可选的; 我用它来重命名输出 xml 中的 xml 节点。 如果删除它; 不会出现任何编组错误或异常。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册