Java核心面试问题 之 第1部分

您打算学习核心Java吗?还是计划在未来几天进行采访?不用担心,请阅读下面给出的所有面试问题,以刷新您的概念,并可能在最佳Java列表中添加一些新内容。

面试问题清单

如何在Java中创建不可变对象?算上所有好处?
Java是按引用传递还是按值传递?
finally块的用途是什么?Java中的finally块是否可以保证被调用?最终何时不调用块?
为什么有两个Date类;为什么?一个在java.util包中,另一个在java.sql中?
什么是标记界面?
为什么Java中的main()被声明为public static void main?
将String创建为new()和文字之间有什么区别?
String中的substring()如何工作?
解释HashMap的工作。
接口和抽象类之间的区别?
什么时候覆盖hashCode和equals()?

如何在Java中创建不可变对象?算上所有好处?

不变类是一种一旦创建便无法更改其状态的类。在这里,对象状态本质上是指存储在类的实例变量中的值,无论它们是原始类型还是引用类型。

要使类不可变,需要遵循以下步骤:

  1. 不要提供“设置”方法或修改字段或字段引用的对象的方法。Setter方法旨在更改对象的状态,这是我们在此要避免的。
  2. 使所有字段finalprivate。声明的字段private在类外部无法访问,并且使它们final确保即使您不小心也无法更改它们。
  3. 不允许子类覆盖方法。最简单的方法是将该类声明为final。Java中的最终类不能被覆盖。
  4. 永远记住,您的实例变量将是可变的或不可变的。标识它们并返回具有所有可变对象(对象引用)复制内容的新对象。不变的变量(原始类型)可以安全地返回,而无需付出额外的努力。

另外,您应该记住不变类的以下好处。面试期间您可能需要它们。不变的类–

  • 易于构建,测试和使用
  • 自动是线程安全的,并且没有同步问题
  • 不需要复制构造函数
  • 不需要克隆的实现
  • 允许hashCode使用延迟初始化,并缓存其返回值
  • 用作字段时不需要防御性地复制
  • 制作好Map键和Set元素(这些对象在集合中时不得更改状态)
  • 在构造时就建立了其类不变式,因此无需再次检查
  • 总是具有“ 失败原子性 ”(约书亚·布洛赫(Joshua Bloch)使用的一个术语):如果不可变对象引发异常,则它永远不会处于不良状态或不确定状态。

看看写的一个例子这篇文章

Java是按引用传递还是按值传递?

Java Spec指出Java中的所有内容都是传递值。Java中没有“ 通过引用传递 ”这样的东西。这些术语与方法调用关联,并将变量作为方法参数传递。好吧,原始类型总是按值传递而不会造成任何混淆。但是,应该在复杂类型的方法参数的上下文中理解该概念。

在Java中,当我们将复杂类型的引用作为任何方法参数传递时,总是将内存地址一点一点地复制到新的引用变量中。见下图:

价值传递

在上面的示例中,第一个实例的地址位被复制到另一个引用变量,因此导致两个引用都指向存储实际对象的单个存储位置。请记住,再次引用null不会使第一次引用也为null。但是,从任一参考变量更改状态也会对其他参考产生影响。

在此处详细阅读:Java通过值传递还是引用传递?

finally块的用途是什么?是否可以保证Java中的finally块被调用?最终何时不调用块?

finally块始终在try退出时执行。这样可以确保finally即使发生意外异常也可以执行该块。但是,finally是的不仅仅是异常处理更加有用-它允许不慎被绕过具有清除代码returncontinuebreakfinally即使在没有例外的情况下,将清除代码放在块中始终是一个好习惯。

如果在执行trycatch代码时JVM退出,则该finally块可能不会执行。同样,如果执行trycatch代码的线程被中断或杀死,则finally即使整个应用程序继续运行,该块也可能不会执行。

为什么有两个Date类;为什么?一个在java.util包中,另一个在java.sql中?

java.util.Date代表日期和时间,a java.sql.Date代表日期。的补码java.sql.Datejava.sql.Time,仅代表一天中的某个时间。
java.sql.Date是的一个子类(扩展)java.util.Date。因此,发生了什么变化java.sql.Date

– toString()生成不同的字符串表示形式:yyyy-mm-dd
– static valueOf(String)从具有上述表示形式的字符串中创建日期的方法
–不建议使用小时,分钟和秒的getter和setter方法

java.sql.Date类使用JDBC和它的目的是没有时间的一部分,也就是说,小时,分钟,秒和毫秒应该是零……但这不是由类执行。

解释标记界面?

标记器界面模式是计算机科学中的一种设计模式,与提供有关对象的运行时类型信息的语言一起使用。它提供了一种将元数据与一个类相关联的方法,其中该语言对该类元数据没有明确的支持。在Java中,它用作未指定方法的接口。

在Java中使用标记接口的一个很好的例子是Serializable接口。类实现此接口,以指示可以将其非临时数据成员写入字节 Stream 或文件系统。

主要问题与标志接口是一个接口定义用于实现类约定,并且该约定是由所有子类继承。这意味着您不能“取消实施”标记。在给定的示例中,如果创建不想序列化的子类(也许因为它依赖于瞬态),则必须诉诸显式抛出NotSerializableException。

为什么Java中的main()被声明为public static void?

为什么公开main方法是public使它可以在任何地方访问,并且对于可能希望使用它启动应用程序的每个对象都可以访问。在这里,我并不是说JDK / JRE具有类似的原因,因为java.exe或javaw.exe(用于Windows)使用Java本机接口(JNI)调用来调用方法,因此,无论使用哪种访问修饰符,他们都可以通过任何一种方式来调用它。 。

为什么是静态的假设我们没有main方法static。现在,要调用任何方法,您需要它的一个实例。对?众所周知,Java可以有重载的构造函数。现在,应该使用哪一个,重载的构造函数的参数从何而来。

为什么作废这样就没有任何将值返回给实际调用此方法的JVM的用途。应用程序唯一想与调用过程进行通信的是:正常终止或异常终止。使用已经可以做到System.exit(int)。非零值表示异常终止,否则一切正常。

将String创建为new()和文字之间有什么区别?

当我们String使用new()它创建时,它在堆中创建并添加到字符串池中,而String使用文字创建时,则仅在存在于堆的Perm区域中的字符串池中创建。

那么,您真的需要非常深入地了解字符串池的概念,才能回答此问题或类似问题。我的建议..关于字符串类和字符串池的 “努力学习” 。

String中的substring()如何工作?

StringJava中的语言与任何其他编程语言一样,都是字符序列。这更像是用于该char序列的实用程序类。此char序列在以下变量中维护:

/** 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;

/** The count is the number of characters in the String。 */
private final int count;

每当我们从任何现有的字符串实例创建子字符串时,substring()方法都只会设置offsetcount变量的新值。内部char数组不变。如果substring()不加注意地使用方法,则可能是内存泄漏的根源。在这里阅读更多

解释HashMap的工作。如何解决重复冲突?

你们大多数人都会同意,HashMap是当今访谈中最喜欢讨论的话题。如果有人要我描述“ HashMap如何工作?”,我只是回答:“ 关于散列原理 ”。就这么简单。

现在,以最简单的形式进行哈希处理是一种在对属性应用任何公式/算法之后为任何变量/对象分配唯一代码的方法。

根据定义,映射为:“将键映射为值的对象”。很容易..对吗?因此,HashMap有一个内部类Entry,它看起来像这样:

static class Entry<k ,V> implements Map.Entry<k ,V>
{
final K key;
V value;
Entry<k ,V> next;
final int hash;
...//More code goes here
}

当某人尝试在中存储键值对时HashMap,会发生以下情况:

  • 首先,检查键对象是否为空。如果key为null,则值存储在table [0]位置。因为null的哈希码始终为0。
  • 然后在下一步中,通过调用键的哈希码,使用键的哈希码计算哈希值hashCode()。该哈希值用于计算数组中用于存储Entry对象的索引。JDK设计人员很好地假设可能有一些编写不佳的hashCode()函数可以返回非常高或很低的哈希码值。为了解决此问题,他们引入了另一个hash()函数,并将对象的哈希码传递给该hash()函数,以将哈希值带入数组索引大小的范围内。
  • 现在indexFor(hash, table.length)调用函数以计算用于存储Entry对象的确切索引位置。
  • 这是主要部分。现在,我们知道两个不相等的对象可以具有相同的哈希码值,如何将两个不同的对象存储在相同的数组位置(称为存储桶)中。答案是LinkedList。如果您还记得,Entryclass的属性为“ next”。此属性始终指向链中的下一个对象。这正是的行为LinkedList。因此,在发生碰撞的情况下,Entry对象以LinkedList表格形式存储。当一个Entry对象需要存储在特定的索引中时,HashMap检查是否已经有一个条目?如果尚无条目,则将Entry对象存储在此位置。如果已经有一个对象位于计算索引上,next则检查其属性。如果为null,则当前Entry对象成为中的next节点LinkedList。如果next变量不为空,则遵循过程直到其next被评估为空。

    如果我们添加另一个具有与之前输入相同的键的值对象该怎么办。从逻辑上讲,它应该替换旧值。怎么做的?好了,确定对象的index位置之后Entry,在迭代LinkedList计算的索引的同时,为每个对象HashMap调用equals()键对象上的方法Entry。所有这些Entry对象都LinkedList将具有相似的哈希码,但是equals()方法将测试真实相等性。如果key.equals(k)为true,则两个键都被视为相同的键对象。这将导致仅在对象内部替换值对象Entry

这样,可以HashMap确保密钥的唯一性。

接口和抽象类之间的区别?

如果您正在面试初级程序员,这是一个非常常见的问题。好吧,最明显的区别如下:

  • 默认情况下,在Java接口中声明的变量是final。抽象类可能包含非最终变量。
  • Java接口是隐式的abstract,不能具有实现。Java抽象类可以具有实现默认行为的实例方法。
  • 默认情况下,Java接口的成员是公共的。Java抽象类可以具有类成员的常规风格,例如privateabstract等等。
  • Java接口应使用关键字“ Implements ” 来实现;Java抽象类应使用关键字“ extends ” 进行扩展。
  • Java类可以实现多个接口,但只能扩展一个抽象类。
  • 接口是 绝对抽象和无法实例化;Java抽象类也无法实例化,但是可以在存在main()的情况下调用。从Java 8开始,您可以在interfaces中定义默认方法
  • 抽象类比接口要快一些,因为接口涉及在Java中调用任何重写方法之前进行的搜索。在大多数情况下,这并不是显着的差异,但是如果您正在编写时间紧迫的应用程序,那么您可能不想无所事事。

什么时候覆盖hashCode()和equals()?

hashCode()equals()方法已在Objectclass中定义,该类是java对象的父类。因此,所有java对象都继承这些方法的默认实现。

hashCode()方法用于获取给定对象的唯一整数。当此对象需要以某种HashTable类似的数据结构存储时,该整数用于确定存储桶位置。默认情况下,对象的hashCode()方法返回存储对象的内存地址的整数表示形式。
equals()顾名思义,该方法用于简单地验证两个对象的相等性。默认实现只是检查两个对象的对象引用以验证它们的相等性。

请注意,通常有必要在重写此方法时重写hashCode方法,以维护该hashCode()方法的常规协定,该协定规定相等的对象必须具有相等的哈希码。

  • equals()必须定义一个相等关系(必须是自反的,对称的和可传递的)。另外,它必须是一致的(如果未修改对象,则它必须保持返回相同的值)。此外,o.equals(null)必须始终返回false
  • hashCode()还必须保持一致(如果未根据修改对象equals(),则必须保持返回相同的值)。

两种方法之间的关系为:

a.equals(b)那么无论何时都a.hashCode()必须与相同b.hashCode()

saigon has written 1445 articles

2 thoughts on “Java核心面试问题 之 第1部分

Leave a Reply