这里仅补充牛客专刊《Java开发岗高频面试题全解析》提到但是未展开讲解的知识点,个人收录向。
String,StringBuffer与StringBuilder的区别??
林木声-Java泛型理解
Java总结篇系列:Java泛型
java基础---->Serializable的使用
java高级---->Serializable的过程分析
Java中equals()和HashCode()的关系
1.指针
JAVA语言让编程者无法找到指针来直接访问内存无指针,并且增添了自动的内存管理功能,从而有效地防止了c/c++语言中指针操作失误,如野指针所造成的系统崩溃。但也不是说JAVA没有指针,虚拟机内部还是使用了指针,只是外人不得使用而已。这有利于Java程序的安全。
2.多重继承
c++支持多重继承,这是c++的一个特征,它允许多父类派生一个类。尽管多重继承功能很强,但使用复杂,而且会引起许多麻烦,编译程序实现它也很不容易。Java不支持多重继承,但允许一个类继承多个接口(extends+implement),实现了c++多重继承的功能,又避免了c++中的多重继承实现方式带来的诸多不便。
3.数据类型及类
Java是完全面向对象的语言,所有函数和变量部必须是类的一部分。除了基本数据类型之外,其余的都作为类对象,包括数组。对象将数据和方法结合起来,把它们封装在类中,这样每个对象都可实现自己的特点和行为。而c++允许将函数和变量定义为全局的。此外,Java中取消了c/c++中的结构和联合,消除了不必要的麻烦。
4.自动内存管理
Java程序中所有的对象都是用new操作符建立在内存堆栈上,这个操作符类似于c++的new操作符。下面的语句由一个建立了一个类Read的对象,然后调用该对象的work方法: Read r=new Read(); r.work();语句Read r=new Read();在堆栈结构上建立了一个Read的实例。Java自动进行无用内存回收操作,不需要程序员进行删除。而c++中必须由程序员释放内存资源,增加了程序设计者的负担。Java中当一个对象不被再用到时,无用内存回收器将给它加上标签以示删除。JAVA里无用内存回收程序是以线程方式在后台运行的,利用空闲时间工作。
5.操作符重载
Java不支持操作符重载。操作符重载被认为是c++的突出特征,在Java中虽然类大体上可以实现这样的功能,但操作符重载的方便性仍然丢失了不少。Java语言不支持操作符重载是为了保持Java语言尽可能简单。
6.预处理功能
Java不支持预处理功能。c/c++在编译过程中都有一个预编译阶段,即众所周知的预处理器。预处理器为开发人员提供了方便,但增加丁编译的复杂性。JAVA虚拟机没有预处理器,但它提供的引入语句(import)与c++预处理器的功能类似。
7. Java不支持缺省函数参数,而c++支持 在c中,代码组织在函数中,函数可以访问程序的全局变量。c++增加了类,提供了类算法,该算法是与类相连的函数,c++类方法与Java类方法十分相似,然而,由于c++仍然支持c,所以不能阻止c++开发人员使用函数,结果函数和方法混合使用使得程序比较混乱。 Java没有函数,作为一个比c++更纯的面向对象的语言,Java强迫开发人员把所有例行程序包括在类中,事实上,用方法实现例行程序可激励开发人员更好地组织编码。
8. 字符串
c和c++不支持字符串变量,在c和c++程序中使用Null终止符代表字符串的结束,在Java中字符串是用类对象(String和StringBuffer)来实现的,这些类对象是Java语言的核心,用类对象实现字符串有以下几个优点: (1)在整个系统中建立字符串和访问字符串元素的方法是一致的; (2)字符串类是作为Java语言的一部分定义的,而不是作为外加的延伸部分; (3)Java字符串执行运行时检空,可帮助排除一些运行时发生的错误; (4)可对字符串用“+”进行连接操作。
9.“goto“语句
“可怕”的goto语句是c和c++的“遗物”,它是该语言技术上的合法部分,引用goto语句引起了程序结构的混乱,不易理解,goto语句子要用于无条件转移子程序和多结构分支技术。鉴于以上理由,Java不提供goto语句,它虽然指定goto作为关键字,但不支持它的使用,使程序简洁易读。
10.类型转换
在c和c++中有时出现数据类型的隐含转换,这就涉及了自动强制类转换问题。例如,在c++中可将一浮点值赋予整型变量,并去掉其尾数。Java不支持c++中的自动强制类型转换,如果需要,必须由程序显式进行强制类型转换。
11.异常
JAVA中的异常机制用于捕获例外事件,增强系统容错能力 try{//可能产生异常的代码 }catch(exceptionType name){ //处理 } 其中exceptionType表示异常类型。而C++则没有如此方便的机制。
java静态与非静态区别
Java中equals和==的区别
一致性哈希算法原理
10分钟带你了解一致性hash算法
CountDownLatch和CyclicBarrier的使用和区别
happen-before原则
我认为并发是难度较深的知识点了,死记是不行的,必须理解原理。下面讲下我的个人理解
首先要理解这是多CPU执行的并发多线程,以及其内存模型
线程对共享变量的写操作不是立马反映到主内存中的,而是先写到线程专有的本地内存(缓存)中,比方说有一个共享变量a=1,线程A将其值变为a=2,但是这时a=2,这个结果只存在A的本地内存里面,主内存中的a仍然是a=1,线程B中的a的值也是a=1,这时候线程B读到的就是脏数据了,为了避免这种情况发生,就需要制定一个先后顺序,使A线程a=2,的这个结果对B可见。这就是happened-before原则。(纯属个人理解,如果你觉得有错误,你的指正将对我有很大的帮助。)
Java虚拟机对内部锁的四种优化方式
An Introduction to Lock-Free Programming(英文,晦涩)
多个生产者和多个消费者,一样可以做到免锁访问,但要使用原子操作。这里的意思应该是不用原子操作级别的免锁,理由也很简单,生产者和消费者需要修改的位置是分开的(生产者加在尾部,消费者从头部消费),且只有一个读一个写,不会发生冲突。所以只有一点需要关注,就是尾部指针和头部指针每次需要比较以避免生产溢出或者过度消费,而简单变量的读操作都是原子的。
类似的一个概念叫CopyOnWrite,复制一份,修改完后,替换回去时只需替换一个指针或引用,锁住的粒度非常小。但有可能还有线程持有的是旧的指针,因此旧的副本需要延迟释放。
直译:比较和交换 ,修改值时同时保留其旧的值 ,比方说现有a=1, 线程A欲将其修改成2,这时线程A有两个值,预期旧值1,新值2,这时候将a=1再和a原来位置的值做比较,若a没有被其他线程篡改,则将2写回去,返回成功;若被篡改(即预期值 != 原有值),则不对a的值做修改,返回失败。
什么是CAS机制?如何解决ABA问题?
原文较长,我提取一下我认为需要了解的
答:当一个值从A更新为B,再从B更新为A,普通CAS机制会误判通过检测。解决方案是使用版本号,通过比较值和版本号才判断是否可以替换。
在Java中,AtomicStampedReference类就实现了用版本号做比较的CAS机制。
我们假设一个取款机的例子。假如有一个遵循CAS机制的取款机。小肖有100元存款,需要提取50元。但由于取款机硬件出现了问题,导致取款操作同时提交了两遍,开启了两个线程,两个线程都是获取当前值100元,要更新成50元。
理想情况下,应该一个线程更新成功,一个线程更新失败,小肖的存款只扣除一次,余额为50.
线程1首先执行成功,把余额100更新为50,同时线程2由于某种原因陷入了阻塞状态,这时候,小肖的妈妈汇款给了小肖50元。
线程2仍然是阻塞状态,线程3此时执行成功,把余额从50改成了100.
这时候,线程2恢复运行,由于之前阻塞的时候获得了”当前值“100,并且经过compare检测,此时存款也的确是100元,所以成功把变量值从100更新成50.
原本线程2应当提交失败,小肖的正确余额应该保持100元,结果由于ABA问题提交成功了。
真正要做到严谨的CAS机制,我们在compare阶段不仅需要比较内存地址V中的值是否和旧的期望值A相同,还需要比较变量的版本号是否一致。
我们仍然以刚才的例子来说明,假设地址V中存储着变量值A,当前版本号是01.线程1获取了当前值A和版本号01,想要更新为B,此时线程1陷入了阻塞状态。
这时候,内存地址V中的变量进行了多次改变,版本号提升到03,但是变量值仍然是A。
随后,线程1恢复运行,进行compare操作。首先经过比较,内存地址V中的值与当前值A相同,但是版本号不相同,所以这一次更新失败。
什么是AQS(AbstractQueuedSynchronizer)?
AQS(AbstractQueuedSynchronizer)的实现原理
啊?这~