目录
- 基础
- 1.JDK和JRE的区别
- 2.Java为什么不直接实现lterator接口,而是实现lterable?
- 3.简述什么是值传递和引用传递?
- 4.概括的解释下Java线程的几种可用状态?
- 中级
- 1.简述Java同步方法和同步代码块的区别 ?
- 2.HashMap和Hashtable有什么区别?
- 3.简述Java堆的结构? 什么是堆中的永久代(Perm Gen space)?
- 4.简述 Dubbo 和 Spring Cloud 有什么区别 ?
- 高级
- 1.为什么集合类没有实现Cloneable和Serializable接口?
- 2.Java中的HashMap的工作原理是什么?
- 系列文章
- 版本记录
基础
1.JDK和JRE的区别
JDK:全称Java Development Kit,翻译为Java开发工具包,提供Java的开发和运行环境,是整个Java的核心。目前各大主流公司都有自己的jdk,比如oracle jdk(注意,生产环境使用时需要注意法律风险)、openjdk(目前生产环境主流的jdk)、dragonwell(阿里家的jdk,在金融电商物流方面做了优化)、zulujdk(巨硬家的jdk)等等
JRE:全称Java Runtime Environment,Java运行时环境,为Java提供运行所需的环境
总的来说,JDK包含JRE,JAVA源码的编译器javac,监控工具jconsole,分析工具jvisualvm
总结,如果你需要运行Java程序(类似我的世界那种),只需要安装JRE;如果你需要程序开发,那么需要安装JDK就行了,不需要再重复安装JRE。
2.Java为什么不直接实现lterator接口,而是实现lterable?
Iterator是迭代器类,而Iterable是接口。好多类都实现了Iterable接口,这样对象就可以调用iterator()方法。
看一下JDK中的集合类,比如List一族或者Set一族,都是实现了Iterable接口,但并不直接实现Iterator接口。仔细想一下这么做是有道理的。
因为Iterator接口的核心方法next()或者hasNext() 是依赖于迭代器的当前迭代位置的。如果Collection直接实现Iterator接口,势必导致集合对象中包含当前迭代位置的数据(指针)。
当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。
除非再为Iterator接口添加一个reset()方法,用来重置当前迭代位置。
但即时这样,Collection也只能同时存在一个当前迭代位置。而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器。多个迭代器是互不干扰的。
3.简述什么是值传递和引用传递?
值传递:方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参 数的值。
引用传递:也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。
4.概括的解释下Java线程的几种可用状态?
线程在执行过程中,可以处于下面几种状态:
1 就绪(Runnable):线程准备运行,不一定立马就能开始执行。
2 运行中(Running):进程正在执行线程的代码。
3 等待中(Waiting):线程处于阻塞的状态,等待外部的处理结束。
4 睡眠中(Sleeping):线程被强制睡眠。
5 I/O阻塞(Blocked on I/O):等待I/O操作完成。
6 同步阻塞(Blocked on Synchronization):等待获取锁。
7 死亡(Dead):线程完成了执行。"
中级
1.简述Java同步方法和同步代码块的区别 ?
区别:
同步方法默认用this或者当前类class对象作为锁;
同步代码块可以选择以什么来加锁,比同步方法要更细颗粒度,我们可以选择只同步会发生同步问题的部分代码而不是整个方法;
同步方法使用关键字 synchronized修饰方法,而同步代码块主要是修饰需要进行同步的代码,用 synchronized(object){代码内容}进行修饰;
【为何使用同步?】
java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(增删改查),将会导致数据的不准确,相互之间产生冲突。类似于在atm取钱,银行数据确没有变,这是不行的,要存在于一个事务中。因此加入了同步锁,以避免在该线程没有结束前,调用其他线程。从而保证了变量的唯一性,准确性。
1.同步方法:
即有synchronized (同步,美 ['sɪŋkrənaɪzd] ) 修饰符修饰的方法。
由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用给方法前,要获取内置锁,否则处于阻塞状态。
例:public synchronized getMoney(){}
注:synchronized修饰静态方法,如果调用该静态方法,将锁住整个类。
2.同步代码块
即有synchronized修饰符修饰的语句块,被该关键词修饰的语句块,将加上内置锁。实现同步。
例:synchronized(Object o ){}
同步是高开销的操作,因此尽量减少同步的内容。通常没有必要同步整个方法,同步部分代码块即可。
同步方法默认用this或者当前类class对象作为锁。
同步代码块可以选择以什么来加锁,比同步方法要更颗粒化,我们可以选择只同步会发生问题的部分代码而不是整个方法
2.HashMap和Hashtable有什么区别?
📌 试题回答参考思路:
HashMap和Hashtable区别:
1:HashMap和Hashtable都实现了Map接口,因此很多特性非常相似。但是,他们有以下不同点:
2:HashMap允许键和值是null,而Hashtable不允许键或者值是null。
3:Hashtable是同步的,而HashMap不是。因此,HashMap更适合于单线程环境,而Hashtable适合于多线程环境。
4:HashMap提供了可供应用迭代的键的集合,因此,HashMap是快速失败的。另一方面,Hashtable提供了对键的列举(Enumeration)。
5:一般认为Hashtable是一个遗留的类。
3.简述Java堆的结构? 什么是堆中的永久代(Perm Gen space)?
📌 试题回答参考思路:
1:堆结构
JVM的堆是运行时数据区,所有类的实例和数组都是在堆上分配内存。它在JVM启动的时候被创建。对象所占的堆内存是由自动内存管理系统也就是垃圾收集器回收。
堆内存是由存活和死亡的对象组成的。
存活的对象是应用可以访问的,不会被垃圾回收。
死亡的对象是应用不可访问尚且还没有被垃圾收集器回收掉的对象。一直到垃圾收集器把这些对象回收掉之前,他们会一直占据堆内存空间。
2:永久代(Perm Gen space)
永久代主要存在类定义,字节码,和常量等很少会变更的信息。并且永久代不会发生垃圾回收,如果永久代满了或者超过了临界值,会触发完全垃圾回收(Full Gc)
永久代中一般包含:
类的方法(字节码…)
类名(Sring对象)
.class文件读到的常量信息
class对象相关的对象列表和类型列表 (e.g., 方法对象的array)
JVM创建的内部对象
JIT编译器优化用的信息
而在java8中,已经移除了永久代,新加了一个叫做元数据区的native内存区。
3:元空间
元空间和永久代类似,都是对JVM中规范中方法的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存的限制。类的元数据放入native memory,字符串池和类的静态变量放入java堆中。这样可以加载多少类的元数据就不再由MaxPermSize控制,而由系统的实际可用空间来控制。
4:采用元空间而不用永久代的原因:
为了解决永久代的OOM问题,元数据和class对象存放在永久代中,容易出现性能问题和内存溢出。
类及方法的信息等比较难确定其大小,因此对于永久代大小指定比较困难,大小容易出现永久代溢出,太大容易导致老年代溢出(堆内存不变,此消彼长)。
永久代会为GC带来不必要的复杂度,并且回收效率偏低。
4.简述 Dubbo 和 Spring Cloud 有什么区别 ?
📌 试题回答参考思路:
SpringCloud与Dubbo的区别:
1:两者都是现在主流的微服务框架,但却存在不少差异:
2:初始定位不同:SpringCloud定位为微服务架构下的一站式解决方案;Dubbo 是 SOA 时代的产物,它的关注点主要在于服务的调用和治理
3:生态环境不同:SpringCloud依托于Spring平台,具备更加完善的生态体系;而Dubbo一开始只是做RPC远程调用,生态相对匮乏,现在逐渐丰富起来。
4:调用方式:SpringCloud是采用Http协议做远程调用,接口一般是Rest风格,比较灵活;Dubbo是采用Dubbo协议,接口一般是Java的Service接口,格式固定。但调用时采用Netty的NIO方式,性能较好。
组件差异比较多,例如SpringCloud注册中心一般用Eureka,而Dubbo用的是Zookeeper
5:SpringCloud生态丰富,功能完善,更像是品牌机,Dubbo则相对灵活,可定制性强,更像是组装机。相关资料:
6:SpringCloud:Spring公司开源的微服务框架,SpirngCloud 定位为微服务架构下的一站式解决方案。
7:Dubbo:阿里巴巴开源的RPC框架,Dubbo 是 SOA 时代的产物,它的关注点主要在于服务的调用,流量分发、流量监控和熔断
高级
1.为什么集合类没有实现Cloneable和Serializable接口?
📌 试题回答参考思路:
1.Cloneable接口作用是将一个对象的属性值复制给另一个对象,而不是对象的一个引用。
2.Serializable接口作用(这个罗嗦一下)
序列化的用途
1.有时候,如果想让一个对象持久的存储下来(存到磁盘),或者是进行远程的对象调用,那就要使用序列化实现这些作用。我们必须对所有支持持久化存储的类实现Serializable接口,读取的时候也要进行反序列化。
2.对于jvm来说,进行持久化的类必须有个标记,就是实现Serializable接口,关联serialVersionUID,这个变量就是在反序列话中确定用那个类加载这个对象。
3.值得主意的是,持久化的数据都是存在在java堆中,static类型的数据存在在方法区中,不能被持久化。如果不想让某个成员变量持久化,变量前面用transient关键字
4.当然序列化的那个serialVersionUID这个还可以进行自定义
为什么集合类中不实现上面两个接口呢?
其实不难看出,Cloneable是复制对象的,序列化也是针对对象的操作,集合类只是管理对象的一个工具,就好比说list能够线性的管理对象,set集合能够对对象去重等,这些集合类都是针对与为管理对象而产生的。
其实,着两个接口都是针对真是的对象,而不是集合类这样的管理对象的对象。这个从语义上就是集合类的Cloneable接口和Serializable接口
应该又集合中具体的类型实现,而不是又集合类来实现序列化。
假设集合类实现了这两个接口,如果我要生成一个不需要序列化,不需要clone的集合,那么集合类就强行实现,这样有违集合的设计原则。
2.Java中的HashMap的工作原理是什么?
📌 试题回答参考思路:
在 Java 中,HashMap 属于常用的基于哈希表实现的键值对存储结构,它采用了数组+链表/红黑树的方式进行实现。下面将从以下几个方面介绍 HashMap 的实现原理:哈希函数、数组+链表的实现、扩容机制。
一、哈希函数
HashMap 的核心思想是哈希映射,即将任意长度的输入(即键)通过哈希函数变换成固定长度的输出(即该键在数组中的索引位置),并将该键和值存储到找到的索引位置处。具体来说,哈希函数需要满足以下两个条件:
散列均匀。这意味着不同的键应该有不同的哈希值,并且此哈希值在数组中分布均匀,也就是不要让大量哈希值都集中到一个区域。
计算速度快。为了避免计算哈希值过于缓慢,需要使用高效的哈希函数。
在 Java 中,Java 8 以前使用的是传统的拉链法解决哈希冲突(即多个键映射到同一个数组下标的情况),而 Java 8 之后为了进一步提升性能,采用了链表和红黑树相结合的方式来处理哈希冲突。
二、数组+链表的实现
HashMap 的内部结构是一个数组,数组中每个元素称为桶。桶里放的元素类型是 Entry 类型的对象,该类包含了键和值。当 HashMap 中加入一个键值对时,它会首先根据键获取其哈希码(即通过根据 hash() 方法计算得到),然后通过这个哈希码在数组中找到相应桶,并把键值对存储在桶中。
如果多个键映射到同一索引位置上,就需要通过链表将它们串联起来,而 JDK 1.8 之前版本中采用的则是最基础的链式结构。但随着链表长度的增加,查询效率会逐渐变低,甚至还可能造成链表成环并导致死循环等情况,因此,Java 8 引入了一种新的机制:当链表长度超过阈值(默认为 8)时,会将链表转化为红黑树,以提高查询效率。在使用红黑树优化后,HashMap 的查询性能会更进一步的提升。
系列文章
内容 | 地址 链接 |
---|---|
JAVA介绍 | Linux (实战)常用命令 |
版本记录
- 2023-10-24 第一版