1.JDK和JRE的区别:
JRE是Java运行时环境,包括bin文件(JVM)和lib文件(类库,没有javac)。
JDK是Java开发工具包,包括JRE,include(java和JVM交互用的头文件)。
通常安装的eclipse、idea等IDE有自己的编译器而不是用JDK bin目录中自带的,所以在安装时只要求你选中JRE路径。
2.final和static
final修饰变量,不能修改;修饰方法,不能覆盖;修饰类,不能继承。
static修饰的方法和类,存储在方法区,随类一起被加载。static不能和abstract
static 不能和abstract一起修饰方法,必须有实现。
static不能修饰接口,抽象类。
3.自动装箱是Java编译器在基本数据类型和对应的对象包装类型间的转化,即int转化为Integer,自动拆箱是Integer调用其方法将其转化为int。
4.覆盖||重写(override)
必须有继承。重写方法的方法名称、参数列表必须与原方法的相同,返回类型可以相同也可以是原类型的子类型(从Java SE5开始支持)。
重写方法不能比原方法访问性权限小。
重写方法不能比原方法抛出更多的异常。
final方法不能被重写的。
private方法不能被重写,否则在其子类中只是新定义了一个方法,并没有对其进行重写。
static方法不能被重写。因为静态方法是在编译时把静态方法和类的引用类型进行匹配。
重写是发生在运行时的。因为编译期编译器不知道无法确定该去调用哪个方法,JVM会在代码运行时决定。
5.重载(overload)
发生在同一个类中,方法名相同。
返回类型可以不同,但只有返回类型不同不构成重载。
重载是编译时多态,重写是运行时多态。
6.继承时静态语句块,非静态语句块,构造函数的运行顺序。
父类静态语句块 子类静态语句块>父类非静态语句块>父类构造方法 >子类非静态语句块>子类构造方法。
7.String
final,因此不可继承
JDK9之前,char 16位——private final char value[];
JDK9之后,byte 8位——private final byte[] value
String 支持多种编码,如果不指定编码的话,它可能使用两种编码,分别为 LATIN1 和 UTF16。LATIN1 可能比较陌生,其实就是 ISO-8859-1 编码,属于单字节编码。而 UTF16 为双字节编码,它使用1个或2个16位长的空间存储。
String s = "abc";
String ss = new String("abc");// 两个对象,一个是静态存储区的"abc",一个是用new创建在堆上的对象。
String a = "Programming";
String b = new String("Programming");
String c = "Program" + "ming";
System.out.println(a == b);//false
System.out.println(b == c);//false
System.out.println(a == c);//true
System.out.println(a.equals(b));//true
System.out.println(a.equals(c));//true
System.out.println(a.intern() == b.intern());//true
和StringBuffer,StringBuilder的区别
String 不可变,因此是线程安全的
StringBuilder可变。不是线程安全的
StringBuffer 可变。是线程安全的,内部使用 synchronized 来同步
String.intern()
String s3 = s1.intern(); //首先把 s1 引用的对象放到 String Pool(字符串常量池)中,然后返回这个对象引用。因此 s3 和 s1 引用的是同一个字符串常量池的对象。
8.抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?
答:都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。
9.接口和抽象类
先继承后实现,单继承多实现。(class X extends C implements A,B)
接口可以继承接口。抽象类可以实现(implements)接口,抽象类可继承具体类,但前提是具体类必须有明确的构造函数。
抽象类可以包含抽象方法和非抽象方法,但接口只有抽象方法。
接口方法和字段默认是public。
接口不能有构造函数,抽象类可以。
接口的初始化不会引起其父接口的初始化。
抽象类与普通类最大的区别是抽象类不能实例化,需要继承抽象类才能实例化其子类。
接口中可以有默认的方法实现。
接口的字段默认都是 static 和 final 的。(声明时必须赋值)
10.在Java 中,如何跳出当前的多重嵌套循环?
在最外层循环前加一个标记如A,然后用break A;可以跳出多重循环。(Java中支持带标签的break和continue语句,作用有点类似于C和C++中的goto语句,但是就像要避免使用goto一样,应该避免使用带标签的break和continue,因为它不会让你的程序变得更优雅,很多时候甚至有相反的作用,所以这种语法其实不知道更好)
11.Object
方法:
public final native Class> getClass()
public native int hashCode()
public boolean equals(Object obj)
protected native Object clone() throws CloneNotSupportedException
public String toString()
public final native void notify()
public final native void notifyAll()
public final native void wait(long timeout) throws InterruptedException
public final void wait(long timeout, int nanos) throws InterruptedException
public final void wait() throws InterruptedException
protected void finalize() throws Throwable {}
12.equals
基本类型,== 判断两个值是否相等,基本类型没有 equals() 方法。
引用类型,== 判断两个实例是否引用同一个对象,而 equals() 判断引用的对象是否等价。
【equals判断过程】首先判断是否是同一个对象的引用,若是则返回true,否则,则判断是否属于同一个类类(instanceof),是则将Object转型,然后继续判断关键域,否则返回false。
13.hashcode
在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个实例散列值也相等。
一个数与 31 相乘可以转换成移位和减法:31*x == (x<<5)-x,编译器会自动进行这个优化。
@Override
public int hashCode() {
int result = 17;
result = 31 * result + x;
result = 31 * result + y;
result = 31 * result + z;
return result;
}
14.深拷贝和浅拷贝
15.异常
【分类】Throwable 是所有异常的父类
Throwable分为两种: Error 和 Exception。其中 Error 用来表示 JVM 无法处理的错误
Exception 分为两种:
受检异常 :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
非受检异常 :是程序运行时错误,例如除 0 会引发 Arithmetic Exception。
image.png
16.反射
https://www.sczyh30.com/posts/Java/java-reflection-1/
【弊端】
由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。
反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
用法:
1.在运行时判断任意一个对象所属的类;
2.在运行时构造任意一个类的对象;
3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
4.在运行时调用任意一个对象的方法
参考资料:
https://github.com/CyC2018/Interview-Notebook/blob/master/notes/Java%20%E5%9F%BA%E7%A1%80.md
17.HashMap可以通过下面的语句进行同步:
Map m = Collections.synchronizeMap(hashMap);