大数据开发(Java面试真题)

大数据开发(Java面试真题)

  • 一、Java基本概念和数据结构
    • 1、请解释Java中HashMap和HashTable的区别?
    • 2、Java中ThreadLocal的原理是什么?
    • 3、请简要说明Java中equals()和hashCode()的作用及区别?
    • 4、Java中的四种访问修饰符及它们之间的区别?
    • 5、Java中ArrayList和LinkedList区别是什么?
    • 6、Java中ArrayList扩容过程是什么?
    • 7、Java中HashMap底层实现是什么?
    • 8、Java中ConcurrentHashMap支持多并发的原理是什么?
    • 9、HashMap原理?转换成红黑树条件?为什么这么设计?
    • 10、Java线程安全的HashMap?ConcurrentHashMap和HashTable的区别?ConcurrentHashMap原理?
  • 二、Java字符串和集合
    • 1、请解释Java中的String、StringBuilder和StringBuffer的区别?
    • 2、Java String为什么是不可变的?为什么要设计成不可变?
    • 3、Java集合类型?
  • 三、JVM与垃圾回收
    • 1、讲一下 JVM 的垃圾回收的相关概念。
    • 2、JVM 常见调优方法有哪些?
    • 3、什么是JVM垃圾回收?Java中有几种垃圾回收算法?
    • 4、Java的垃圾回收机制是什么?简要描述它的工作原理。
  • 四、Java内存管理与性能优化
    • 1、Java的内存区域分为几个部分?
    • 2、什么情况下Java新建的对象不存储在Eden中?
    • 3、Java线程池的核心参数有哪些?
    • 4、请解释下Java中的线程池是什么,如何使用线程池来提高程序的性能?
  • 五、Java异常处理和类加载
    • 1、请解释Java中的异常处理机制,包括checked exception和unchecked exception?
    • 2、JVM中一个类加载的过程是什么样子?
  • 六、Java高级特性
    • 1、Java中Synchronized的底层原理是什么?
    • 2、泛型?
    • 3、常用的反射方法?
    • 4、Java中深拷贝和浅拷贝的区别是什么?

一、Java基本概念和数据结构

1、请解释Java中HashMap和HashTable的区别?

HashMap和HashTable是两个常见的哈希表实现类,在以下几个方面有所不同:

  1. 线程安全性HashTable是线程安全的,各个方法都有synchronized修饰,适用于多线程环境。而HashMap不是线程安全的,如果多个线程同时访问一个HashMap实例并且至少一个线程修改了Map结构,则必须通过外部同步机制来保证其同步。
  2. 允许空键和空值HashMap允许插入null键和null值,而HashTable不允许
  3. 迭代器遍历顺序HashMap的迭代器是fail-fast的,即在迭代过程中如果其它线程对HashMap进行结构修改(增加或者删除元素),会抛出异常。而HashTable继承自Dictionary类,并不支持迭代器

2、Java中ThreadLocal的原理是什么?

ThreadLocal是Java中的一种线程封闭机制,它可以为每个线程都创建一个独立的变量副本,使得每个线程都可以独立地改变自己地副本,而不会影响其它线程所对应地副本==。ThreadLocal对于实现线程地局部变量以及线程安全十分有用。下面是ThreadLocal的基本工作原理:

  1. 内部存储:每个Thread都有一个ThreadLocalMap类型的成员变量ThreadLocals,这个变量是ThreadLocal的内部类。
  2. ThreadLocalMap的键为ThreadLocal对象,值为线程局部变量:也就是说,ThreadLocal本身并不存储值,它只是作为一个key来帮助线程从ThreadLocalMap获取一个线程局部变量
  3. get()方法:当调用ThreadLocal的get()方法时,实际上是去调用Thread.currentThread().getThreadLocalMap().get(this)。这个操作就是获取当前线程的threadLocals成员变量,然后以当前ThreadLocal实例作为key,去获取线程局部变量
  4. set()方法:当调用ThreadLocal的set()方法时,实际上是去调用Thread.currentThread().getThreadLocalMap().set(this,value)。这个操作就是获取当前线程的threadLocals成员变量,然后以当前ThreadLocal实例作为key,和将要存储的值作为value,存入ThreadLocalMap中

3、请简要说明Java中equals()和hashCode()的作用及区别?

equals()方法判断两个对象是否相同,在Object类中默认比较两个对象是否为同一引用。而hashCode()方法返回对象对应的哈希码值,主要被哈希表使用。

作用
-equals():主要用户判断两个对象内容是否相同(而不是引用地址),可以根据业务需求进行重写。
-hashCode():主要用于提高对对象的查找和存储效率,将对象映射为哈希表中的索引

区别

  1. equals()和hashCode()是不同目的所使用的方法,equals()用于判断对象内容相等性,hashCode()主要用于哈希表存储
  2. 如果两个对象调用equals()方法返回true,则它们的hashCode值应该一样,但反之则不成立

4、Java中的四种访问修饰符及它们之间的区别?

Java中有四种访问修饰符:public、protected、private和default(即没有明确的修饰符)。它们用于限定类、方法和变量对其它类或子类的可见性。

-public:可以被所有类访问。被public修饰的类、方法和变量都可以在任何地方访问。
-protected只能在声明所在类或者子类中使用。被protected修饰的方法和成员变量对于同一包内其它类也是可见的
-private:仅可以在声明所在类内部使用。私有对象无法从该类外部直接访问。
-default:没有明确指定访问级别,也称为包级私有访问权限。默认情况下,只允许同一个包内的其它类进行访问

5、Java中ArrayList和LinkedList区别是什么?

ArrayList和LInkedList是Java中两种不同的集合类,它们的区别主要体现在以下几个方面:

  1. 数据结构ArrayList是基于动态数组实现的,通过数组实现元素的存储和访问;而LinkedList则是基于双向链表实现的,通过链表节点实现元素的存储和访问。
  2. 插入和删除操作ArrayList在尾部进行插入和删除操作比较高效,因为它使用数组实现,可以直接在尾部进行元素的增删;而在中间或头部进行插入和删除操作时,由于需要移动元素,效率较低。而LinkedList在任意位置进行插入和删除操作效率较高,因为它只需要更改节点的指针即可。
  3. 随机访问ArrayList支持通过下标进行随机访问,可以通过索引快速定位元素;而LinkedLisk不支持直接通过下标访问,需要从头节点或尾节点开始遍历链表,直到找到对应位置的元素。
  4. 内存访问ArrayList在存储元素时需要预留一定的空间,当元素数超过预留空间时,需要进行动态扩容;而LinkedList则不需要进行扩容操作,但是每个节点需要存储额外的指针信息,相对于ArrayList来说占用的内存较多。

综上所述,如果需要频繁进行插入和删除操作,并且不需要频繁随机访问元素,可以选择使用LinkedList;如果需要频繁随机访问元素,可以选择使用ArrayList

6、Java中ArrayList扩容过程是什么?

  1. 在创建ArrayList对象时,默认会创建一个初始容量为10的数组
  2. 当添加新元素时,如果当前数组已满(即元素个数等于数组容量),则会触发扩容操作
  3. 扩容操作会创建一个新的数组,新数组的容量是原数组容量的1.5倍(JDK1.4之前为原容量的2倍)
  4. 将原数组中的元素逐个复制到新数组中。
  5. 更新ArrayList内部的引用指向新数组
  6. 新元素添加到新数组中

7、Java中HashMap底层实现是什么?

Java中HashMap底层实现是通过哈希表(HashTable)和链表(LinkedList)结合的方式来实现的。具体来说,HashMap内部维护了一个数组,数组的每个元素是一个链表的头节点。当我们往HashMap中插入键值对时,首先会根据键的哈希值计算出在数组中的位置,然后将该键值对插入到对应链表的末尾。如果发生哈希冲突,即多个键的哈希值相同时,会将新的键值对插入到链表的头部。当链表的长度超过一定阈值(默认为8),链表就会转化为红黑树,以提高查询效率。在进行查询操作时,根据键的哈希值找到对应链表或红黑树,然后再遍历链表或搜索红黑树,找到对应值。这种底层实现方式使得HashMap再插入、删除和查找操作上都具有较高的效率。

8、Java中ConcurrentHashMap支持多并发的原理是什么?

ConcurrentHashMap是Java中线程安全的哈希表实现,它支持多并发操作的原理主要有以下几点:

  1. 分段锁:ConcurrentHashMap内部将数据分成多个段,每个段都可以独立地进行加锁和解锁操作。这样不同的线程可以同时访问不同的段,从而提高并发能力。
  2. 锁分离:与传统的同步容器不同,ConcurrentHashMap的读操作并不需要加锁,多个线程可以同时进行读操作,只要写操作需要加锁。这样可以避免不必要的阻塞,提高了并发读的效率。
  3. CAS(比较并交换)操作:ConcurrentHashMap使用了CAS操作来保证线程安全。在并发写操作时,通过CAS操作来实现无锁的数据更新
  4. 红黑树:ConcurrentHashMap中的每个段内部使用了红黑树来存储数据,当链表长度超过阈值时,会将链表转化为红黑树,这样可以保证在最坏的情况下仍然有较高的性能。

9、HashMap原理?转换成红黑树条件?为什么这么设计?

HashMap是Java中常见的一种数据结构,它基于哈希表实现。具体原理如下:

  1. HashMap内部由一个数组和链表(或红黑树)组成。数组是HashMap的主体,用于存储键值对。链表和红黑树用于解决哈希冲突,提高查找效率。
  2. 添加一个键值对到HashMap中时,首先根据键的hashCode()方法计算出一个哈希值,然后通过哈希值与数组长度取模,得到在数组中的位置。如果该位置上已经存在其它键值对,就发生了哈希冲突
  3. 如果发生哈希冲突,会在该位置上的链表或红黑树上顺序查找键值对。如果键已经存在,则更新对应的值。如果键不存在,则在链表或红黑树的末尾添加新的键值对
  4. 链表长度超过阈值(默认为8)时,链表会转换为红黑树

转换为红黑树的条件如下:
-当链表长度达到8时,且当前数组长度大于等于64,HashMap会将链表转换为红黑树。
-当红黑树节点数量小于等于6时,HashMap会将红黑树转换为链表

这样设计的原因是,当链表长度过长时,查找效率会降低,因为需要遍历链表进行查找。而红黑树相比链表,具有更高效的查找、插入和删除操作,能够更好地提高HashMap的性能。同时,对于较小的链表,转换为红黑树的开销反而比链表更大,所以在节点数量小于等于6时,会将红黑树转换回链表,以节省内存空间

10、Java线程安全的HashMap?ConcurrentHashMap和HashTable的区别?ConcurrentHashMap原理?

Java线程安全的HashMap可以使用ConcurrentHashMap来实现。ConcurrentHashMap是Java并发包中的一个线程安全的哈希表实现,它比传统的HashTable和同步的HashMap具有更好的并发性能
ConcurrentHashMap和HashTable的区别如下:

  1. 锁机制ConcurrentHashMap使用了分段锁(Segment),每个Segment相当于一个小的HashTable,只锁住当前操作的Segement而不是整个HashTable;而HashTable在每次操作时都锁住整个HashTable
  2. 并发性ConcurrentHashMap允许多个线程同时读取,而写操作会锁住相关的Segment,使得在并发写入时性能更好;HashTable在写操作时需要锁住整个HashTable,导致并发写入性能较差。
  3. 扩容机制ConcurrentHashMap在扩容时只需要锁住相关的Segment,不影响其它Segment的读写操作,提高了并发性能;HashTable在扩容时需要锁住整个HashTable,导致其它线程无法读写,性能较差。

ConcurrentHashMap的原理是基于分段锁(Segment)实现的。它将整个哈希表分成多个小的HashTable(Segment),每个Segment独立地进行锁定和扩容操作。这样可以提高并发性能,允许多个线程同时读取,而写操作只需要锁定相关地Segment,不影响其它Segment的读写操作。同时ConcurrentHashMap使用CAS算法来保证并发操作的一致性和线程安全性。

二、Java字符串和集合

1、请解释Java中的String、StringBuilder和StringBuffer的区别?

String、StringBuilder和StringBuffer是Java用来操作字符串的类,在以下几个方面有所不同:

  1. 可变性String类是不可变类,即String对象在创建后其值不能被改变;而StringBuilder和StringBuffer类是可变类,提供了修改和拼接字符串方法。
  2. 线程安全行String是线程安全的StringBuilder是非线程安全的StringBuffer是线程安全但效率相对较低
  3. 性能效率由于StringBuilder不是线程安全且没有额外开销,在并发访问场景下比其它两者更高效。如果需要多个线程共享一个字符串缓存区,推荐使用StringBuffer类。
    总的来说,如果需要频繁修改字符串且涉及多线程操作,应使用StringBuffer;如果是单线程操作且需要频繁修改字符串,则选择StringBuilder;而若字符串内存不需要被修改,则使用String更为合适

2、Java String为什么是不可变的?为什么要设计成不可变?

Java中的String是不可变的,这是因为String类被设计成了不可变的对象。这意味着一旦一个String对象被创建,它的值就不能被修改。

不可变有以下几个原因:

  1. 线程安全:不可变的特性使得String对象在多线程环境中是安全的。因为它的值不可变,不会被其它线程修改,所以不需要同步控制
  2. 缓存哈希值:String类将哈希值缓存在对象中,因为它是不可变的,所以哈希值只需要计算一次,而不需要每次使用时重新计算。这样可以提高性能。
  3. 字符串池:Java中的字符串池是为了节省内存而设计的。不可变的String对象可以被共享并重复使用,避免了创建多个相同值得字符串对象。这样可以减少内存占用,提高性能。
  4. 安全性:字符串作为参数传递给一些敏感得API时,不可变的特性可以确保参数的值不会被修改,从而保证数据的安全性。

综述所述,Java中的String被设计成不可变的主要是为了提高性能、确保线程安全以及节省内存

3、Java集合类型?

Java集合类型有以下几种:

  1. List(列表):List是一个有序的集合,可以包含重复元素。常见的实现类有ArrayList和LinkedList。
  2. Set(集合):Set是一个不允许重复元素的集合。常见的实现类有HashSet和TreeSet。
  3. Map(映射):Map是一种键值对的集合,每个键只能对应一个值。常见的实现类有HashMap和TreeMap。
  4. Queue(队列):Queue是一种先进先出(FIFO)的集合。常见的实现类有LinkedList和PriorityQueue。
  5. Stack(栈):Stack是一种后进先出的集合。常见的实现类有Stack。
  6. Vector(向量):Vector是一个动态数组,与ArrayList类似,但是它是线程安全的。

三、JVM与垃圾回收

1、讲一下 JVM 的垃圾回收的相关概念。

Java 虚拟机的垃圾回收是 Java 内存管理的一个重要部分,它负责自动化地管理 Java 程序的内存,通过识别和回收不再使用的对象来释放内存。垃圾回收器在程序运行时进行,尽管开发者无法直接控制其精确的运行时间,但可以通过编写“内存友好”的代码以及调整 JVM 配置参数来影响其行为。

以下是关于 JVM 垃圾回收的一些基本概念:
对象的生命周期Java 对象的生命周期开始于创建(当使用 new 关键字时)并在不再有引用指向它们时结束。如果一个对象不再被引用,那么它就可能被垃圾回收。
堆(Heap)内存Java 对象存储在堆内存中。堆在 JVM 启动时创建,可以通过 JVM 参数调整其大小。
垃圾回收算法:垃圾回收器使用特定的算法来确定哪些对象可以被视为"垃圾"并进行回收。常见的垃圾回收算法有标记-清除、标记-压缩、复制、以及分代回收等。
停顿时间垃圾回收器在运行时,通常会导致 Java 应用程序的执行暂停,这种现象被称为“停顿时间”。减少停顿时间是垃圾回收器优化的一个重要目标。
分代回收Java 的垃圾回收器通常采用分代回收策略,将堆内存分为新生代和老年代。这种策略基于这样一个观察:大多数对象的生命周期都很短。
新生代新创建的对象首先放在新生代。新生代通常分为一个 Eden 区和两个 Survivor 区(S0和 S1)。大部分对象在 Eden 区被垃圾回收
老年代如果对象在新生代中存活了足够长的时间,它们会被移动到老年代。老年代的空间通常比新生代大,并且其垃圾回收频率较低
垃圾回收器:Java 提供了多种垃圾回收器,包括 Serial、Parallel、CMS、G1以及 ZGC等。每种垃圾回收器都有其特定的使用场景和优劣,选择哪种垃圾回收器取决于具体的应用需求。

2、JVM 常见调优方法有哪些?

内存分配扩大 JVM 堆的大小可以提供更多的空间给对象,减少垃圾回收(GC)的次数。使用-Xms 和-Xmx 参数可以分别设置堆的初始大小和最大大小。然而,分配过多的内存可能会导致更长的 GC 停顿时间,并可能影响其他进程的性能。

选择垃圾回收器:根据应用的需求和特性选择合适的垃圾回收器。例如,对于需要低延迟的实时系统,选择并发垃圾回收器(如 CMS 或 G1)可能是个好选择对于可以容忍更长 GC 停顿时间的批处理任务,使用并行垃圾回收器可能更为合适
调整新生代和老年代的比例:JVM 的堆内存被划分为新生代和老年代,其中新生代通常分为 Eden 区和两个 Survivor 区(S0和 S1)。这些区域的大小可以通过参数-XX:NewRatio,-XX:SurvivorRatio 进行调整。这种调整可以根据应用的对象生命周期进行,以减少 GC 的次数。
调整线程堆栈大小:使用-Xss 参数可以设置每个线程的堆栈大小。如果应用创建了大量的线程,减小线程堆栈大小可能会帮助减少内存消耗。
启用类数据共享:类数据共享可以加快 JVM 启动速度并减少内存消耗。可以通过-XX:+UseSharedSpaces 参数启用 CDS。
使用 JVM 内建工具进行监控和故障排查:JVM 提供了一些内建工具,如 JConsole, VisualVM, jstat 等,可以用于监控 JVM 的性能和资源使用情况,帮助定位和解决性能问题。

3、什么是JVM垃圾回收?Java中有几种垃圾回收算法?

JVM垃圾回收指的是当Java应用程序运行时,自动释放不再使用的对象内存空间,并进行资源回收和整理过程。JVM提供了几种垃圾回收算法:

  1. 标记-清除算法首先标记所有被引用对象,在清除阶段将未标记的对象释放
  2. 复制算法将内存分为相同大小的两块,每次只使用其中的一块。当一块内存用完了之后,将活着的对象复制到另一块内存上,并清除原来使用过的内存
  3. 标记-整理算法先标记所有被引用对象,然后将活着的对象移动到一端,最后清除边界以外的对象
  4. 分代收集算法根据对象生命周期划分为不同代,在垃圾回收时更关注年轻代,因为大多数新生的对象很快就会死去。这种方式减少了全局垃圾检查和处理时间。

4、Java的垃圾回收机制是什么?简要描述它的工作原理。

垃圾回收机制是Java自动管理内存的一种方式,它会自动释放不再被引用或无法访问到的对象所占用的内存。
工作原理如下:

  1. 标记阶段从根对象开始遍历所有可达对象,并标记为“活跃”状态
  2. 清理阶段遍历堆内存中所有已分配的对象,将未标记未“活跃”状态的对象清除出堆内存
  3. 压缩阶段:在清理完毕后,对堆进行整理,消除由于释放了一些空间而产生的碎片

四、Java内存管理与性能优化

1、Java的内存区域分为几个部分?

堆(Heap)存放对象实例的地方,包括新生代(Eden区,From Survivor区,To Survivor区)和老年代
方法区存储类的结构信息如运行时常量池,字段和方法数据等
虚拟机栈存储每个线程的执行信息,包括局部变量、操作数栈、动态链接和方法退出信息
本地方法栈为虚拟机使用到的Native方法服务
程序计数器指示当前线程正在执行的字节码指令

2、什么情况下Java新建的对象不存储在Eden中?

  1. 大对象直接进入老年代:所谓的“大对象”是指需要大量连续内存空间的Java对象。例如,很长的字符串或者大的数组。由于Eden区和Survivor区可能无法存放这样大的对象,所以大对象在新建时直接被分配到老年代中。
  2. 长期存活的对象进入老年代:Java的垃圾收集器假设大部分对象都是“照生暮死”的,所以采用了分代收集的方法。当Eden区中的对象在Minor GC(小型垃圾收集)后仍然存活,且年龄(被Minor GC清理的次数)达到一定值(默认15)时,这些对象会被移动到老年代中。这个年龄阈值可以通过-XX:MaxTenuringThreshold参数进行设置。

3、Java线程池的核心参数有哪些?

corePoolSize:线程池的基本大小,即在没有任务执行时线程池的大小,并且只有在工作队列满了的情况下,才会创建超出这个数量的线程。
maximunPoolSize线程池最大线程数。这是线程池可以容纳的最大线程数,超出这个数的线程会被拒绝。
workQueue当线程池中的线程都被使用时,新任务会被放在这个队列中等待被执行。这个参数通常是一个实现了BlockingQueue、LinkedBlockingQueue或SynchronousQueue。
threadFactory:用于创建新线程的工厂。使用这个工厂可以自定义如何创建线程,例如设置线程的名称、优先级等。
handler当线程池和工作队列都满了,用于处理被拒绝的任务。常见的实现有AbortPolicy(直接抛出异常)、CallerRunsPolicy(用调用者的线程执行任务)、DiscardPolicy(静默丢弃任务)和DiscardOldestPolicy(丢弃队列中最旧的任务)。
keepAliveTime当线程池中的线程数量超过corePoolSize时,这是多余的空闲线程在被终止前等待新任务的最长的时间
timeUnitkeepAliveTime参数的时间单位,如TimeUnit.SECONDS、TimeUnit.MILLISECONDS等。
这些参数共同决定了线程池的创建、运行和任务处理策略。

4、请解释下Java中的线程池是什么,如何使用线程池来提高程序的性能?

Java中的线程池是一种管理和复用线程的机制,可以通过预先创建、管理和重复利用线程对象来优化多线程程序的性能。使用线程池可以减少频繁创建和销毁线程带来的开销,并且可以控制同时执行任务的最大数量
具体使用方法如下:

  1. 使用’ExecutorService’接口提供的’newFixedThreadPool’方法初始化一个固定大小的线程池
  2. 创建实现了’Runnable’接口的任务
  3. 将任务提交给线程池处理,调用’submit()'方法提交任务
  4. 线程池会自动分配可用于处理任务的工作线程,并在执行完后将其放回到缓存队列中等待新任务
    优点:使用线程池机制可以避免因频繁创建和销毁大量额外开销,能够高效触发系统资源利用率;同时,还可方便地控制并发协同与资源消耗。

五、Java异常处理和类加载

1、请解释Java中的异常处理机制,包括checked exception和unchecked exception?

Java的异常处理机制适用于处理程序运行时可能出现的错误和异常情况。Java中的异常可分为两种类型:checked exception(被检查的异常)和unchecked exception(未被检查的异常)
-Checked Exception:这些在编译时由编译器强制要求进行捕获或声明抛出。例如,‘IOException’、'SQLException’等。如果不对这些异常进行try-catch捕获或throws声明抛出,代码将无法通过编译。
-Unchecked Exception:这些是在运行时发生且不需要显式捕获或声明抛出。常见的Unchecked Exceptions包括"NullPointerException",'ArrauIndexOutOfBoundsException’等。
对于Checked Exceptions,开发者必须根据具体情况选择合适的方式来处理它们,比如使用try-catch快来捕获并处理该类异常;而对于Unchecked Exceptions通常可以通过良好的编程实践避免其发生,或者选择适当层次向上抛出以由调用方去负责处理

2、JVM中一个类加载的过程是什么样子?

  1. 加载:类加载的第一步是加载,即通过类的全限定名找到对应的二进制字节码文件。这个过程可以通过类加载器完成,类加载器会根据类的名称定位到类文件,并将其读取到内存中
  2. 验证:在加载完成后,JVM会对加载的类进行验证,确保类文件的字节码符合JVM规范,不会危害JVM的安全。验证的过程包括文件格式验证、元数据验证、字节码验证以及符号引用验证。
  3. 准备:在验证通过后,JVM会为类的静态成员遍历分配内存空间,并设置默认初始值。这个过程并不会为实例变量分配空间,只是为静态变量分配。
  4. 解析:解析阶段是将符号引用替换为直接引用的过程。符号引用是一种编译时的引用,直接引用是在运行时可直接指向内存地址的引用。解析过程包括将常量池中的符号引用替换为直接引用、将类、方法、字段等符号解析为具体的内存地址
  5. 初始化:在准备阶段完成后,JVM会开始执行类的初始化过程。类初始化时会执行类的静态代码块和静态变量的赋值操作。这个过程是类加载的最后一个阶段。
  6. 使用:类加载完成后,就可以使用该类创建对象、调用方法等操作。

六、Java高级特性

1、Java中Synchronized的底层原理是什么?

Synchronized是Java中用于实现线程同步的关键字,它的底层原理是通过对象监视器(也称为内部锁或监视锁)来实现的。
当一个线程进入synchronized代码块时,它会尝试获取对应对象的监视器。如果该监视器没有被其它线程占用,则该线程获取到监视器并执行代码块中的逻辑。如果监视器已经被其它线程占用,该线程就会进入阻塞状态,等待监视器的释放
在Java虚拟机中,每个对象都有一个与之关联的监视器锁。当一个线程获取到该对象的监视器锁时,其它线程就无法同时获取该对象的监视器锁,它们会被阻塞直到锁被释放。
在方法上适用synchronized关键字时,它会对该方法的整个代码块进行加锁,以保证同一时间只有一个线程可以执行该方法。而在代码块上使用synchronized关键字时,它只会对该代码块进行加锁,其它线程仍然可以同时执行其它非同步代码块
需要注意的是,synchronized关键字会引入一定的性能开销,因为每次进入synchronized代码块或方法时,都会进行加锁或解锁的操作。因此,在使用synchronized时需要权衡线程安全和性能之间的平衡。

2、泛型?

泛型是Java中一种参数化类型的概念,它允许我们在编写类、接口和方法时使用未知的数据类型。通过使用泛型,我们可以创建通用的代码,可以在不同的数据类型上进行操作,提高代码的复用性和类型安全性。泛型使用尖括号<>来定义,可以用于类、接口和方法的声明和实例化中。在使用泛型时,可以指定具体的数据类型,也可以使用通配符来表示未知的数据类型

3、常用的反射方法?

常用的反射方法有:

  1. 获取Class对象:通过Class.forName(),对象.getClass()、类名.class等方式获取一个类的Class对象。
  2. 创建实例:通过Class对象的newInstance()方法创建类的实例。
  3. 获取类的成员变量:通过Class对象的getField()、getDeclaredField()等方法获取类的公共或私有成员变量。
  4. 获取类的方法:通过Class对象的getMethod()、getDeclaredMethod()等方法获取类的公共或私有方法。
  5. 调用方法:通过Method对象的invoke()方法调用方法。
  6. 修改成员变量的值:通过Field对象的set()方法修改成员变量的值。
  7. 调用构造函数:通过Class对象的getConstructor()、getDeclaredConstructor()等方法获取类的公共或私有构造函数,并通过Constructor对象的newInstance()方法创建类的实例。
    这些方法可以在运行时动态地获取和操作类的信息,使得我们可以在不知道具体类名地情况下,通过反射机制来调用类地方法、访问成员变量等

4、Java中深拷贝和浅拷贝的区别是什么?

在Java中,深拷贝和浅拷贝是对于对象复制的两种不同方式。

浅拷贝:是创建一个新对象,该对象的实例变量与原对象相同,如果有引用类型的成员变量,浅拷贝仅仅复制了引用而不是创建新的对象。这意味着原对象和浅拷贝对象会共享相同的引用类型成员变量,对其中一个对象的修改会影响到另一个对象

深拷贝:是创建一个新对象,该对象的所有实例变量都会被复制,并且会为引用类型的成员变量创建新的对象。这意味着原对象和深拷贝对象是完全独立的,对其中一个对象的修改不会影响到另一个对象
在Java中,可以通过实现Cloneable接口和重写clone()方法来实现浅拷贝。对于深拷贝,可以通过实现Serializable接口并使用对象序列化和反序列化来实现,或者通过手动复制所有引用类型成员变量的值来实现
需要注意的是,如果引用类型成员变量也实现了Cloneable接口并进行了深拷贝,那么在进行深拷贝时需要在clone()方法中递归调用成员变量clone()方法,确保所有层级的引用类型对象都被正确复制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/737461.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

五、OpenAI实战之Assistants API

在8线小城的革委会办公室里&#xff0c;黑8和革委会主任的对话再次展开。 黑8&#xff1a;主任&#xff0c;您知道吗&#xff1f;除了OpenAI API&#xff0c;现在还有一项新的技术叫做Assistants API&#xff0c;它可以帮助我们更好地进行对话和沟通。 主任&#xff1a;Assis…

性能优化-卡牌项目渲染优化

优化的方向 CPU 影响帧率 GPU 影响帧率 内存 超了会崩 显存 显存超了画面会异常&#xff0c;甚至可能导致游戏崩溃 带宽 影响耗电 分辨率 设备性能不行又要求流畅&#xff0c;降低目标渲染分辨率&#xff0c;立竿见影&#xff0c;但是会牺牲画质 场景 1 使用烘焙…

Vue:自动按需导入element-plus图标,动态导入

在 Vue3 中&#xff0c;component 动态组件的 is 属性必须绑定的是组件实例&#xff0c;而不是组件名字 所以需要在JS里面导入组件&#xff0c;创建一个对象存储&#xff0c;利用键值对&#xff0c;返回组件 如何配置自动导入看上一篇&#xff1a;https://blog.csdn.net/ruanc…

Java网络编程详解

目录 网络编程 1、概述 2、网络通信的要素 3、IP 4、端口 5、通信协议 6、TCP 文件上传 Tomcat 7、UDP 单方发送单方接受 双方发送接收 8、URL URL测试 URL下载网络资源 网络编程 1、概述 信件&#xff1a; 计算机网络&#xff1a; 计算机网络是指将地理位置不…

WPF —— TextBlock、LineBreak RadioButton控件详解

一:TextBlock 1&#xff1a;TextBlock 简介 <LineBreak/> 换行 显示文本 标签内容和content属性共存 2、TextBlock 常用的属性 Foreground&#xff1a;TextBlock的文本内容的颜色。 Background&#xff1a;背景&#xff0c;获取或设置要用于填充内容区域背景的 Brush…

冒泡排序的理解与实现【C语言、C++、java】

冒泡排序介绍 冒泡排序(Bubble Sort)&#xff0c;又被称为气泡排序或泡沫排序。 它是一种较简单的排序算法。它会遍历若干次要排序的数列&#xff0c;每次遍历时&#xff0c;它都会从前往后依次的比较相邻两个数的大小&#xff1b;如果前者比后者大&#xff0c;则交换它们的位…

一体机电脑辐射超标整改

电脑一体机是目前台式机和笔记本电脑之间的一个新型的市场产物&#xff0c;它将主机部分、显示器部分整合到一起的新形态电脑&#xff0c;该产品的创新在于内部元件的高度集成。随着无线技术的发展&#xff0c;电脑一体机的键盘、鼠标与显示器可实现无线链接&#xff0c;机器只…

美国站群服务器使用技巧与注意事项

美国站群服务器使用技巧与注意事项有哪些?RAKsmart小编为您整理发布美国站群服务器使用技巧与注意事项&#xff0c;希望对您有帮助。 美国站群服务器的使用技巧主要包括远程管理、灵活配置和备份还原&#xff0c;具体如下&#xff1a; 1. **远程管理**&#xff1a;用户可以通过…

洛谷 P1036 [NOIP2002 普及组] 选数

题目描述 已知 nn 个整数 x_1,x_2,\cdots,x_nx1​,x2​,⋯,xn​&#xff0c;以及 11 个整数 kk&#xff08;k<nk<n&#xff09;。从 nn 个整数中任选 kk 个整数相加&#xff0c;可分别得到一系列的和。例如当 n4n4&#xff0c;k3k3&#xff0c;44 个整数分别为 3,7,12,1…

计算机网络-第5章 运输层(2)

5.6 TCP可靠传输实现 以字节为单位的滑动窗口。 发送窗口已满&#xff0c;停止发送。 发送和接收的数据都来自缓存。 超时重传时间RTO选择&#xff1a;自适应算法&#xff0c; 选择确认SACK&#xff1a;只传送缺少的数据。大多数实现还是重传所有未被确认的数据块。 5.7 TCP的…

Spring 初学者遇到的问题

TagLibraryValidator Spring 实战 5.2 中有个表单需要在 jsp 中遍历数组&#xff0c;添加&#xff1a;<% taglib uri"http://java.sun.com/jsp/jstl/core" prefix"c" %>&#xff0c;访问时发现有些问题&#xff1a; java.lang.NoClassDefFoundError…

Java线程锁之Lock的使用

Lock 的使用 Lock 是java 1.5 中引入的线程同步工具&#xff0c;它主要用于多线程下共享资源的控制。本质上Lock 仅仅是一个接口&#xff0c; 可以通过显式定义同步锁对象来实现同步&#xff0c;能够提供比synchronized 更广泛的锁定操作&#xff0c;并支持多个相关的 Lock接…

LLM 推理优化

LLM 推理服务重点关注两个指标&#xff1a;吞吐量和时延&#xff1a; 吞吐量&#xff1a;主要从系统的角度来看&#xff0c;即系统在单位时间内能处理的 tokens 数量。计算方法为系统处理完成的 tokens个数除以对应耗时&#xff0c;其中 tokens 个数一般指输入序列和输出序列长…

掌握Mongodb,看完这篇文章就够了

目录 1.概念 2.操作 2.1数据库操作 2.2集合操作 2.3数据操作 3.查询 4.常用技术 5.python与MongoDB 1.概念 MongoDB是一种非关系型数据库&#xff08;NoSQL&#xff09;&#xff0c;它以灵活的文档存储格式&#xff08;BSON&#xff09;和强大的查询能…

MinGW-w64的下载与安装

文章目录 1 下载2 安装3 配置环境变量4 验证 1 下载 官网地址&#xff1a;https://www.mingw-w64.org/github地址&#xff1a;https://github.com/niXman/mingw-builds-binaries/releases windows下载 跳转github下载 版本号选择&#xff1a;13.2.0是GCC的版本号&#xff1b…

如何避免MYSQL主从延迟带来的读写问题?

在MYSQL 部署架构选型上&#xff0c;许多公司都会用到主从读写分离的架构&#xff0c;如下是一个一主一从的架构&#xff0c;主库master负责写入&#xff0c;从库slave进行读取。 但是既然是读写分离&#xff0c;必然会面临这样一个问题&#xff0c;当在主库上进行更新后&#…

010-$nextTick

$nextTick 1、问题2、$nextTick3、应用场景 1、问题 Vue 实现响应式&#xff0c;在 data 更新后&#xff0c;一定时间内&#xff0c;没有继续操作DOM&#xff0c;然后会触发浏览器渲染引擎去更新DOM&#xff0c;更新DOM也是需要时间的&#xff0c;所以 data 更新引起的 DOM更新…

FreeRTOS学习第9篇--队列介绍

目录 FreeRTOS学习第9篇--队列介绍1. 数据传输的方法1.1 任务之间如何传输数据1.2 队列的本质 2. 队列的工作原理和实现2.1 创建队列2.2 向队列发送数据2.3 从队列接收数据 3. 使用队列进行任务间的通信3.1 通信示例3.2 同步示例 结论 FreeRTOS学习第9篇–队列介绍 本文目标&a…

《C++游戏编程入门》第1章 类型、变量与标准I/O: Lost Fortune

《C游戏编程入门》第1章 类型、变量与标准I/O: Lost Fortune 1.1.1 使用C编写游戏1.1.2 生成可执行文件1.1.3 错误处理 1.2 第一个C程序01.game_over.cpp01.game_over2.cpp01.game_over3.cpp 1.4 使用算术运算符01.expensive_calculator.cpp 1.5 声明和初始化变量01.game_stats…

minimap2参数设置+解释【全网最详细】

Indexing -H: 使用同源聚合的k-mer(适用于PacBio数据) -k INT: k-mer的大小(不超过28)【默认值:15】 -W INT: minimizer窗口大小【默认值:10】 -I NUM: 每个~NUM输入碱基分割索引【默认值:4G】 -d FILE: 将索引转储到文件中 Mapping: -f FLOAT: 过滤掉顶部FLOAT比例的重…