首页 > 编程语言 >HowToDoInJava-其它教程-2-二-

HowToDoInJava-其它教程-2-二-

时间:2024-10-24 18:11:40浏览次数:8  
标签:xml 教程 其它 Java String HowToDoInJava import com public

HowToDoInJava 其它教程 2(二)

原文:HowToDoInJava

协议:CC BY-NC-SA 4.0

Java 核心面试问题 – 第 2 部分

原文: https://howtodoinjava.com/interview-questions/core-java-interview-questions-series-part-2/

Java 面试问题系列:第 1 部分中,我们讨论了面试官通常问的一些重要问题。 现在是推进该讨论的时候了。 在这篇文章中,我将在下面给出的问题列表中进行讨论。

Why finalize() method should be avoided?
Why HashMap should not be used in multithreaded environment? Can it cause infinite loop as well?
Explain abstraction and encapsulation? How are they related?
Difference between interfaces and abstract classes?
How StringBuffer save the memory?
Why wait and notify is declared in Object class instead of Thread ?
Write Java program to create deadlock in Java and fix it ?
What happens if your Serializable class contains a member which is not  serializable? How do you fix it?
Explain transient and volatile keywords in java?
Difference between Iterator and ListIterator?

为什么要避免使用finalize()方法?

我们都知道,在回收分配给对象的内存之前,垃圾收集器线程会调用finalize()方法的基本声明。 请参阅这篇文章,证明根本不能保证finalize()调用。 其他原因可能是:

  1. finalize()方法无法像构造器一样在链接中工作。 这意味着就像您调用构造器时一样,所有超类的构造器都将被隐式调用。 但是,在使用finalize方法的情况下,则不遵循此方法。 超类的finalize()应该显式调用。

  2. finalize方法引发的任何异常都将被 GC 线程忽略,并且不会进一步传播,实际上不会记录在日志文件中。 真糟糕,不是吗?

  3. 另外,当您的类中包含finalize()时,也会影响性能。 Joshua bloch 在《Effective Java》(第 2 版)中说,

    “哦,还有一件事:使用终结器会严重影响性能。 在我的机器上,创建和销毁简单对象的时间约为 5.6 ns。 添加终结器会将时间增加到 2,400 ns。 换句话说,使用终结器创建和销毁对象要慢 430 倍。”

为什么不应该在多线程环境中使用HashMap? 它也会引起无限循环吗?

我们知道HashMap是非同步集合,因为它的同步计数器是HashTable。 因此,当您在多线程环境中访问集合时,所有线程都在访问集合的单个实例时,出于各种明显的原因,例如HashTable,使用HashTable更安全。 以避免脏读并保持数据一致性。 在最坏的情况下,这种多线程环境也可能导致无限循环。

是的,它是真实的。 HashMap.get()可能导致无限循环。 让我们看看如何?

如果查看HashMap.get(Object key)方法的源代码,则如下所示:

public Object get(Object key) {
    Object k = maskNull(key);
    int hash = hash(k);
    int i = indexFor(hash, table.length);
    Entry e = table[i];
    while (true) {
        if (e == null)
            return e;
        if (e.hash == hash && eq(k, e.key))
            return e.value;
        e = e.next;
    }
}

在多线程环境中,while(true){...}始终是运行时无限循环的受害者,因此e.next可以指向自身。 这将导致无限循环。 但是,e.next将如何指向自身(即)。

这可能在void transfer(Entry[] newTable)方法中发生,该方法在HashMap调整大小时调用。

do {
    Entry next = e.next;
    int i = indexFor(e.hash, newCapacity);
    e.next = newTable[i];
    newTable[i] = e;
    e = next;
} while (e != null);

如果调整大小并且同时其他线程试图修改映射实例,则这段代码很容易产生上述条件。

避免这种情况的唯一方法是在代码中使用同步,或者更好的方法是使用同步集合。

解释抽象和封装? 它们有什么关系?

抽象

抽象仅捕获与当前视角有关的那些对象的详细信息。

面向对象编程理论中,抽象涉及定义定义代表抽象“角色”的对象的功能,这些抽象“角色”可以执行工作,报告和更改其状态,并与系统中的其他对象“通信”。

任何编程语言中的抽象都可以通过多种方式工作。 从创建子例程到定义用于进行低级语言调用的接口可以看出。 一些抽象试图通过完全隐藏它们依次建立在其上的抽象,来限制程序员所需概念的广度。 例如设计模式。

通常,可以通过两种方式查看抽象:

数据抽象是创建复杂数据类型并仅公开有意义的操作以与数据类型进行交互的方法,其中隐藏了外部工作中的所有实现细节。

控制抽象是识别所有此类语句并将其作为工作单元公开的过程。 我们通常在创建函数来执行任何工作时使用此功能。

封装

将类中的数据和方法与实现隐藏(通过访问控制)结合起来通常称为封装。 结果是具有特征和行为的数据类型。 封装本质上既具有信息隐藏又具有实现隐藏。

无论进行任何更改,都封装它”。 它被引用为著名的设计原则。 因此,在任何类中,运行时中的数据都可能发生更改,将来的发行版中可能会更改实现。 因此,封装既适用于数据也适用于实现。

因此,它们可以像下面这样关联:

  • 抽象更多是关于“类可以做什么”。(想法)
  • 封装更多地是关于“如何”实现该功能。(实现)

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

接口和抽象类之间的基本区别可以算作如下:

  • 接口不能有任何方法,而抽象类可以(在 Java8 默认方法之后不正确)
  • 一个类可以实现许多接口,但只能有一个超类(是否抽象)
  • 接口不属于类层次结构。 不相关的类可以实现相同的接口

您应该记住:“当您可以用做什么充分描述该概念时,而无需指定任何它是如何工作的,那么您应该使用一个接口。 如果您需要包括一些实现细节,那么您将需要在抽象类中表示您的概念。”

另外,如果我说的不同:是否可以将许多分组在一起并用一个名词描述的类? 如果是这样,请以该名词的名称创建一个抽象类,并从其继承这些类。 例如,CatDog都可以从抽象类Animal继承,并且此抽象基类将实现方法void breathe(),所有动物都将以完全相同的方式执行该方法。

什么样的动词可以应用于我的类,通常也可以应用于其他动词? 为每个动词创建一个接口。 例如,所有动物都可以喂食,因此我将创建一个名为IFeedable的接口,并让Animal实现该接口。 尽管DogHorse足以实现ILikeable,但有些还不够。

正如某人所说:主要区别在于您想要实现的地方。 通过创建接口,可以将实现移动到实现接口的任何类。 通过创建一个抽象类,您可以在一个中央位置共享所有派生类的实现,并且避免了很多不好的事情,例如代码重复。

StringBuffer如何节省内存?

字符串被实现为不变对象; 也就是说,当您最初决定将某些内容放入String对象时,JVM 会分配一个与初始值大小正好相等的固定宽度数组。 然后将其视为 JVM 内部的常量,在不更改String值的情况下,可以大大节省性能。 但是,如果您决定以任何方式更改String的内容,那么 JVM 实质上要做的就是将原始String的内容复制到一个临时空间中,进行更改,然后将这些更改保存到一个全新的内存阵列中。 因此,在初始化后更改String的值是一项相当昂贵的操作。

StringBuffer在 JVM 内部被实现为可动态增长的数组,这意味着任何更改操作都可以在现有内存位置上进行,而新内存仅按需分配。 但是,JVM 没有机会围绕StringBuffer进行优化,因为假定其内容在任何情况下都是可更改的。

为什么在对象类而不是线程中声明了waitnotify

waitnotifynotifyAll方法仅在您希望线程访问共享资源并且共享资源可以是堆上的任何 Java 对象时才需要。 因此,这些方法是在核心Object类上定义的,因此每个对象都可以控制允许线程在其监视器上等待。 Java 没有用于共享公共资源的任何特殊对象。 没有定义这样的数据结构。因此,在Object类上有责任成为共享资源,条件是它可以使用wait()notify()notifyAll()之类的辅助方法。

Java 基于 Hoare 的监视器概念。 在 Java 中,所有对象都有一个监视器。 线程在监视器上等待,因此要执行等待,我们需要 2 个参数:

– 线程
– 监视器(任何对象)

在 Java 设计中,无法指定线程,它始终是当前运行代码的线程。 但是,我们可以指定监视器(这是我们称为wait的对象)。 这是一个很好的设计,因为如果我们可以让任何其他线程在所需的监视器上等待,则会导致“入侵”,给设计/编程并发程序带来了困难。 请记住,在 Java 中,不推荐使用会干扰另一个线程执行的所有操作(例如stop())。

编写 Java 程序以在 Java 中创建死锁并修复死锁?

在 Java 中,死锁是指至少有两个线程在某个不同的资源上持有锁,并且都在等待其他资源来完成其任务的情况。 而且,没有人能够锁定它所拥有的资源。

阅读更多:编写死锁并使用 Java 解决

如果您的Serializable类包含一个不可序列化的成员,该怎么办? 您如何解决?

在这种情况下,将在运行时引发NotSerializableException。 要解决此问题,一个非常简单的解决方案是将此类字段标记为瞬态。 这意味着这些字段将不会被序列化。 如果还要保存这些字段的状态,则应考虑已经实现Serializable接口的引用变量。

您可能还需要使用readResolve()writeResolve()方法。 让我们总结一下:

  • 首先,设置您的不可序列化字段transient
  • writeObject()中,首先在流上调用defaultWriteObject()来存储所有非瞬态字段,然后调用其他方法来序列化不可序列化对象的各个属性。
  • readObject()中,首先在流上调用defaultReadObject()以读回所有非瞬态字段,然后调用其他方法(与您添加到writeObject的方法相对应)来反序列化不可序列化的对象。

另外,我强烈建议阅读关于 Java 中序列化的完整指南。

解释 Java 中的transientvolatile关键字?

transient

Java 中的transient关键字用于指示不应序列化字段。”根据语言规范:可以将变量标记为transient,以指示它们不是对象持久状态的一部分。 例如,您可能具有从其他字段派生的字段,并且仅应以编程方式进行操作,而不要通过序列化来保持状态。

例如,在BankPayment.java类中,可以对principalrate之类的字段进行序列化,而即使在反序列化之后也可以随时计算interest

回想一下,java 中的每个线程也都有自己的本地内存空间,并且它在本地内存中执行所有读/写操作。 完成所有操作后,它将所有线程访问该变量的位置写回主存储器中变量的修改状态。 通常,这是 JVM 内部的默认流程。 但是,volatile修饰符告诉 JVM,访问该变量的线程必须始终将其自身的变量私有副本与内存中的主副本进行协调。 这意味着每次线程想要读取变量的状态时,它都必须刷新其本地内存状态并从主内存中更新变量。

volatile

volatile在无锁算法中最有用。 当您不使用锁定来访问该变量并且希望一个线程所做的更改在另一个线程中可见时,或者您要创建“后接”关系以确保计算无需重新排序,以确保更改在适当的时间可见。

volatile应该用于在多线程环境中安全发布不可变对象。 声明诸如public volatile ImmutableObject foo之类的字段可确保所有线程始终看到当前可用的实例引用。

IteratorListIterator之间的区别?

我们可以使用Iterator遍历SetListMap。 但是ListIterator仅可用于遍历List。 其他差异如下所示。

您可以:

  1. 向后迭代。
  2. 随时获取索引。
  3. 随时添加新值。
  4. 在这个时间设置一个新值。

例如:

List<String> names = new ArrayList<String>();
names.add("Alex");
names.add("Bob");
names.add("Charles");
System.out.println(names);

ListIterator<String> listIterator = names.listIterator();

//Add a value at any place using ListIterator
while(listIterator.hasNext()){
    listIterator.next();
    listIterator.add("Lokesh");
}
System.out.println(names);

listIterator = names.listIterator();

//Set a value at any place using ListIterator
while(listIterator.hasNext()){
    listIterator.next();
    listIterator.set("John");
}
System.out.println(names);

Output:

[Alex, Bob, Charles]
[Alex, Lokesh, Bob, Lokesh, Charles, Lokesh]
[John, John, John, John, John, John]

显然,我可以在列表中的任意位置添加元素,同时对其进行迭代 – 同样,我也可以更改任何元素。 使用Iterator不可能。

学习愉快!

Java 核心面试问题 – 第 3 部分

原文: https://howtodoinjava.com/interview-questions/core-java-interview-questions-series-part-3/

面试问题系列中:第 1 部分第 2 部分,我们讨论了面试官通常会问的一些重要问题。 现在是推进该讨论的时候了。 在这篇文章中,我将在下面给出的问题列表中进行讨论。

Deep copy and shallow copy?
 What is synchronization? Class level locking and object level locking?
 Difference between sleep() and wait()?
 Can you assign null to this reference variable?
 What if the difference between && and &??
 How to override equals and hashCode() methods?
 Explain all access modifiers?
 What is garbage collection? Can we enforce it?
 What is native keyword?
 What is serialization? Explain the catches?

深拷贝和浅拷贝?

克隆是原始副本的精确副本。 在 Java 中,它实质上意味着能够创建状态与原始对象相似的对象。clone()方法提供了此功能。

浅拷贝应尽可能少地重复。 默认情况下,Java 克隆是浅表复制或“逐字段复制”,即,由于Object类不了解将在其上调用clone()方法的类的结构。 因此,JVM 被要求克隆时,请执行以下操作:

1)如果该类只有原始数据类型成员,则将创建该对象的全新副本,并返回对该新对象副本的引用。

2)如果该类包含任何类类型的成员,则仅复制对那些成员的对象引用,因此原始对象和克隆对象中的成员引用都引用同一对象。

深层副本会复制所有内容。 集合的深层副本是两个集合,原始集合中的所有元素都重复了。 在这里,我们想要一个独立于原始版本的克隆,对克隆进行更改不应影响原始版本。

深度克隆要求满足以下规则。

  1. 无需单独复制原始类型。
  2. 原始类中的所有成员类都应支持克隆,而上下文中原始类的clone方法应在所有成员类上调用super.clone()
  3. 如果任何成员类不支持克隆,则必须在克隆方法中创建该成员类的新实例,并将其所有属性一一复制到新的成员类对象中。 这个新的成员类对象将在克隆对象中设置。

在此处详细了解克隆

什么是同步? 对象级锁定和类级锁定?

同步是指多线程。 同步的代码块一次只能由一个线程执行。 Java 支持执行多个线程。 这可能会导致两个或多个线程访问相同的字段或对象。 同步是使所有并发线程在执行中保持同步的过程。 同步避免了由于共享内存视图不一致而导致的内存一致性错误。 当方法声明为已同步时; 该线程持有该方法对象的监视器。如果另一个线程正在执行同步方法,则该线程将被阻塞,直到该线程释放监视器。

Java 中的同步是使用syncronized关键字实现的。 您可以在类中的已定义方法或块上使用syncronized关键字。 关键字不能与类定义中的变量或属性一起使用。

对象级别锁定是一种机制,当您要同步非静态方法或非静态代码块,以便仅一个线程将能够在给定实例的代码上执行代码块时, 类。 应该始终这样做以确保实例级数据线程安全。

类级别锁定可防止多个线程在运行时进入所有可用实例中的任何同步块。 这意味着,如果在运行时有 100 个DemoClass实例,则一次只能在一个实例中的任何一个线程上执行demoMethod(),而所有其他实例将被其他线程锁定。 为了确保静态数据线程的安全,应该始终这样做。

在此处了解有关同步的更多信息。

sleep()wait()之间的区别?

sleep()是一种用于将进程保留几秒钟或所需时间的方法,但是如果使用wait()方法,线程将进入等待状态,直到我们调用notify()notifyAll()

主要区别在于,wait()释放锁定或监视器,而sleep()不在等待期间释放任何锁或监视器。 通常,“等待”用于线程间通信,而“睡眠”用于引入执行暂停。

Thread.sleep()在一段时间内将当前线程发送到“不可运行”状态。 该线程将保留其已获取的监视器 - 即,如果该线程当前处于同步块或方法中,则其他线程无法进入该块或方法。 如果另一个线程调用t.interrupt(),它将唤醒睡眠线程。 请注意,sleep是一种静态方法,这意味着它始终会影响当前线程(正在执行sleep方法的线程)。 一个常见的错误是调用t.sleep(),其中t是一个不同的线程。 即使这样,当前线程仍将睡眠,而不是t线程。

object.wait()将当前线程发送到“不可运行”状态,就像sleep()一样,但要稍加调整。 Wait是在对象而不是线程上调用的; 我们将此对象称为“锁定对象”。 在调用lock.wait()之前,当前线程必须在锁对象上进行同步。 然后,wait()释放此锁定,并将线程添加到与该锁定关联的“等待列表”。 稍后,另一个线程可以在同一个锁对象上同步并调用lock.notify()。 这将唤醒原始的等待线程。 基本上,wait()/notify()就像sleep()/interrupt()一样,仅活动线程不需要直接指针指向睡眠线程,而仅需要指向共享锁对象的指针。

在此处详细阅读区别。

可以为this引用变量分配null吗?

没有。 你不能。在 Java 中,赋值语句的左侧必须是变量。 “this”是一个特殊的关键字,始终代表当前实例。 这不是任何变量。

同样,不能将null分配给“super”或任何此类关键字。

&&&之间是否有区别?

&是按位的,&&是逻辑的。

  • &求值操作的双方。
  • &&求值操作的左侧,如果为真,则继续并求值右侧。

请阅读此处以深入了解。

如何覆盖equalshashCode()方法?

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

hashCode()方法用于获取给定对象的唯一整数。 当此对象需要存储在类似数据结构的HashTable中时,此整数用于确定存储桶位置。 默认情况下,对象的hashCode()方法返回存储对象的内存地址的整数表示形式。

顾名思义,equals()方法用于简单地验证两个对象的相等性。 默认实现只是检查两个对象的对象引用以验证它们的相等性。

以下是在覆盖这些函数时要记住的要点。

  1. 始终使用对象的相同属性来生成hashCode()equals()两者。 在本例中,我们使用了员工 ID。
  2. equals()必须一致(如果未修改对象,则必须保持返回相同的值)。
  3. 只要a.equals(b),则a.hashCode()必须与b.hashCode()相同。
  4. 如果覆盖一个,则应覆盖另一个。

在此处阅读更多有趣的事实以及指南。

解释所有访问修饰符?

Java 类,字段,构造器和方法可以具有四种不同的访问修饰符之一:

private

如果将方法或变量标记为私有,则只有同一类内的代码才能访问该变量或调用该方法。 子类中的代码无法访问变量或方法,也不能从任何外部类中进行代码。
如果将一个类标记为私有,则没有外部类可以访问该类。 不过,对于类来说,这实际上没有多大意义。 因此,访问修饰符private主要用于字段,构造器和方法。

默认

通过根本不编写任何访问修饰符来声明默认访问级别。 默认访问级别意味着与类相同的包中的类本身内的代码+类内的代码可以访问类,字段,构造器或方法。 因此,默认访问修饰符有时也称为包访问修饰符。

如果子类声明了默认的可访问性,则子类不能访问父类中的方法和成员变量,除非子类与父类位于同一包中。

protected

protected访问修饰符的作用与默认访问权限相同,除了子类还可以访问超类的受保护方法和成员变量。 即使子类与超类不在同一个包中,也是如此。

public

公开访问修饰符意味着所有代码都可以访问类,字段,构造器或方法,无论访问代码位于何处。

| 修饰符 | 相同的类 | 相同的包 | 子类 | 其他包 |
| --- | --- | --- |
| public | Y | Y | Y | Y |
| protected | Y | Y | Y | N |
| 默认 | Y | Y | N | N |
| private | Y | N | N | N |

什么是垃圾回收? 我们可以执行吗?

垃圾回收是许多现代编程语言(例如 Java 和 .NET 框架中的语言)中的自动内存管理功能。 使用垃圾回收的语言通常在 JVM 之类的虚拟机中解释或运行。 在每种情况下,运行代码的环境还负责垃圾回收。 GC 具有两个目标:应释放所有未使用的内存,并且除非程序不再使用它,否则不应释放任何内存。

你能强迫垃圾收集吗? 不,System.gc()尽可能接近。 最好的选择是调用System.gc(),这只是向垃圾收集器提示您要它进行收集。 由于垃圾收集器是不确定的,因此无法强制立即收集。 另外,在OutOfMemoryError文档下,它声明除非 VM 在完全垃圾回收后未能回收内存,否则不会抛出该错误。 因此,如果在出现错误之前一直分配内存,那么您将已经强制执行完整的垃圾回收。

在此处详细了解垃圾收集。

什么是`native关键字? 详细解释?

native关键字应用于方法,以指示该方法是使用 JNI 在本地代码中实现的。 它标记了一种方法,它将以其他语言而不是 Java 来实现。

过去曾使用本机方法来编写对性能至关重要的部分,但随着 Java 变得越来越快,这种方法现在已不那么普遍了。 当前需要本机方法

  • 您需要从 Java 调用用其他语言编写的库。
  • 您需要访问只能从其他语言(通常为 C)访问的系统或硬件资源。 实际上,许多与真实计算机交互的系统功能(例如磁盘和网络 IO)只能执行此操作,因为它们调用了本机代码。

使用本机代码库的缺点也很重要:

  1. JNI/JNA 倾向于破坏 JVM 的稳定性,尤其是当您尝试做一些复杂的事情时。 如果您的本机代码错误地执行了本机代码内存管理,则很有可能会使 JVM 崩溃。 如果您的本机代码是不可重入的,并且从多个 Java 线程中调用,则坏事……会偶尔发生。 等等。
  2. 带有本机代码的 Java 比纯 Java 或纯 C/C++ 更难调试。
  3. 本机代码可能为其他平台无关的 Java 应用引入重要的平台依赖项/问题。
  4. 本机代码需要一个单独的构建框架,并且也可能存在平台/可移植性问题。

什么是序列化? 解释渔获物?

在计算机科学中,在数据存储和传输的上下文中,序列化是将数据结构或对象状态转换为一种格式的过程,该格式可以稍后在相同或另一台计算机环境中存储和恢复。 当根据序列化格式重新读取生成的一系列位时,可以使用它来创建原始对象的语义相同的克隆。

Java 提供了自动序列化,该序列化要求通过实现java.io.Serializable接口来标记对象。 实现该接口会将类标记为“可以序列化”,然后 Java 将在内部处理序列化。 在Serializable接口上没有定义任何序列化方法,但是可序列化类可以选择定义具有某些特殊名称和签名的方法,如果定义了这些特殊名称和签名,这些方法将在序列化/反序列化过程中被调用。

对象序列化后,其类中的更改会破坏反序列化过程。 要确定您的类中将来的变化,这些变化将是兼容的,而其他变化将被证明是不兼容的,请在此处阅读完整的指南。 简而言之,我在这里列出:

不兼容的更改

  • 删除字段
  • 将类上移或下移
  • 将非静态字段更改为静态或将非瞬态字段更改为瞬态
  • 更改原始字段的声明类型
  • 更改writeObjectreadObject方法,使其不再写入或读取默认字段数据
  • 将类从可序列化更改为可外部化,反之亦然
  • 将类从非枚举类型更改为枚举类型,反之亦然
  • 删除SerializableExternalizable
  • writeReplacereadResolve方法添加到类

兼容的更改

  • 新增字段
  • 添加/删除类
  • 添加writeObject/readObject方法(首先应调用defaultReadObjectdefaultWriteObject)
  • 删除writeObject/readObject方法
  • 添加java.io.Serializable
  • 更改对字段的访问
  • 将字段从静态更改为非静态或将瞬态更改为非瞬态

学习愉快!

Java 面试的 40 个热门问答集

原文: https://howtodoinjava.com/interview-questions/useful-java-collection-interview-questions/

毫无疑问,java 集合是最重要的领域之一,无论您是初级还是高级,您都可以在任何位置对其进行测试。 范围如此之广,几乎不可能涵盖所有问题。 但是,根据我以前的面试,我尝试提出您必须知道的尽可能多的优秀的 java 集合面试问题

我的目标是初学者和高级问题,所以如果您发现一些基本问题,请多多包涵,因为它们对某些初级开发人员可能有用。

Java collection interview questions

General questions

1) What is the Java Collections API? List down its advantages?
2) Explain Collections hierarchy?
3) Why Collection interface does not extend Cloneable and Serializable interface?
4) Why Map interface does not extend Collection interface?

List interface related

5) Why we use List interface? What are main classes implementing List interface?
6) How to convert an array of String to ArrayList?
7) How to reverse the list?

Set interface related

8) Why we use Set interface? What are main classes implementing Set interface?
9) How HashSet store elements?
10) Can a null element added to a TreeSet or HashSet?

Map interface related

11) Why we use Map interface? What are main classes implementing Map interface?
12) What are IdentityHashMap and WeakHashMap?
13) Explain ConcurrentHashMap? How it works?
14) How hashmap works?
15) How to design a good key for hashmap?
16) What are different Collection views provided by Map interface?
17) When to use HashMap or TreeMap?

Tell the difference questions

18) Difference between Set and List?
19) Difference between List and Map?
20) Difference between HashMap and HashTable?
21) Difference between Vector and ArrayList?
22) Difference between Iterator and Enumeration?
23) Difference between HashMap and HashSet?
24) Difference between Iterator and ListIterator?
25) Difference between TreeSet and SortedSet?
26) Difference between ArrayList and LinkedList?

More questions

27) How to make a collection read only?
28) How to make a collection thread safe?
29) Why there is not method like Iterator.add() to add elements to the collection?
30) What are different ways to iterate over a list?
31) What do you understand by iterator fail-fast property?
32) What is difference between fail-fast and fail-safe?
33) How to avoid ConcurrentModificationException while iterating a collection?
34) What is UnsupportedOperationException?
35) Which collection classes provide random access of it’s elements?
36) What is BlockingQueue?
37) What is Queue and Stack, list their differences?
38) What is Comparable and Comparator interface?
39) What are Collections and Arrays class?
40) Recommended resources

不要浪费时间,让我们深入研究 Java 集合的概念。

Java 集合面试一般问题

1)什么是 Java 集合框架? 列出其优势?

根据定义,集合是代表一组对象的对象。 像集合论一样,集合是一组元素。 很简单!

在 JDK 1.2 之前,JDK 具有一些工具类,例如VectorHashTable,但是没有集合框架的概念。 从 JDK 1.2 以后,JDK 感到需要对可重用数据结构提供一致的支持。 最后,集合框架主要由 Joshua Bloch 设计和开发,并在 JDK 1.2 中引入。

Java 集合的最明显的优点可以列出为

  • 随时可用的代码,减少了编程工作
  • 由于数据结构和算法的高性能实现而提高了性能
  • 通过建立公共语言来回传递集合,从而在不相关的 API 之间提供互操作性
  • 通过仅学习一些顶级接口和受支持的操作,易于学习的 API

2)解释集合的层次结构?

Java Collection Hierarchy

Java 集合的层次结构

如上图所示,集合框架顶部有一个接口,即集合。 通过集,列表和队列接口对其进行了扩展。 然后在这 3 个分支中还有其他类别的负载,我们将在以下问题中学习。

记住Collection接口的签名。 它会在很多问题上帮助您。

public interface Collection extends Iterable {
//method definitions
}

框架还包含Map接口,它是集合框架的一部分。 但它不会扩展Collection接口。 我们将在此问题库中的第四个问题中看到原因。

3)为什么Collection接口没有扩展CloneableSerializable接口?

好吧,最简单的答案是“不需要这样做”。 扩展接口仅表示您正在创建接口的子类型,换句话说,不希望使用更专门的行为和Collection接口来实现CloneableSerializable接口。

另一个原因是并非每个人都有理由拥有Cloneable集合,因为如果它具有非常大的数据,那么每个不必要的克隆操作都将消耗大量内存。 初学者可能在不知道后果的情况下使用它。

另一个原因是CloneableSerializable是非常专门的行为,因此仅在需要时才应实现。 例如,集合中的许多具体类都实现了这些接口。 因此,如果您想要此功能。 使用这些集合类,否则使用其替代类。

4)为什么Map接口没有扩展Collection接口?

这个面试问题的一个很好的答案是“因为它们不兼容”。 集合具有方法add(Object o)。 Map 无法使用这种方法,因为它需要键值对。 还有其他原因,例如Map支持keySetvalueSet等。Collection类没有此类视图。

由于存在如此大的差异,因此在Map接口中未使用Collection接口,而是在单独的层次结构中构建。

Java 集合面试 – 列出接口问题

5)为什么要使用List接口? 什么是实现List接口的主要类?

Java 列表是元素的“有序”集合。 该排序是基于零的索引。 它不关心重复项。 除了在Collection接口中定义的方法外,它确实有自己的方法,它们在很大程度上也要根据元素的索引位置来操作集合。 这些方法可以分为搜索,获取,迭代和范围视图。 以上所有操作均支持索引位置。

实现List接口的主要类为: StackVectorArrayListLinkedList。 在 Java 文档中阅读有关它们的更多信息。

6)如何将String数组转换为arraylist

这更多是一个程序性问题,在初学者水平上可以看到。 目的是检查集合工具类中申请人的知识。 现在,让我们了解Collection框架中有两个工具类,它们大多数在面试中看到,即CollectionsArrays

集合类提供了一些静态函数来对集合类型执行特定操作。 数组提供了要在数组类型上执行的工具函数。

//String array
String[] words = {"ace", "boom", "crew", "dog", "eon"};
//Use Arrays utility class
List wordList = Arrays.asList(words);
//Now you can iterate over the list

请注意,此函数并非特定于String类,它将返回数组属于任何类型的元素的List。 例如:

//String array
Integer[] nums = {1,2,3,4};
//Use Arrays utility class
List numsList = Arrays.asList(nums);

7)如何反转列表?

这个问题就像上面的测试您对集合工具类的了解。 使用它的reverse()方法可以反转列表。

   Collections.reverse(list);

Java 集合面试 – `Set``接口问题

8)为什么要使用Set接口? 什么是实现Set接口的主要类?

对集合论中的数学集合进行建模。 Set接口类似于List接口,但有一些区别。 首先,它是未排序的集合。 因此,添加或删除元素时不会保留任何顺序。 它提供的主要功能是“元素的唯一性”。 它不支持重复元素。

Set还对equalshashCode操作的行为增加了更强的约定,从而即使它们的实现类型不同,也可以有意义地比较Set实例。 如果两个Set实例包含相同的元素,则它们相等。

基于上述原因,它没有基于列表之类的元素的索引进行的操作。 它只有由Collection接口继承的方法。

实现Set接口的主要类为:EnumSetHashSetLinkedHashSetTreeSet。 阅读更多有关 Java 文档的信息。

9)HashSet如何存储元素?

您必须知道HashMap存储具有一个条件的键值对,即键将是唯一的。 HashSet使用映射的此功能来确保元素的唯一性。 在HashSet类中,映射声明如下:

private transient HashMap<E,Object> map;

//This is added as value for each key
private static final Object PRESENT = new Object();

因此,将元素存储在HashSet中时,会将元素存储为映射中的键,将“PRESENT”对象存储为值。 (请参见上面的声明)。

public boolean add(E e) {
return map.put(e, PRESENT)==null;
}

我强烈建议您阅读这篇文章:HashMap如何在 Java 中工作?这篇文章将帮助您轻松地回答所有与HashMap相关的问题。

10)是否可以将null元素添加到TreeSet或 HashSet 中?

如您所见,上一个问题的add()方法中没有null检查。 并且HashMap还允许一个null键,因此在HashSet中允许一个“null”。

TreeSet使用与HashSet相同的概念进行内部逻辑,但是使用NavigableMap来存储元素。

private transient NavigableMap<E,Object> m;

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

NavigableMapSortedMap的子类型,不允许使用null键。 因此,本质上,TreeSet也不支持空键。 如果您尝试在TreeSet中添加null元素,它将抛出NullPointerException

Java 集合面试 – Map接口问题

11)为什么要使用Map接口? 什么是实现Map接口的主要类?

Map接口是一种特殊的集合类型,它用于存储键值对。 因此,它不会扩展Collection接口。 该接口提供了在映射的各种视图上添加,删除,搜索或迭代的方法。

实现Map接口的主要类有:HashMapHashtableEnumMapIdentityHashMapLinkedHashMapProperties

12)什么是 IdentityHashMapWeakHashMap

IdentityHashMapHashMap相似,不同之处在于在比较元素时使用引用相等性。 IdentityHashMap类不是一种广泛使用的Map实现。 尽管此类实现了Map接口,但它有意违反Map的一般协定,该协定要求在比较对象时必须使用equals()方法。 IdentityHashMap设计为仅在少数情况下使用,其中需要引用相等语义。

WeakHashMapMap接口的实现,该接口仅存储对其键的弱引用。 当不再在WeakHashMap外部引用键值对时,仅存储弱引用将允许对键值对进行垃圾回收。 该类主要用于与equals方法使用==运算符测试对象标识的键对象一起使用。 一旦丢弃了这样的键,就永远无法重新创建它,因此以后不可能在WeakHashMap中对该键进行查找,并且会惊讶地发现它的项目已被删除。

13)解释ConcurrentHashMap吗? 怎么运行的?

来自 Java 文档:

支持检索的完全并发和用于更新的可调整预期并发的哈希表。 此类遵循与Hashtable相同的功能规范,并且包括与Hashtable的每个方法相对应的方法的版本。 但是,即使所有操作都是线程安全的,检索操作也不需要进行锁定,并且不支持以阻止所有访问的方式锁定整个表。 在依赖于其线程安全性但不依赖于其同步详细信息的程序中,此类可与Hashtable完全互操作。

阅读有关ConcurrentHashMap面试问题的更多信息。

14)HashMap如何工作?

最重要的问题在每个工作面试中最有可能出现。 您必须在这个主题上非常清楚。不仅因为它是最常被问到的问题,而且会让您对与集合 API 相关的其他问题打开思路。

这个问题的答案非常大,您应该阅读我的文章:HashMap如何工作? 现在,让我们记住HashMap在哈希原理上工作。 根据定义,映射是:“将键映射到值的对象”。 为了存储这种结构,使用了内部类Entry

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

此处,键和值变量用于存储键值对。 整个项目对象存储在数组中。

/**
* The table, re-sized as necessary. Length MUST Always be a power of two.
*/
transient Entry[] table;

数组的索引是根据Key对象的哈希码计算的。 阅读更多链接主题。

15)如何为哈希表设计一个好的键?

在回答HashMap如何工作后,通常会跟进另一个好问题。 好吧,最重要的约束是,您将来必须能够取回值对象。 否则,没有使用这种数据结构。 如果您了解hashmap的工作原理,将会发现它很大程度上取决于Key对象的hashCode()equals()方法。

因此,好的键对象必须一次又一次提供相同的hashCode(),无论它被获取了多少次。 同样,与equals()方法比较时,相同的键必须返回true,而不同的键必须返回false

因此,不变类被认为是HashMap的最佳候选者。

阅读更多:如何为HashMap设计一个好的键?

16)Map接口提供哪些不同的集合视图?

Map接口提供了 3 个存储在其中的键值对的视图:

  • 键集视图
  • 值集视图
  • 项集视图

可以使用迭代器浏览所有视图。

17)什么时候使用HashMapTreeMap

HashMap是众所周知的类,我们所有人都知道。 因此,我将离开这部分,说它用于存储键值对,并允许对这样的对集合执行许多操作。

TreeMapHashMap的特殊形式。 它维护HashMap类中缺少的键的顺序。 默认情况下,此排序为“自然排序”。 通过提供Comparator类的实例,可以覆盖默认顺序,该类的compare方法将用于维护键的顺序。

请注意,所有插入映射的键都必须实现Comparable接口(这是确定顺序的必要条件)。 此外,所有这些键必须相互可比较:k1.compareTo(k2)不得为映射中的任何键k1k2抛出ClassCastException。 如果用户尝试将键放入违反此约束的映射中(例如,用户尝试将字符串键放入其键为整数的映射中),则put(Object key, Object value)调用将引发ClassCastException

Java 集合面试 – 讲述差异问题

18)SetList之间的区别?

最明显的区别是:

  • Set是无序集合,其中List是基于零索引的有序集合。
  • 列表允许重复元素,但Set不允许重复。
  • List不会阻止插入空元素(随您喜欢),但是Set将只允许一个空元素。

19)列表和映射之间的区别?

也许是最简单的问题。 列表是元素的集合,而映射是键值对的集合。 实际上,有很多差异源自第一个陈述。 它们具有单独的顶层接口,单独的一组通用方法,不同的受支持方法和不同的集合视图

我会花很多时间来回答这个问题,仅作为第一个区别就足够了。

20)HashMapHashTable之间的区别?

Java 中的HashMapHashtable之间有一些区别:

  • Hashtable是同步的,而HashMap不是同步的。
  • 哈希表不允许使用空键或空值。 HashMap允许一个空键和任意数量的空值。
  • HashMapHashtable之间的第三个重要区别是HashMap中的Iterator是快速失​​败的迭代器,而Hashtable的枚举器则不是。

21)VectorArrayList之间的区别?

让我们记下差异:

  • Vector的所有方法都是同步的。 但是,ArrayList的方法不同步。
  • Vector是在 JDK 的第一个版本中添加的旧类。 当在 Java 中引入集合框架时,ArrayList是 JDK 1.2 的一部分。
  • 默认情况下,Vector在内部调整大小时会将其数组的大小加倍。 但是,重新调整大小时,ArrayList的大小增加一半。

22)迭代器和枚举器之间的区别?

迭代器与枚举在以下三个方面有所不同:

  • 迭代器允许调用方使用其remove()方法在迭代过程中从基础集合中删除元素。 使用枚举器时,不能从集合中添加/删除元素。
  • 枚举器在旧类(例如Vector/Stack等)中可用,而Iterator在所有现代集合类中可用。
  • 另一个小的区别是Iterator改进了方法名称,例如Enumeration.hasMoreElement()变为Iterator.hasNext()Enumeration.nextElement()变为Iterator.next()等。

23)HashMapHashSet之间的区别?

HashMap是键值对的集合,而HashSet是唯一元素的无序集合。 而已。 无需进一步描述。

24)IteratorListIterator之间的区别?

有三个区别:

  • 我们可以使用Iterator遍历SetList以及MapObject类型。 但是列表迭代器可用于遍历列表类型的对象,但不能遍历对象的集合类型。
  • 通过使用Iterator,我们只能从正向检索Collection对象中的元素,而List Iterator则允许您使用hasPrevious()previous()方法在任一方向上遍历。
  • ListIterator允许您使用add() remove()方法修改列表。 使用Iterator不能添加,只能删除元素。

25)TreeSetSortedSet之间的区别?

SortedSetTreeSet实现的接口。 就是这样!

26)ArrayListLinkedList之间的区别?

  • LinkedList将元素存储在双链列表数据结构中。 ArrayList将元素存储在动态调整大小的数组中。
  • LinkedList允许进行固定时间的插入或删除,但只允许顺序访问元素。 换句话说,您可以向前或向后浏览列表,但是在中间抓取一个元素所花费的时间与列表的大小成正比。 另一方面,ArrayList允许随机访问,因此您可以在固定时间内抓取任何元素。 但是,从末端开始的任何地方添加或删除,都需要将后面的所有元素移开,以形成开口或填补空白。
  • LinkedListArrayList具有更多的内存开销,因为在ArrayList中,每个索引仅保存实际的对象(数据),但是在LinkedList的情况下,每个节点都保存下一个和上一个节点的数据以及地址。

更多面试面试问题

27)如何使集合只读?

使用以下方法:

  • Collections.unmodifiableList(list);
  • Collections.unmodifiableSet(set);
  • Collections.unmodifiableMap(map);

这些方法采用集合参数,并返回一个具有与原始集合中相同的元素的新的只读集合。

28)如何使集合线程安全?

使用以下方法:

  • Collections.synchronizedList(list);
  • Collections.synchronizedSet(set);
  • Collections.synchronizedMap(map);

上面的方法将集合作为参数并返回相同类型的集合,这些类型是同步的且线程安全的。

29)为什么没有像Iterator.add()这样的方法将元素添加到集合中?

迭代器的唯一目的是通过集合进行枚举。 所有集合都包含add()方法以实现您的目的。 添加Iterator毫无意义,因为集合可能有序,也可能没有排序。 而且add()方法对于有序和无序集合不能具有相同的实现。

30)有哪些不同的方法可以遍历列表?

您可以使用以下方式遍历列表:

  • 迭代器循环
  • for循环
  • for循环(高级)
  • While循环

阅读更多: http://www.mkyong.com/java/how-do-loop-iterate-a-list-in-java/

31)通过迭代器快速失败属性您了解什么?

快速失败迭代器一旦意识到自迭代开始以来就已更改集合的结构,便会失败。 结构更改意味着在一个线程迭代该集合时,从集合中添加,删除或更新任何元素。

通过保留修改计数来实现快速失败行为,如果迭代线程实现了修改计数的更改,则会引发ConcurrentModificationException

32)快速失败和故障安全之间有什么区别?

您已经在上一个问题中理解了快速失败。 故障安全迭代器与快速失败相反。 如果您修改要在其上进行迭代的基础集合,它们将永远不会失败,因为它们在集合的克隆而不是原始集合上起作用,这就是为什么将它们称为故障保护迭代器。

CopyOnWriteArrayList的迭代器是故障安全迭代器的示例,而且ConcurrentHashMap keySet编写的迭代器也是故障安全迭代器,并且永远不会抛出ConcurrentModificationException

33)如何在迭代集合时避免ConcurrentModificationException

您应该首先尝试查找故障安全的另一个替代迭代器。 例如,如果您正在使用List,则可以使用ListIterator。 如果它是旧式集合,则可以使用枚举。

如果上述选项不可行,则可以使用以下三种更改之一:

  • 如果使用的是 JDK1.5 或更高版本,则可以使用ConcurrentHashMapCopyOnWriteArrayList类。 这是推荐的方法。
  • 您可以将列表转换为数组,然后在数组上进行迭代。
  • 您可以通过将列表放在同步块中来在迭代时锁定列表。

请注意,最后两种方法会导致性能下降。

34)什么是UnsupportedOperationException

实际的集合类型不支持的被调用方法抛出的异常

例如,如果您使用“Collections.unmodifiableList(list)”创建一个只读列表列表,然后调用add()remove()方法,那将会发生什么。 它应该明确抛出UnsupportedOperationException

35)哪些集合类可随机访问其元素?

ArrayListHashMapTreeMapHashtable类提供对其元素的随机访问。

36)什么是BlockingQueue

一个队列,它另外支持以下操作:在检索元素时等待队列变为非空,并在存储元素时等待队列中的空间变为可用。

BlockingQueue方法有四种形式:一种抛出异常,第二种返回一个特殊值(根据操作的不同,返回nullfalse),第三种无限期地阻塞当前线程,直到操作成功为止;第四种仅在放弃之前给出最大时间限制。

阅读文章中的阻塞队列示例用法: 如何使用阻塞队列?

37)什么是队列和栈,列出它们之间的差异?

设计用于在处理之前保存元素的集合。 除了基本的集合操作之外,队列还提供其他插入,提取和检查操作。

通常但不一定以 FIFO(先进先出)的方式对元素进行排序。

栈也是队列的一种形式,但有一个区别,那就是 LIFO(后进先出)。

无论使用哪种顺序,队列的开头都是该元素,可以通过调用remove()poll()将其删除。 另请注意,栈和向量都已同步。

用法:如果要按接收顺序处理传入流,请使用队列。适用于工作列表和处理请求。
如果只想从栈顶部推动并弹出,请使用栈。 适用于递归算法。

38)什么是ComparableComparator接口?

在 Java 中。 所有具有自动排序功能的集合都使用比较方法来确保元素的正确排序。 例如,使用排序的类为TreeSetTreeMap等。

为了对一个类的数据元素进行排序,需要实现ComparatorComparable接口。 这就是所有包装器类(例如IntegerDoubleString类)都实现Comparable接口的原因。

Comparable帮助保留默认的自然排序,而Comparator帮助以某些特殊的必需排序模式对元素进行排序。 比较器的实例,通常在支持集合时作为集合的构造器参数传递。

39)什么是CollectionsArrays类?

CollectionsArrays类是支持集合框架核心类的特殊工具类。 它们提供工具函数以获取只读/同步集合,以各种方式对集合进行排序等。

数组还帮助对象数组转换为集合对象。 数组还具有一些函数,有助于复制或处理部分数组对象。

40)推荐资源

好吧,这不是面试的问题..

标签:xml,教程,其它,Java,String,HowToDoInJava,import,com,public
From: https://www.cnblogs.com/apachecn/p/18500109

相关文章

  • HowToDoInJava-其它教程-1-一-
    HowToDoInJava其它教程1(一)原文:HowToDoInJava协议:CCBY-NC-SA4.0Maven本地仓库位置以及如何更改?原文:https://howtodoinjava.com/maven/change-local-repository-location/在本教程中,学习更改Maven本地仓库的位置。Maven是构建和依赖项管理工具。它将所需的项目......
  • StudyTonight-Web-中文教程-一-
    StudyTonightWeb中文教程(一)原文:StudyTonight协议:CCBY-NC-SA4.0HTMLHTML标签AHTML<a>标签原文:https://www.studytonight.com/html5-references/html-a-tagHTML<a>标签是一个锚点,用来创建一个超链接。超链接用于将当前网页与其他网页或互联网上可用的任何其他网......
  • ZetCode-Kotlin-教程-一-
    ZetCodeKotlin教程(一)原文:ZetCode协议:CCBY-NC-SA4.0KotlinHelloWorld教程原文:http://zetcode.com/kotlin/helloworld/KotlinHelloWorld教程展示了如何在Kotlin中创建HelloWorld程序。Kotlin是在Java虚拟机上运行的静态类型的编程语言。Kotlin由Jet......
  • ZetCode-Java-教程-二-
    ZetCodeJava教程(二)原文:ZetCode协议:CCBY-NC-SA4.0Java语法结构原文:http://zetcode.com/lang/java/lexis/像人类语言一样,计算机语言也具有词汇结构。Java程序的源代码由令牌组成。令牌是原子代码元素。在Java中,我们具有注释,标识符,字面值,运算符,分隔符和关键字。Ja......
  • ZetCode-GUI-教程-九-
    ZetCodeGUI教程(九)原文:ZetCode协议:CCBY-NC-SA4.0wxWidgets中的布局管理原文:http://zetcode.com/gui/wxwidgets/layoutmanagement/典型的应用由各种小部件组成。这些小部件放置在容器小部件内。程序员必须管理应用的布局。这不是一件容易的事。在wxWidgets中,我......
  • ZetCode-PHP-教程-一-
    ZetCodePHP教程(一)原文:ZetCode协议:CCBY-NC-SA4.0PHP教程原文:https://zetcode.com/lang/php/这是PHP教程。本教程涵盖了PHP编程语言的核心。它使用PHPCLI。PHP教程适合初学者。目录PHP语言词法结构基础知识数据类型字符串运算符控制流数组数组......
  • 计算机毕业设计项目推荐:大学生实习成绩评价系统的设计与实现38147(开题答辩+程序定制+
    摘 要21世纪的今天,随着社会的不断发展与进步,人们对于信息科学化的认识,已由低层次向高层次发展,由原来的感性认识向理性认识提高,管理工作的重要性已逐渐被人们所认识,科学化的管理,使信息存储达到准确、快速、完善,并能提高工作管理效率,促进其发展。论文主要是对大学生实习成绩......
  • 计算机毕业设计项目推荐,个人知识管理系统 79004(开题答辩+程序定制+全套文案 )上万套实
    摘 要尽管我们每天面临的信息越来越多,信息过载与信息噪音越来越严重,但只要我们能充分利用个人知识管理技能,借助有效的个人知识管理软件相信战胜海量信息不再是困难。本课题在分析了个人知识管理现状以及对现有的个人知识管理网站进行研究比较的基础上,针对网络交流互助的特......
  • vue3入门教程,一站学会全套vue!
    vue3vue3作为前端重要的框架,学会vue可以让你更加了解前端。本博客致力于让你一站学会vue3的全部内容,从小白到高手。全是干货,准备好了吗?文章目录vue3创建工程文档结构核心语法模板语法插值语法指令语法无参指令有参指令自定义指令setupsetup函数setup语法糖响应式数......
  • SQL:Windows下MySQL的安装教程(超详细)
    一.系统环境:操作系统:Windows11;MySQL版本:mysql-community-8.0.40.0;二.MySQL下载:访问MySQL官网下载地址:https://www.mysql.com/,点击DOWNLOADS;跳转后页面下滑找到框选链接并点击;跳转后点击框选链接;跳转后点击Download;5.当前下载页面需要登录但是也可以点......