(一) 基本概念和常识
1. Java语言有什么特点?
- 简单易学(摒弃了指针和内存管理等容易发生错误的地方,而且有丰富的类库)
- 面向对象
- 移植性强(一次编译,随处运行)
- 支持多线程
- 健壮(Java是强类型语言,还提供了异常处理,垃圾回收等特性)
2. 说一说JDK、JRE、JVM的区别?
JVM是运行字节码的Java虚拟机(字节码就是.class文件,只面向虚拟机)。JVM针对不同的系统有不同的实现,使得Java代码编译一次,随处可以运行。
JRE是java的运行环境。它是运行已编译的java程序所需资源的集合,包括虚拟机JVM,Java类库,Java命令等组件。
JDK是Java开发工具包,提供了Java的开发环境和运行环境。它包括JRE,而且还有编译器javac和工具如javadoc。
如果只运行java程序,安装JRE即可。如果要编写、编译Java源代码,就得安装JDK。也有例外情况,例如运行一个含有JSP的Web程序,就需要JDK,因为将JSP转化成Servlet后需要用JDK编译。
3. 为什么说 Java 语言“编译与解释并存”?
因为Java源代码首先要经过javac编译步骤,变成字节码文件,然后再由JVM解释运行。所以编译与解释并存。
4. 什么是字节码?采用字节码的最大好处是什么?
字节码就是Java源代码经过javac编译后形成的.class文件,它不面向任何处理器,只面向JVM。
Java通过字节码的方式,一定程度上缓解了传统解释型语言执行速度慢的问题,同时保留了跨平台的特性,所以Java程序运行时比较高效,而且无须重新编译,即可在不同平台执行。
5. Oracle JDK 和 OpenJDK 有什么区别?
OpenJDK是一个参考模型,全部开源。Oracle JDK是OpenJDK的一个实现,部分开源。
Oracle JDK相对更稳定,而且性能好一点。
6. JAVA和C++有什么区别?
- C++是编译型语言,运行速度比Java快。Java是解释型语言,能跨平台。
- Java不提供指针来直接访问内存,更加安全。
- Java有自动内存管理机制,不需要像C++一样手动释放内存。
- Java的类只能是单继承,C++可以多继承。但是Java接口可以多继承,就是一个类可以实现多个接口。
- C++的字符数组或字符串需要用空字符结尾(
'\0'
),Java的字符串不需要结束符。
7. JAVA语言采用何种编码方案?
Java采用Unicode编码标准,把世界上的各种语言的每一个字符都设定了唯一编码,实现跨语种、跨平台使用。
(二) 基础语法
1. Java的注释有几种?怎么表示?
有三种,分别为单行注释,多行注释和文档注释。
分别为//
, /* */
, /** */
多行注释和文档注释不能嵌套使用
2. Java访问修饰符是什么?有哪几种?
访问修饰符可以修饰类、变量、方法,用来控制它们的访问权限。
修饰符 | 当前类 | 子类 | 当前包 | 其他包 |
---|---|---|---|---|
private | √ | |||
默认(default) | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
3. final, finally, finalize的区别?
final是用来修饰类、方法、变量的。如果修饰类,则表示该类无法被继承;如果修饰方法,则该方法无法被重写;如果修饰变量,则该变量是一个常量,无法被重新赋值。
finally出现在try-catch代码块中,无论是否出现异常,finally内的语句都会执行。
finalize是一个方法,属于Object类,该方法一般由垃圾回收器来调用。
4. this有什么作用?super呢?
this代表对象本身,是当前对象的引用。
this的作用主要有两个:形参和成员变量重名时,使用this来区分;引用本类的构造方法。
super为自己父类对象的应用。离自己最近的一个父类。
super的作用也有两个:调用父类的属性和方法;引用父类的构造方法。
5. ==和equals有什么区别?
**==**判断的是两个变量的值是否相等。如果是两个基本数据类型,那么就直接比较值。如果是两个对象,那么就比较地址的值。
equals判断两个对象是否相等,如果类中没有重写equals方法,那么就会使用Object中的equals方法,和==是一样的效果。如果类中重写了equals方法,那么就可以比较类中的内容是否相等。
6. 为什么重写equals()方法后还要重写hashCode()方法?
如果要以某个类为键创建散列表,那么就得使用hashCode()方法计算其下标,如果表中对应下标有元素的话,说明发生了冲突,会根据hashCode和equals方法判断键是否相同,如果相同,则直接覆盖值。如果不同,就插入红黑树或放到链表末尾。
如果仅仅重写了equals方法,那么两个相等的对象的hashCode很可能不等,导致哈希表保存重复的对象。而HashSet、HashMap这种是不允许出现重复元素的。所以要同时重写hashCode方法,保证两个对象如果equals()返回相等时,hashCode()应该是相同的结果。
(三) 数据类型
1. Java有哪些基本数据类型,各占多少字节,取值范围是多少?
2. 谈谈自动装箱和拆箱?
自动装箱:自动将基本数据类型包装成引用类型。
自动拆箱:自动将包装类型拆成基本数据类型。
例如将一个常数赋值给Integer类型,就会进行自动装箱操作,将常数包装成Integer类型。如果将一个Integer类型和一个整数做加法,那么就会自动拆箱,将Integer拆正对于的整数。
Java中的大部分包装类型都实现了常量池技术,包括Byte、Short、Integer、Long、Char、Boolean。前四种默认创建了[-127, 128]的缓存数据,Char类型创建了[0, 127]的缓存数据,Boolean直接返回True或False。如果要装箱的基本类型在缓存池区间内,就直接返回对应的引用即可,如果不在区间内,就会创建新的对象。
下列程序的输出结果是什么?
public class Main {
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
Long h = 2L;
System.out.println(c==d); // true
System.out.println(e==f); // false
System.out.println(c==(a+b)); // true
System.out.println(c.equals(a+b)); // true
System.out.println(g==(a+b)); // true
System.out.println(g.equals(a+b)); // false
System.out.println(g.equals(a+h)); // true
}
}
3. Java中switch能支持哪些数据类型?
jdk1.5之前,能支持byte, short, int, char四种基础类型。
jdk1.5增加了枚举类和byte, short, int, char的包装类,支持包装类的原因是Java进行了自动拆箱操作,支持枚举类的原因是枚举类有一个ordinal方法,返回的是int类型的数值。
jdk1.7开始支持String类型,是因为String类型有一个HashCode方法返回int值。其余几种能不丢失精度的情况下向上转型为int,所以总的来说,switch支持的是int。
switch表达式中的值不能为null,不然会报NullPointerException。case中的值也不能为null,会编译错误。
(四) Java包
1. JDK 中常用的包有哪些?
- java.lang,这个是java的基础包,在使用时不需要导包。
- java.util,这个包含有各种集合类。
- java.io,这个包含有读写文件相关操作。
- java.sql,这个包是和数据库操作相关的。
2. import java和javax有什么区别?
javax刚开始作为一个拓展的API包来使用,但随着时间推移,javax发展成了java API的组成部分。但将javax包中的内容移动到java包中会破坏之前的代码。因此,javax包就成了标准的一部分。实际上java和javax没有区别,就是名字不同。
(五) String类
1. 什么是字符串常量池?
字符串常量池位于堆内存中,专门用来存放字符串常量。它的设计思想就是避免频繁地创建重复字符串,导致系统性能降低。
所以在创建字符串常量时,先判断字符串在不在常量池中,如果在,就直接返回引用。如果不在,就实例化字符串,并存放到常量池中。
2. String、StringBuffer、StringBuilder有什么异同点?
这三个都是使用字符数组保存字符串,而且都是final类,无法被继承。
可变性方面,String是不可变的,因为类中的字符数组被final修饰。StringBuffer和StringBuilder中的字符数组是可变的。
线程安全方面,String由于是不可变的,所以线程安全。StringBuffer也是线程安全的,因为大部分方法加了同步锁,可以实现对字符数组的互斥访问。而StringBuilder为了提高性能,就没有同步锁,所以线程不安全。
性能方面,String的性能最低,StringBuffer其次,StringBuilder最快。因为String类型进行字符串拼接、修改时,其实是每次都在创建了新的字符串,所以效率最慢。StringBuffer由于有同步锁,就会阻塞一些访问字符数组的进程,效率会慢些。StringBuilder不涉及到锁,所以速度最快。
如果只是定义个字符串,或进行少量的拼接操作,那么可以使用String。如果涉及大量字符串改动,而且是多线程操作,那么就应该使用StringBuffer。如果是单线程,那就可以用StringBuilder。
3. 使用HashMap时,使用String做Key有什么好处?
由于HashMap中根据HashCode来计算值的存放位置。String类型是不可变的,所以它的HashCode是固定的,可以被缓存下来,不用重复计算,所以效率很高。
4. String类可以被继承吗?
不能,String是final类,无法被继承。