❤1、Java基础
1、为什么重写equals还要重写hashcode
(1)两个对象相等,hashCode则一定相等;(2)hashCode相等,两个对象不一定相等;为了提高程序的效率,先进行hashcode的比较,如果不同,不必要进equals的比较了。如果不重写hashCode()会降低Map等集合的索引速度。
2、说一下map的分类和常见的情况
HashMap: 线程不安全,底层采用数组 + 链表 + 红黑数组成,允许一条记录的为null。
HashTable:线程安全,不允许键值为空
LinkedHashMap: 保证了元素插入的顺序,即输入顺序和输出顺序一致。遍历速度只与数据多少有关系。
TreeMap: 实现了SortMap接口,能够把保存的记录按照键排序(默认为升序)也可指定排序比较器。
在Map中插入,删除,定位元素:HashMap
要按照自定义顺序或自然顺序遍历:TreeMap
要求输入顺序和输出顺序相同:LinkedHashMap
3、Object若不重写hashCode()的话,hashCode()如何计算出来的?
将对象的内存值进行哈希运算,返回一个int类型的哈希值。
4、==比较的是什么?
对于基本数据类型来说,比较的是值,对于引用类型来说,比较的是引用指向的对象是否为同一个(即比较对象的内存地址)。
5、若对一个类不重写,它的equals()方法是如何比较的?
默认采用的Object类的equals(),而在Object类中,equals()方法的实际是采用==实现比较的。
6、java8新特性
lambda表达式:允许把函数作为一个方法的参数。
方法引用:直接引用已有的Java类或者对象(实例)的方法或构造器。
默认方法:在接口里都有一个实现方法。
Stream API: 新添加Stream API 半把真正的函数式编程风格引入Java。
DateTimeAPI:加强对于日期和时间的处理。
Optional:解决空指针异常。
Js引擎。
7、说说Lamda表达式的优缺点。
优点:
简洁
非常容易并行计算。
可能代表未来的编程趋势。
缺点:
若不用并行计算,很多时候计算速度没有比传统的 for 循环快。(并行计算有时需要预热才显示出效率优势)
不容易调试。
若其他程序员没有学过 lambda 表达式,代码不容易让其他语言的程序员看懂。
8、一个十进制的数在内存中是怎么存的?
二进制补码
9、为啥有时会出现4.0-3.6=0.40000001这种现象?
在计算机中无法直接进行计算,都需要转换为二进制数进行运算,在二进制小数的计算过程中,产生了误差。
10、Java支持的数据类型有哪些?什么是自动拆装箱?
8种基本类型:byte、short、char、int、long、float、double、booblean以及引用类型包括数组、类、接口等。
自动装箱、拆箱是Java中8种基本类型与其包装类型之间的转化。装箱是基本数据类型与其包装类型的转化,拆箱是其逆过程。封装成对象能够更好的调用方法。
11、什么是值传递和引用传递?
值传递:对于基本类型而言、传递的是该变量的一个副本,改变副本不影响原变量。
引用传递:一般对于对象类型而言,传递的是该对象地址的一个副本,并不是原对象本身。
一般认为,Java中的传递都是值传递,Java中实例对象的传递是引用传递。
12、数组(Array)和列表(ArrayList)有什么区别?什么时候应该使用Array而不是ArrayList?
Array可以包含基本类型以及对象类型并且是同一数据类型,ArrayList只能包含对象类型,Object。Array大小是固定的,ArrayList的大小是动态变化的。ArrayList提供了更多方法和特性。
Array:集合长度固定、保存的对象为基础数据类型,且为同一类型。对集合进行随机的读写。
ArrayList:长度不固定,如果长度增长频繁,应考虑预设ArrayList的长度或者使用链表LinkedList代替,ArrayList每次扩容都要进行数组的拷贝。插入和删除使用其内置方法较为方便。
13、你了解大O符号(big-O notation)么?你能给出不同数据结构的例子么?
大O符号描述了当数据结构里面的元素增加的时候,算法的规模或者是一个渐进上界。O表示算法的时间或者空间复杂度上界。比如数组的插入时间复杂度为O(N),空间复杂度为O(1),链表的插入时间复杂度为O(1),空间复杂度为O(1).
14、String是最基本的数据类型吗?
不是,String是引用类型。
15、int 和 Integer 有什么区别
Integer是int的包装类型,int的初值为0,Integer的初值为null
Integer 和new Integer不会相等,new出来的对象存在堆中,而非new Integer存放在常量池中,内存地址不一致。
两个非new Integer,如果数在-128 - 127之间则为true,否则为false.因为在编译时,Integer i = x, 会转化为Integer.valueOf(x),而此函数在-128 - 127对数据进行缓存。
两个都是new 的话,内存地址不同,false
int 和Integer比较,都为true,原因在于自动拆箱
16、String 和StringBuffer的区别
String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
17、我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串?
// 将str字符串从iso8859-1转化成utf8编码
res = new String (str.getBytes(“iso8859-1”), “utf-8”);
18、&和&&的区别?
&和&&都可以作为逻辑与的运算符,表示逻辑与,当运算符两边的表达式的结果都为true时,整个运算结果才为true。&&具有短路功能呢,如果第一个为false,即不再判断第二个表达式。&可作为位运算符。表示按位与运算。
19、在Java中,如何跳出当前的多重嵌套循环?
在最外层定义一个标号,在循环中直接break 标号就行了。
20、你能比较一下Java和JavaSciprt吗?
基于对象和面向对象:Java是一门真正面向对象的语言,Js是脚本语言,基于对象和事件驱动的编程语言。
解释和编译:Java在运行时必须先编译再解释执行,而Js是一种解释性语言。
强类型和弱类型:Java采用强类型的变量检查必须先声明后使用,而Js是一种弱类型。
代码格式不一样:
Java是是静态语言亦称为“准动态语言”,可通过反射机制、字节码操作产生动态性,Js是动态语言。
21、简述正则表达式及其用途。
在编写处理字符串的程序时,经常会有查找符合某些复杂规则的字符串的需要,正则表达式就是用于描述这些规则的工具。正则表达式就是记录文本规则的代码。
22、Java中是如何支持正则表达式操作的?
String str = “待匹配字符串”;
Pattern p = Pattern.compile(“正则表达式”);
Matcher m = p.matcher(str);
23、请你说说Java和PHP的区别?
1、PHP适合快速开发,开发成本低。Java适合开发大型的应用系统。
2、系统技术架构的比较,PHP只能实现简单的两层或者三层的架构。Java可实现多层的网络架构。
3、PHP对于不同的数据库需要采用不同的数据库接口,Java用JDBC统一实现。
❤2、关键字
1、介绍一下Syncronized锁,如果用这个关键字修饰一个静态方法,锁住了什么?如果修饰成员方法,锁住了什么?
对于普通的同步方法: 锁是当前的对象
对于静态函数的同步方法: 锁是指引用当前类的class对象
对于同步方法块的内容: 锁是指Synchonized括号里配置的对象
2、介绍一下volatile?
java关键字之一,只能用来修饰变量。使用其修饰的变量会强制将修改的值写入主存,主存中值的更新会使缓存中的值失效。(非volatile变量不具备这样的特性,非volatile变量的值会被缓存,线程A更新了这个值,线程B读取这个变量的值时可能读到的并不是是线程A更新后的值)。volatile禁止指令重排。其具有可见性、有序性。
3、锁有了解嘛,说一下Synchronized和lock
1、Lock是一个接口,而synchionized是java中的关键字,synchronized是内置语言实现的。
2、synchronized在发生异常时能够自动释放占有锁,因此不会导致死锁现象发生;而Lock在发生异常时,若不是主动unLock(),有可能会早场死锁现象。
3、Lock可以让等待锁的线程响应中断;使用synchronized,等待的线程会一直等待下去,不能响应中断。
4、Lock可以判断是否成功获取锁,而synchronized无法办到。
5、Lock可以提高多个线程进行读操作的效率。
4、讲一讲Java里面的final关键字怎么用的?
final修饰关键字;修饰类表示该类不能被继承,变量或者方法被final修饰表示在使用中变量值不能被修改为常量,方法不能被重写。
❤3、面向对象
1、wait方法底层原理
object中的方法,可以暂停线程,期间会释放对象锁,不像sleep方法,线程休眠期依然持有锁,wait方法的线程,必须调用notify或notifyAll方法唤醒线程!
2、Java有哪些特性,举个多态的例子。
封装、继承、多态。不同种类动物具有不一样的行为。
3、String为啥不可变?
底层final修饰
4、类和对象的区别
类是对象的抽象,对象时类的实例
5、请列举你所知道的Object类的方法。
clone() :创建并返回此对象的一个副本。
equals(Object obj) :指示其他某个对象是否与此对象“相等”。
getClass() :返回此 Object 的运行时类。
hashCode() :返回该对象的哈希码值。
notify() :唤醒在此对象监视器上等待的单个线程
notifyAll() :唤醒在此对象监视器上等待的所有线程。
toString() :返回该对象的字符串表示。
wait() : 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
6、重载和重写的区别?相同参数不同返回值能重载吗?
1)重写 override
方法名、参数、返回值相同。
子类方法不能缩小父类方法的访问权限。
子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。
存在于父类和子类之间。
方法被定义为 final 不能被重写。
2)重载 overload
参数类型、个数、顺序至少有一个不相同。
不能重载只有返回值不同的方法名。
存在于父类和子类、同类中。
3)相同参数不同返回值不可以重载,因为重载必须改变参数列表(否则,虚拟机怎么知道该调用哪一个方法)
7、”static”关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法?
Static表示静态的意思,可用于修饰成员变量和成员函数,被静态修饰的成员函数只能访问静态成员,不可以访问非静态成员。静态是随着类的加载而加载的,因此可以直接用类进行访问。 重写是子类中的方法和子类继承的父类中的方法一样(函数名,参数,参数类型,反回值类型),但是子类中的访问权限要不低于父类中的访问权限。重写的前提是必须要继承,private修饰不支持继承,因此被私有的方法不可以被重写。静态方法形式上可以被重写,即子类中可以重写父类中静态的方法。但是实际上从内存的角度上静态方法不可以被重写。
8、String能继承吗?
不能,String类为final修饰。
9、StringBuffer和StringBuilder有什么区别,底层实现上呢?
StringBuffer线程安全,StringBuilder非线程安全。两者都继承AbstractStringBuilder。StringBuffer重写了AbstractBuilder方法时使用了synchronized同步块。
10、类加载机制,双亲委派模型,好处是什么?
类加载机制 :虚拟机把描述类的数据从class文件加载到内存,并对书韩剧进行校验,转换解析和初始化。
双亲委派机制:当类受到一个类加载请求,自己不会去尝试加载这个类,而是把请求委派给父类去完成,每一层次的类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中。只有当父类加载反馈自己无法完成这个请求时,子类加载器才会尝试自己加载。
好处:比如加载位于rt.jar包中的类java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载。这样就保证了使用不同的类加载器最终得到的都是同样一个Object对象。
11、静态变量存在哪?
全局区
12、讲讲什么是泛型?
不确定的一种数据类型。是一预编译检查类型。泛型可以将运行时异常转换城编译阶段的错误。
13、解释extends 和super 泛型限定符-上界不存下界不取
extends 指定上界限,只能传入本类和子类
super 指定下界限,只能传入本类和父类
14、是否可以在static环境中访问非static变量?
不可以。static变量属于类,在类加载的时候被初始化,这个时候非静态变量没有加载,故静态变量不能访问。
15、谈谈如何通过反射创建对象?
1、默认构造器通过Class的newInstance()方法获取。
// 只能默认创建无构造
Class> clz = Class.forName(“完整包名”);
Object obj = clz.newInstance();
2、通过获取构造器getConstructor(Class>…parameterTypes);(通过有参的构造器,参数可以指定具体类型和多个数量
Class> clz = Class.forName(“完整包名”);
Constructor> con = clz.getConstructor(String.class, String.class); // 这里面的参数需要是类型的.class
Object ojb = con.newInstance("",""); //与上文获取的构造方法参数类型相对应即可
16、Java支持多继承么?
普通类不支持,但是接口支持,普通类可以实现多个接口
17、接口和抽象类的区别是什么?
抽象类可以有构造方法,接口中不能有构造方法。
抽象类可以有普通成员变量,接口中没有普通成员变量。
抽象类可以包含静态方法,接口中不能包含静态方法。
一个类可以实现多个接口,但只能继承一个抽象类。
接口可以被多重实现,抽象类只能被单一继承。
18、Comparable和Comparator接口是干什么的?列出它们的区别。
Comparable是集合内部定义的方法实现排序。Comparator是在集合外部实现的排序。
Comparable是表示当前类支持排序;Comparator可定义自定义比较器。
19、面向对象的特征有哪些方面
封装:给对象提供隐藏内部特性和行为的能力。
继承:给对象提供了从基类获取字段和方法的能力。
多态:编程语言给不同的底层数据类型做相同的接口展示一种能力。
抽象:把想法从具体的实例中分离出来。
20、final, finally, finalize的区别。
1、final是修饰关键字
一个类被声明为final,不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为abstract的,又被声明为final.
变量被声明为final,可以保证在使用中不被使用,被声明为final的变量必须在声明时给定初值,而且在以后的引用中只能读取,不可修改,被声明为final的方法也同样只能使用,不能重写。
2、finally
在异常处理时,提供finally块来执行任何清楚操作,如果抛出一个异常,那么相匹配的的catch子句就会执行,最后进入fianlly语句。
在以下 4 种特殊情况下,finally块不会被执行:
在 finally 语句块中发生了异常。
在前面的代码中用了 System.exit() 退出程序。
程序所在的线程死亡。
关闭 CPU 。
3、finalize
这是一个方法,在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是垃圾收集器在确定这个对象没有被引用时对这个对象调用的。
它是在 Object 类中定义的,因此所有的类都继承了它。
子类覆盖 finalize() 方法,以整理系统资源或者执行其他清理工作。
finalize() 方法,是在垃圾收集器删除对象之前对这个对象调用的。
21、Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?
1)重写 override
方法名、参数、返回值相同。
子类方法不能缩小父类方法的访问权限。
子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。
存在于父类和子类之间。
方法被定义为 final 不能被重写。
2)重载 overload
参数类型、个数、顺序至少有一个不相同。
不能重载只有返回值不同的方法名。
存在于父类和子类、同类中。
22、abstract class和interface有什么区别?
抽象类可以有构造方法,接口中不能有构造方法。
抽象类可以有普通成员变量,接口中没有普通成员变量。
抽象类可以包含静态方法,接口中不能包含静态方法。
一个类可以实现多个接口,但只能继承一个抽象类。
接口可以被多重实现,抽象类只能被单一继承。
23、Static Nested Class 和 Inner Class的不同
Static Nested Class :静态内部类,可以不依赖于外部类实例被实例化
Inner Class :内部类需要在外部类实例化后才能实例化
24、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
值传递,在Java里面只有值传递。当Java实例对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变。但对象的引用时永远不会改变的。
Java参数不管是原始类型还是引用类型,传递的都是一个副本。
1、参数是原始类型:传递的是参数的一个副本,即参数的原始值,函数中改变副本的值不会改变原始的值;
2、参数是引用类型:传递的参数是引用参数的副本,这副本是存放的是参数的地址,若没改变副本的地址,改变了地址中的值会影响原始值。如果改变了副本的值,如new一个,那么副本指向了新位置,但是原始引用地址中的值不会发生变化。
25、Java的接口和C++的虚类的相同和不同处。
C++中的虚类相当于Java中的抽象类,所以有如下的不同;
虚类可有构造方法,接口无;
虚类只能单继承,接口可以多实现;
虚类中的方法不一定为抽象方法,可以具有方法体,接口中都是抽象方法,不能有方法体,只是方法声明;
虚类可以是public、private、protected、default,接口只有public;
虚类中的方法权限修饰符同上,接口中只能是public和default;
虚类和接口都不能被实例化;
26、JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出异常吗?
throws:显式的声明一个异常;
throw:抛出一个异常;
try:将可能发生异常的语句包含起来,进行异常的处理;
catch:如果有异常就会执行相关的语句;
finally:不管是否发生异常都会执行;
可以。
27、内部类可以引用他包含类的成员吗?有没有什么限制?
可以,不是静态内部类,无任何限制,一个内部类对象可以访问创建他的外部类对象的成员包括私有成员。如果式静态内部类,不可以访问外部类的普通成员变量只能访问外部类的静态成员变量。
28、两个对象值相同(x.equals(y) == true),但却可有不同的hash code说法是否正确?
不正确,equals()相等。hashCode()肯定相等。hashCode()相等。equals()不一定相等。
29、重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?
1)重写 override
方法名、参数、返回值相同。
子类方法不能缩小父类方法的访问权限。
子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。
存在于父类和子类之间。
方法被定义为 final 不能被重写。
2)重载 overload
参数类型、个数、顺序至少有一个不相同。
不能重载只有返回值不同的方法名。
存在于父类和子类、同类中。
30、如何通过反射获取和设置对象私有字段的值?
getDeclaredField() //获取Field对象
setAccessible(true) //将其设置为可以访问
get/set // 通过get/set方法获取
31、谈一下面向对象的"六原则一法则"。
六原则:
(1)单一职责原则:一个类该做他该做的事;
(2)开闭原则:软件实体应对拓展开发,对于修改关闭;
(3)依赖倒置原则:面向接口编程;
(4)里氏替换原则:任何时候都可以用子类型替换掉父类型;
(5)接口隔离原则:接口要小而专,绝不能大而全;
(6)合成聚合复用原则:优先使用聚合或者合成关系服复用代码;
一法则:
迪米特法则:一个对象应当对其他对象有尽可能少的了解。
32、请问Query接口的list方法和iterate方法有什么区别?
list()返回的对象是完整的,iterate()方法只是返回对象中包含的主键值。
33、Java中的方法覆盖(Overriding)和方法重载(Overloading)是什么意思?
重载(Overloading)
(1)方法重载是让类以统一的方法处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数(类型)。重载Override是一个类中多态性的一种表现。
(2)java的方法重载,就是在类中可以创建多个方法,他们具有相同的名字,但具有不同参数和不同的定义。调用方法时通过传递给他们不同的参数个数和参数类型来决定具体使用那个方法,这就是多态性。
(3)重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不同。无法以返回类型来作为重载函数的区分标准。
重写(Overriding)
(1)父类与子类的多态性,对父类的函数进行重新定义。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写。在java中,子类可继承父类的方法,则不需要重新编写相同的方法。但有时子类并不想原封不动继承父类的方法,而是想做一定的修改,这就采用方法重写。方法重写又称方法覆盖。
(2)若子类中的方法与父类的中的某一方法具有相同的方法名、返回类型和参数表,则新方法覆盖原有的方法。如需要父类的原有方法,可以使用super关键字,该关键字引用房钱类的父类。
(3)子类函数访问权限大于父类。
34、Java中,什么是构造函数?什么是构造函数重载?什么是复制构造函数?
构造函数:初始化对象
构造函数重载:对于默认构造函数的重载;
复制构造函数:Java没有拷贝构造函数的概念。
35、hashCode()和equals()方法有什么联系?
hashCode()相等,equals()不一定相等;
equals()相等,hashCode()一定相等。
❤4、集合
1、Map和ConcurrentHashMap的区别?
map是接口,concurrenthashmap是实现类
hashmap是线程不安全的,put时在多线程情况下,会形成环从而导致死循环。
CoucurrentHashMap是线程安全的,采用分段锁机制,减少锁的粒度
2、hashMap内部具体如何实现的?
在jdk1.8中,hashMap底层是数组 + 链表 + 红黑树,具体可以去研究一下底层源码实现。
3、如果hashMap的key是一个自定义的类,怎么办?
必须重写equals()方法以及hashMap()方法。因为自定义类的hashcode()方法继承于Object类,其hashcode码为默认的内存地址,这样即便有相同的两个对象,比较也是不相等。若不重写比较的是其地址。
4、ArrayList和LinkedList的区别,如果一直在list的尾部添加元素,用哪个效率高?
ArrayList基于动态数组实现,地址连续,查询速率比较高,插入和删除的效率低。
LinkedList基于链表实现,地址任意不连续,新增和删除add以及remove速度快,LinkedList适合头尾操作或插入指定的位置。
5、HashMap底层,负载因子,为啥是2^n?
负载因子默认为0.75,2^n是为了让散列更加均匀。
6、ConcurrentHashMap锁加在了哪些地方?
不同的Segment,ConcurrentHashMap将数据分段,在读写的时候只加到相应的数据段上,这样在多线程的时候,可以读写其他段的数据,提高效率。
7、TreeMap底层,红黑树原理?
平衡二叉树:一棵空树或者左右子树的高度差绝对值不超过1,并且左右两个子树都一个平衡二叉树。
8、concurrenthashmap有啥优势,1.7,1.8区别?
ConcurrentHashMap是线程安全的。
jdk1.7:segment + HashEntry的方式实现;其中Segment在实现上继承了ReentrantLock,自带锁功能。
jdk1.8:Node + 数组 + synchronized来保证并发安全进行实现
9、ArrayList是否会越界?
可能会越界,当多个线程操作同一个ArrayList的时候,两个线程同时执行Add在线程一已经将size++而线程二在读取的时候导致越界,线程在被挂起的时候,执行的位置不一样,size是个共有变量,自增是个非原子操作。
10、什么是TreeMap?
TreeMap继承AbstractMap,实现NavigableMap、Cloneable、Serializable三个接口,能按自然顺序或自定义顺序遍历。
11、ConcurrentHashMap的原理是什么?
线程安全的HashMap实现,采用锁分段技术。把数据分成一段一段的存储,然会给每一段数据进行加锁。当一个线程占用锁访问其中一个段数据。ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成。Segment是一种可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和HashMap类似,是一种数组和链表结构, 一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素, 每个Segment守护者一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。
12、Java集合类框架的基本接口有哪些?
Collection
List
ArrrayList:有序,可重复,底层使用数组实现,查询速度快,线程不安全,扩容 = 当前 * 1.5 + 1;
LinkedList:有序,可重复。底层使用双向循环循环链表实现,增删快,线程不安全;
Vector:有序,底层使用数组,速度快,线程安全效率低,扩容 = 当前容量 * 2。
Set
HashSet:排列无序,不可重复,有去重特性。底层使用Hash表实现,存取速度快。内部是HashMap;
TreeSet:排列无序,不可重复。底层使用二叉树实现,排序存储,内部采用TreeMap的SortedSet;
LinkedHashSet:采用Hash表存储,并使用双向链表记录插入顺序。内部是LinkedHashMap。
Queue:在两端出入的List,所以可以用数组或者链表来实现。
Map
TreeMap:键不可重复,值可重复,底层为二叉树;
HashMap:键不可重复,值可重复,底层哈希表,线程不安全,允许key值为null,value也可以为null。
HashTable:键不可重复,值可重复,底层哈希表,线程安全,key、value都不允许为null。
13、为什么集合类没有实现Cloneable和Serializable接口?
克隆(cloning)或者序列化(serialization)的语义和含义是跟具体的实现相关的。因此应该由集合类的具体实现类来决定如何被克隆或者序列化
14、什么是迭代器?
容器中常用到,迭代器就是用来遍历集合的!使用方法iterator()要求容器返回一个Iterator。使用next()获得序列中的下一个元素。使用hasNext()检查序列中是否还有元素。
15、Iterator和ListIterator的区别是什么?
Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List;
Iterator对集合只能前向遍历,ListIteratorz只能遍历List;
ListIterator实现了Iterator接口,包含其他很多功能。比如增加元素,替换元素,获取前一个和后一个索引。
16、快速失败(fail-fast)和安全失败(fail-safe)的区别是什么?
fail-safe允许在遍历的过程中对容器中的数据进行修改,而fail-fast则不允许。
17、HashMap和Hashtable有什么区别?
1、HashMap是非线程安全的,HashTable是线程安全的。
2、HashMap的键和值都允许有null值存在,而HashTable则不行。
3、因为线程安全的问题,HashMap效率比HashTable的要高。
4、Hashtable是同步的,而HashMap不是。因此,HashMap更适合于单线程环境,而Hashtable适合于多线程环境。
18、ArrayList和LinkedList有什么区别?
ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
理论上来说在做新增和删除操作add和remove时,LinedList比较占优势,因为ArrayList要移动数据。
19、ArrayList,Vector,LinkedList的存储性能和特性是什么?
Arraylist是不同步的,arraylist增长为原来的一半而vector是线程同步的,增长为原来的一半,Arraylist该查速度快,是通过下标,而linklist增删快,只需要移动指针
20、Collection 和 Collections的区别。
Collection ,是集合类的上级接口,继承与他的接口主要有 Set 和List 。
Collections ,是针对集合类的一个工具类,它提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。
21、你所知道的集合类都有哪些?主要方法?
主要有两种。一种Collection,另一种Map。其中Collection包括Set、List和Queue,Set(无序无重)又包括HashSet、LinkedHashSet及TreeSet,List(有序有重)又包括ArrayList、LinkedList及Vector;其中Map包括HashTable、LinkedHashMap、HashMap及TreeMap
22、List、Set、Map是否继承自Collection接口?
List和Set继承自Collection接口,Map和Collection同级,Map是键值对映射容器
23、阐述ArrayList、Vector、LinkedList的存储性能和特性
arraylist,linkedlist是线程不安全的,vector是线程安全的,存储方面vector不及前两者,arrayliat底层是动态数组,查找方面快,linkedlist底层是链表,需要移动指针,查找数据慢,但添加和删除比较快
24、List、Map、Set三个接口存取元素时,各有什么特点?
List集合有序可重复,Set集合无序不重复。Map集合是键值对映射,值可以重复,但键不可以重复!
❤5、线程
1、多线程中的i++线程安全吗?为什么?
不安全。i++不是原子性操作。i++分为读取i值,对i值加一,再赋值给i++,执行期中任何一步都是有可能被其他线程抢占的。**
2、如何线程安全的实现一个计数器?**
可以使用加锁,比如synchronized或者lock。也可以使用Concurrent包下的原子类。
3、多线程同步的方法
实现线程同步可以用现成的sychronize,也可以通过lock锁和原子类实现
4、介绍一下生产者消费者模式?
生产者消费者模式:通过一个容器来解决生产者和消费者的强耦合关系,生产者生成数据无需等待消费者索取,消费者无需直接索要数据。两者并不进行任何通讯,而是通过容器来进行操作
作用:解耦、支持并发、支持忙闲不均。
5、线程,进程,然后线程创建有很大开销,怎么优化?
线程池
6、线程池运行流程,参数,策略
提交任务后会判断核心线程是否已满,否则创建线程执行任务。是则判断队列是否已满,否则加入队列等待,是则线程池是否已满,否则创建线程执行任务,是则按照拒绝策略处理无法执行的任务
7、讲一下AQS吧。
AQS是一个并发包的基础组件,用来实现各种锁,各种同步组件。它包含了state变量,加锁线程,等待队列并发中的核心组件。
8、创建线程的方法,哪个更好,为什么?
需要从Java.lang.Thread类派生一个新的线程类,重载它的run()方法; 实现Runnalbe接口,重载Runnalbe接口中的run()方法。 实现Runnalbe接口更好,使用实现Runnable接口的方式创建的线程可以处理同一资源,从而实现资源的共享.
9、Java中有几种方式启动一个线程?
1、继承Thread类
2、实现Runnable 接口
3、实现callable接口
4、线程池的方式开启线程
10、Java中有几种线程池?
22、启动一个线程是用run()还是start()?
run()方法是线程执行体,start()方法才能启动线程。
24、多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?
多线程有两种实现方法,分别是继承Thread类与实现Runnable接口
同步的实现方面有两种,分别是synchronized,wait与notify
25、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用?
有两种实现方法,分别是继承Thread类与实现Runnable接口用synchronized关键字修饰同步方法,反对使用stop(),是因为它不安全。它会 解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改它们。结果很难检查出真正的问题所在。suspend()方法容易发生死锁。调用suspend()的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此时,其他任何线程都不能访问锁定的资源,除非被”挂起”的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁。所以不应该使用suspend(),而应在自己的Thread类中置入一个标志,指出线程应该活动还是挂起。若标志指出线程应该挂起,便用 wait()命其进入等待状态。若标志指出线程应当恢复,则用一个notify()重新启动线程。
26、线程的sleep()方法和yield()方法有什么区别?
1.sleep()方法给其他线程机会不考虑线程的优先级别,而yield()方法只会给相同运行级别或更高运行级别的线程运行
2.线程执行sleep()方法就会进入阻塞状态,执行yield()方法会转入就绪状态
3.sleep()方法声明抛出InterruptException,而yield()没有声明任何异常
4.sleep()方法比yield方法具有更好的移植性
27、当一个线程进入一个对象的synchronized方法A之后,其它线程是否可进入此对象的synchronized方法B?
是不能的,其他线程只能访问该对象的非同步方法,同步方法则不能进入;
因为非静态方法上的synchronized修饰符要求执行方法时要获得对象的锁,如果已经进入A方法,说明对象锁已经被取
28、请说出与线程同步以及线程调度相关的方法。
❤6、锁
1、讲一下非公平锁和公平锁在reetrantlock里的实现。
非公平锁: 当线程争夺锁的过程中,会先进行一次CAS尝试获取锁,若失败,则进入acquire(1)函数,进行一次tryAcquire再次尝试获取锁,若再次失败,那么就通过addWaiter将当前线程封装成node结点加入到Sync队列,这时候该线程只能乖乖等前面的线程执行完再轮到自己了。
公平锁: 当线程在获取锁的时候,会先判断Sync队列中是否有在等待获取资源的线程。若没有,则尝试获取锁,若有,那么就那么就通过addWaiter将当前线程封装成node结点加入到Sync队列中。
2、讲一下synchronized,可重入怎么实现。
可重入的条件:
1.不在函数内使用静态或全局数据。
2.不返回静态或全局数据,所有数据都由函数的调用者提供。
3.使用本地数据(工作内存),或者通过制作全局数据的本地拷贝来保护全局数据。
4.不调用不可重入函数。
3、锁和同步的区别。
1)Lock是一个接口,而synchronized是Java中的关键字
2)synchronized是内置的语言实现,synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将 unLock()放到finally{} 中
3)Lock可以让等待的线程响应中断,县城可以去做别的事情;
synchronized不行,等待的线程会一直等下去,不能够响应中断
4)Lock可以知道是否获取到锁,知道锁的状态,而synchronized却无法办到
5)Lock可以提高多个线程进行读操作的效率。
4、什么是死锁(deadlock)?
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁。死锁产生有四个必要条件,打破任意一个,就能打破死锁状态: 1 互斥条件 2 请求与保持 3 不剥夺 4 循环等待
5、如何确保N个线程可以访问N个资源同时又不导致死锁?
多线程产生死锁需要四个条件,分别是互斥性,保持和请求,不可剥夺性还有要形成闭环,这四个条件缺一不可,只要破坏了其中一个条件就可以破坏死锁,其中最简单的方法就是线程都是以同样的顺序加锁和释放锁,也就是破坏了第四个条件。
6、请你简述synchronized和java.util.concurrent.locks.Lock的异同?
❤7、JDK
1、Java中的LongAdder和AtomicLong的区别
JDK1.8引入了LongAdder类。CAS机制就是,在一个死循环内,不断尝试修改目标值,直到修改成功。如果竞争不激烈,那么修改成功的概率就很高,否则,修改失败的的概率就很高,在大量修改失败时,这些原子操作就会进行多次循环尝试,因此性能就会受到影响。 结合ConcurrentHashMap的实现思想,应该可以想到对一种传统AtomicInteger等原子类的改进思路。虽然CAS操作没有锁,但是像减少粒度这种分离热点的思想依然可以使用。将AtomicInteger的内部核心数据value分离成一个数组,每个线程访问时,通过哈希等算法映射到其中一个数字进行计数,而最终的计数结果,则为这个数组的求和累加。热点数据value被分离成多个单元cell,每个cell独自维护内部的值,当前对象的实际值由所有的cell累计合成,这样热点就进行了有效的分离,提高了并行度。
2、JDK和JRE的区别是什么?
JRE是Java运行环境,只执行编译产生的Java字节码文件所需的Java虚拟机;JDK是Java开发套件,不仅包含JRE,还包含编译器、其他调式工具,使得开发者能调试、编译、开发自己的Java程序。
❤8、反射
1、反射的实现与作用
1、通过Class.forName()方法加载字符串,就可以得到该字符串做代表的Class对象。Class.forName(“类的全名称”)
2、通过类名调用class属性得到该类的Class对象。类.class
3、调用实例的getClass()方法。对象.getClass()
4、如果是基本类型的包装类,则可以通过调用包装类的Type属性来获得该包装类的Class对象。
❤9、JVM
1、JVM回收算法和回收器,CMS采用哪种回收算法,怎么解决内存碎片问题?
垃圾回收算法
标记-清除 复制算法 标记-整理 增量算法
回收器:
新生代回收器
Serial 单线程:简单高效
ParNew Serial的多线程版本,能与CMS配合,不能与PS配合
Parallel Scavenge 复制算法,多线程并行,适合对响应时间要求较高的场景
老年代回收器
Serial Old 单线程,搭配PS
Parallel Old PS的老年版
CMS 获取最短时间为目标的收集器
G1 基于标记整理,能非常精确的控制java堆
CMS采用标记清除算法
解决内存碎片问题:
2、类加载过程
类从被加载到JVM中开始,到卸载为止,整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。 其中类加载过程包括加载、验证、准备、解析和初始化五个阶段。
3、JVM分区
堆,虚拟机栈,本地方法栈,方法区,程序计数器
4、eden区,survial区?
新生代有一个较大的Eden区和两个较小的Survivor区组成,绝大多数新创建的对象都是在Eden区分配的,其中大多数对象很快消亡。Eden是一块连续的内存,所以分配内存的速度很快。
首先,Eden满时,进行一次minor gc ,将存活 的对象复制到 To Survivor(以下简称To),清除Eden消亡的对象。当Eden再次满时,进行minor gc,To中能够晋升的移动到老年代,存活的对象复制到From。
清空Eden和To,如此切换(默认15),将存活的对象迁移到老年代。
5、JAVA虚拟机的作用?
Java虚拟机能够将class字节码解释成可执行的机器码。Java与平台无关其实是Java字节码与平台无关,Java源文件被编译成class字节码文件,class字节码在Java虚拟机中被解释成机器码,所以在不同的平台,只要有Java环境,那么就可以把字节码解释成对应平台的机器码,即Java被称作“与平台无关的编程语言”;
6、GC中如何判断对象需要被回收?
gc用到垃圾回收机制算法,判断是否是垃圾,从而进行回收。 引用可达法法,程序运行从开始,每次引用对象,都将对引用的对象进行连接起来,到最后形成一张网,没有在这张网上的对象则被认为是垃圾对象。 还有引用计数法,对于对象的引用,每引用一次计数器加一,引用失败,计数器减一,当计数器一段时间为0,则可以被认为是垃圾。
7、JAVA虚拟机中,哪些可作为ROOT对象?
虚拟机栈(栈帧中的本地变量表)中引用的对象
静态变量引用的变量
方法区常量引用的变量
本地方法栈中引用的变量
8、JVM内存模型是什么?
JVM内存模型
方法区(Method Area):存放类似类定义、常量、编译后的代码、静态变量等。在JDK1.7中HotSpot VM的实现就是将其放在永久代中,这样的好处是可以直接使用堆中的GC算法来进行管理,坏处就是会经常出现内存溢出,即PermGen Space异常。所以在JDK1.8中,就取消了永久代,用元空间来取而代之,元空间直接使用本地内存,理论上电脑有多少内存它就可以使用多少内存,所以不会出现内存溢出。
堆(Heap):几乎所有对象、数组等都是在此分配内存的,在JVM内存中占的比例也是很大的,也是GC回收的主要阵地,平时我们说的新生代、老年代、永久代也是指这片区域。
虚拟机栈(Java Stack):当JVM在执行方法时,会在此区域中创建一个栈帧来存放方法的各种信息,比如返回值,局部变量表和各种对象引用等。 方法开始之心就先创建栈帧,执行完后就出栈。
本地方法栈(Native Method Stack):和虚拟机栈类似,专门提供给Native方法用的。
程序计数器:占用很小的一片区域,JVM执行代码一行一行执行字节码,所以需要一个计数器来记录当前执行的行数。
9、jvm是如何实现线程?
Java代码通过Thread类或者Runnable,调用其start方法后创建一个线程。其本质是jvm通过调用Thread.cpp中本地方法pthread_create创建新线程,创建线程的同时在jvm中为线程分配内存空间,即为其分配一个私有的程序计数器、虚拟机栈和本地方法栈。创建线程的方式有三种:用户线程、轻量级进程和内核线程,java线程是基于操作系统原生的线程模型
10、jvm最大内存限制多少
首先JVM内存限制于实际的最大物理内存了 假设物理内存无限大的话 JVM内存的最大值跟操作系统有很大的关系 简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G Linux系统 下为2G-3G) 而64bit以上的处理器就不会有限制了
11、什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?
Java 虚拟机是一个可以执行 Java 字节码的虚拟机进程。Java 源文件被编译成能被 Java 虚拟机执行的字节码文件。
Java 被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者是重新编译。Java 虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其他特性。
12、描述一下JVM加载class文件的原理机制?
1.装载:查找和导入class文件;
2.连接:
(1)检查:检查载入的class文件数据的正确性;
(2)准备:为类的静态变量分配存储空间;
(3)解析:将符号引用转换成直接引用(这一步是可选的)
3.初始化:初始化静态变量,静态代码块。
这样的过程在程序调用类的静态成员的时候开始执行,所以静态方法main()才会成为一般程序的入口方法。类的构造器也会引发该动作。
❤10、GC
1、java中内存泄露是啥,什么时候出现内存泄露?
Java中的内存泄露,广义并通俗的说,就是:不再会被使用的对象的内存不能被回收,就是内存泄露。如果长生命周期的对象持有短生命周期的引用,就很可能会出现内存泄露。
2、minor gc如果运行的很频繁,可能是什么原因引起的,minor gc如果运行的很慢,可能是什么原因引起的?
①
1、 产生了太多朝生夕灭的对象导致需要频繁minor gc
2、 新生代空间设置的比较小
②
1、 新生代空间设置过大。
2、 对象引用链较长,进行可达性分析时间较长。
3、 新生代survivor区设置的比较小,清理后剩余的对象不能装进去需要移动到老年代,造成移动开销。
4、 内存分配担保失败,由minor gc转化为full gc
5、 采用的垃圾收集器效率较低,比如新生代使用serial收集器
3、阐述GC算法
1)引用计数法 Reference Counting:
2)根搜索算法 GC Roots Tracing
3)标记-清除算法 Mark-Sweep:
4)标记整理算法 Mark-Compact:
5)复制算法 Copying
4、GC是什么? 为什么要有GC?
GC是垃圾回收。
内存处理是编程人员容易出现问题的地方,忘记或错误的内存回收,会导致程序或系统不稳,甚至崩溃。Java的GC功能可自动监控对象是否超过作用域,从而达到自动回收内存的目的。Java语言没有提供释放已分配的显示操作方法。
5、垃圾回收的优点和原理。并考虑2种回收机制
java垃圾回收的优点:它使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制,Java中的对象不再有"作用域"的概念,只有对象的引用才有"作用域"。垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。
java垃圾回收的原理: 垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。
6、java中会存在内存泄漏吗,请简单描述。
所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。Java中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动被垃圾回收器从内存中清除掉。由于Java 使用有向图的方式进行垃圾回收管理,可以消除引用循环的问题,例如有两个对象,相互引用,只要它们和根进程不可达的,那么GC也是可以回收它们的。
7、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?(垃圾回收)
对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。可以。程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。强制执行垃圾回收:System.gc()。Runtime.getRuntime().gc()
❤11、IO和NIO、AIO
1、怎么打印日志?
第一,System.print()直接在控制台打印消息。
第二,log4j,最强大的日志记录方式,可以通过配置.properties或.xml的文件,配置日志的目的地,格式等。
第三,commons-logging,最综合最常见的日志记录方式。
2、运行时异常与一般异常有何异同?
运行时异常(不受检查检查)开发人员可以不处理它,但是一旦出现异常将会抛出异常若找不到异常处理程序则导致系统异常退出。
一般异常需要开发人员给出一定处理要么显示声明抛出的异常,要么捕获异常
3、error和exception有什么区别?
首先Exception和Error都是继承于Throwable 类,在 Java 中只有 Throwable 类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型。
Exception和Error体现了JAVA这门语言对于异常处理的两种方式。
Exception是java程序运行中可预料的异常情况,咱们可以获取到这种异常,并且对这种异常进行业务外的处理。
Error是java程序运行中不可预料的异常情况,这种异常发生以后,会直接导致JVM不可处理或者不可恢复的情况。所以这种异常不可能抓取到,比如OutOfMemoryError、NoClassDefFoundError等。
4、给我一个你最常见到的runtime exception
ArithmeticException, 算术异常
ClassCastException, 类型强制转换异常
IndexOutOfBoundsException, 下标越界异常
NullPointerException, 空指针异常
SQLException, 操作数据库异常
5、Java中的异常处理机制的简单原理和应用。
当JAVA程序违反了JAVA的语义规则时,JAVA虚拟机就会将发生的错误表示为一个异常。违反语义规则包括2种情况。一种是JAVA类库内置的语义检查。例如数组下标越界,会引发IndexOutOfBoundsException;访问null的对象时会引发NullPointerException。另一种情况就是JAVA允许程序员扩展这种语义检查,程序员可以创建自己的异常,并自由选择在何时用throw关键字引发异常。所有的异常都是java.lang.Thowable的子类。
6、java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类?
Java中的流分为两种,一种是字节流,另一种是字符流,分别由四个抽象类来表示(每种流包括输入和输出两种所以一共四个):InputStream,OutputStream,Reader,Writer。Java中其他多种多样变化的流均是由它们派生出来的.
7、什么是java序列化,如何实现java序列化?
概念:
序列化:把Java对象转换为字节序列的过程。
反序列化:把字节序列恢复为Java对象的过程。
用途:
把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;在网络上传送对象的字节序列。
序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。
8、运行时异常与受检异常有什么区别?
Throwable是Java异常机制中的超类,有Error和Exception两个子类。
运行时异常(非检查异常)继承了RuntimeException,这类错误无需编译器检查,需要开发者开发时自行注意,常见的非检查异常有NullPointerException、ArrayIndexOutOfBoundsException。
非运行时异常(检查异常)继承自Exception除了RuntimeException以外的部分,需要使用try-catch机制来捕获错误,常见的检查异常有FileNotFoundException,IOException,SQLException。