常见java面试题及答案(208道)
- 常见java面试题及答案(208道)
-
- Java 基础
-
- 1. JDK 和 JRE 有什么区别?
- 2. == 和 equals 的区别是什么?
- 3. 两个对象的 hashCode() 相同,则 equals() 也一定为 true吗?
- 4. final 在 Java 中有什么作用
- 5.Java 中的 Math. round(-1. 5) 等于多少?
- 6. String 属于基础的数据类型吗?
- 7.String 类的常用方法都有哪些?
- 8. String str="i"与 String str=new String(“i”)一样吗?
- 9. new String("a") + new String("b") 会创建几个对象?
- 10. Java 中操作字符串都有哪些类?它们之间有什么区别?
- 11. 如何将字符串反转?
- 12. 抽象类必须要有抽象方法吗?
- 13. 抽象类和接口有哪些区别及相同点?
- 14. 普通类和抽象类有哪些区别?
- 15. 抽象类能使用 final 修饰吗?
- 16. Java 中 IO 流分为几种?
- 17、BIO、NIO、AIO 有什么区别?
- 18、Java 集合都有哪些?
- 19、ArrayList的实现原理?
- 20、ArrayList 和 LinkedList 的区别是什么?
- 21、ArrayList 和 Vector 的区别是什么?
- 22、HashSet 的实现原理
- 23、HashMap 和 Hashtable 有什么区别?
- 24、如何决定使用 HashMap 还是 TreeMap?
- 25、HashMap 的实现原理?
- 26、线程安全的集合有哪些?
- 27、迭代器 Iterator 是什么?
- 28、Iterator 和 ListIterator 有什么区别?
- 29、怎么确保一个集合不能被修改?
- 30、如何实现数组和 List 之间的转换?
- 31、Array 和 ArrayList 有何区别?
- 32、在 Queue 中 poll()和 remove()有什么区别?
- 33、 Files的常用方法都有哪些?
- 34、处理不同类型的文件的方式
- 多线程篇
-
- 35、并行和并发有什么区别
- 36、线程和进程的区别?
- 37、守护线程是什么?
- 38、线程的join()方法
- 39、创建线程有哪几种方式?
- 40、线程的状态有哪些?
- 41、sleep() 和 wait() 有什么区别?
- 42、notify()和 notifyAll()有什么区别?
- 43、线程的 run() 和 start() 有什么区别?
- 44、Lock和Synchorized的区别?
- 45、多线程中 synchronized 锁升级的原理是什么?
- 46、锁的类型都有哪些?
- 47、 创建线程池有哪几种方式?
- 50、什么是变量的可见性
- 51、Volatile和Synchorized的区别
- 52、Volatile和Synchorized如何保证变量的可见性
- 网络篇
常见java面试题及答案(208道)
Java 基础
1. JDK 和 JRE 有什么区别?
JDK:Java Development Kit 的简称,Java 开发工具包,提供了 Java 的开发环境和运行环境。
JRE:Java Runtime Environment 的简称,Java 运行环境,为 Java 的运行提供了所需环境。
具体来说 JDK 其实包含了 JRE,同时还包含了编译 Java 源码的编译器 Javac,还包含了很多 Java 程序调试和分析的工具。简单来说:如果你需要运行 Java 程序,只需安装 JRE 就可以了,如果你需要编写 Java 程序,需要安装 JDK。
2. == 和 equals 的区别是什么?
==
对于基本类型和引用类型 == 的作用效果是不同的,如下所示:
- 基本类型:比较的是值是否相同;
- 引用类型:比较的是引用是否相同;
equals
- equals 本质上就是 ==,默认情况下是比较引用类型的地址
- equals不能用于基本类型的比较,只能用于引用类型的比较
- equals是属于Object的方法,如果是引用类型需要比较值,需要重写equals方法(在对象的比较时,当equals没有重写时,equals的用法和==相等,都是比较两个对象的地址,所以一般比较两个对象中的内容时一般要重写equals方法)
- [String内部已经重写了equals方法]
3. 两个对象的 hashCode() 相同,则 equals() 也一定为 true吗?
不对,两个对象的 hashCode() 相同,equals() 不一定 true。
String str1 = "通话";
String str2 = "重地";
System. out. println(String. format("str1:%d | str2:%d", str1. hashCode(),str2. hashCode()));
System. out. println(str1. equals(str2));
执行结果:
str1:1179395 | str2:1179395
false
代码解读:很显然“通话”和“重地”的 hashCode() 相同,然而 equals() 则为 false,因为在散列表中,hashCode() 相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等。
equals相等的两个对象,hashCode一定相等;
hashCode不相等,一定能推出equals也不相等;
hashCode相等,equals可能相等,也可能不等。
4. final 在 Java 中有什么作用
- final 修饰的类叫最终类,该类不能被继承。
- final 修饰的方法不能被重写。
- final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。
- final 修饰的引用类型,其引用在初始化后就不能改变。
5.Java 中的 Math. round(-1. 5) 等于多少?
Math提供了三个与取整有关的方法:ceil(向上取整)、floor(向下取整)、round(四舍五入)
Math. round(-1. 5) 等于 -1,因为在数轴上取值时,中间值(0.5)向右取整,所以正 0.5 是往上取整,负 0.5 是直接舍弃。
6. String 属于基础的数据类型吗?
String 不属于基础类型。基础类型有 8 种:byte、short、int、long、float、double、char、boolean,而 String 属于对象。
数据类型 | 长度 | 最小值 | 最大值 | 备注 |
---|---|---|---|---|
byte | byte数据类型是8位、有符号的,以二进制补码表示的整数;(256个数字),占1字节 | -128(-2^7) | 127(2^7-1) | byte类型用在大型数组中节约空间,主要代替整数,因为byte变量占用的空间只有int类型的四分之一;默认值是0 |
short | short数据类型是16位、有符号的以二进制补码表示的整数,占2字节 | -32768(-2^15) | 32767(2^15 - 1) | Short数据类型也可以像byte那样节省空间。一个short变量是int型变量所占空间的二分之一;默认值是0 |
int | int数据类型是32位、有符号的以二进制补码表示的整数;占4字节 | -2,147,483,648(-2^31) | 2,147,485,647(2^31 - 1) | 一般地整型变量默认为int类型;默认值是0 |
long | long数据类型是64位、有符号的以二进制补码表示的整数;占8字节 | -9,223,372,036,854,775,808(-2^63) | 9,223,372,036,854,775,807(2^63 -1) | 这种类型主要使用在需要比较大整数的系统上;默认值是0L |
float | float数据类型是单精度、32位、符合IEEE 754标准的浮点数;占4字节 | -3.4*E+38 | 3.4*E-38 | 浮点数是有舍入误差的float在储存大型浮点数组的时候可节省内存空间;默认值是0.0f;float型定义的数据末尾必须有"f"或"F",以便和double区别 |
double | double数据类型是双精度、64位、符合IEEE 754标准的浮点数; | 浮点数的默认类型为double类型;默认值是0.0d; | ||
char | char类型是一个单一的16位Unicode字符;用 ‘’表示一个字符“,java 内部使用Unicode字符集,他有一些转义字符 ,2字节 | 最小值是’\u0000’(即为0) | 最大值是’\uffff’(即为65,535) | char类型可以当整数来用,它的每一个字符都对应一个数字;可以使用int code = (int) c;强制转换,也可以使用 Character 类的 getNumericValue 方法 |
boolean | boolean数据类型表示一位的信息;只有两个取值:true和false | boolean类型只作为一种标志来记录true/false情况;默认值是false; |
7.String 类的常用方法都有哪些?
- (1)常见String类的获取功能
length:获取字符串长度;
charAt(int index):获取指定索引位置的字符;
indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引;
substring(int start):从指定位置开始截取字符串,默认到末尾;
substring(int start,int end):从指定位置开始到指定位置结束截取字符串;
- (2)常见String类的判断功能
equals(Object obj): 比较字符串的内容是否相同,区分大小写;
contains(String str): 判断字符串中是否包含传递进来的字符串;
startsWith(String str): 判断字符串是否以传递进来的字符串开头;
endsWith(String str): 判断字符串是否以传递进来的字符串结尾;
isEmpty(): 判断字符串的内容是否为空串"";
- (3)常见String类的转换功能
byte[] getBytes(): 把字符串转换为字节数组;
char[] toCharArray(): 把字符串转换为字符数组;
String valueOf(char[] chs): 把字符数组转成字符串。valueOf可以将任意类型转为字符串;
toLowerCase(): 把字符串转成小写;
toUpperCase(): 把字符串转成大写;
concat(String str): 把字符串拼接;
- (4)常见String类的其他常用功能
replace(char old,char new) 将指定字符进行互换
replace(String old,String new) 将指定字符串进行互换
trim() 去除两端空格
int compareTo(String str) 会对照ASCII 码表 从第一个字母进行减法运算 返回的就是这个减法的结果,如果前面几个字母一样会根据两个字符串的长度进行减法运算返回的就是这个减法的结果,如果连个字符串一摸一样 返回的就是0。
8. String str="i"与 String str=new String(“i”)一样吗?
不一样,因为内存的分配方式不一样。String str="i"的方式,Java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。
9. new String(“a”) + new String(“b”) 会创建几个对象?
对象1:new StringBuilder()
对象2:new String(“a”)
对象3:常量池中的"a"
对象4:new String(“b”)
对象5:常量池中的"b"
深入剖析:StringBuilder中的toString():
对象6:new String(“ab”)
强调一下,toString()的调用,在字符串常量池中,没有生成"ab"。原因:直接赋值(字面值)的对象会放进常量池(也就是编译阶段的文本字符常量才会被自动添加到驻留池)。运行期动态生成的,不会在字符串常量池中创建字符串对象
String s1 = new String("1") + new String("1");//s1变量记录的地址为:new String
s1.intern();//在字符串常量池中生成"11"。如何理解:jdk6:创建了一个新的对象"11",也就有新的地址;jdk7:此时常量池中并没有创建"11",而是创建了一个指向堆空间中new String("11")的地址;
String s2 = "11";
System.out.println(s1 == s2);//jdk6:false;jdk7:true
10. Java 中操作字符串都有哪些类?它们之间有什么区别?
操作字符串的类有:String、StringBuffer、StringBuilder。
String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
11. 如何将字符串反转?
使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。
// StringBuffer reverse
StringBuffer stringBuffer = new StringBuffer();
stringBuffer. append("abcdefg");
System. out. println(stringBuffer. reverse()); // gfedcba
// StringBuilder reverse
StringBuilder stringBuilder = new StringBuilder();
stringBuilder. append("abcdefg");
System. out. println(stringBuilder. reverse()); // gfedcba
12. 抽象类必须要有抽象方法吗?
不需要,抽象类不一定非要有抽象方法。