提交 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. 在这个时间设置一个新值。
例如:
......
此差异已折叠。
此差异已折叠。
......@@ -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.
先完成此消息的编辑!
想要评论请 注册