1)equals和= =的区别?
1 | public boolean equals(Object obj){return(this == obj);} |
equals也是用= =来比较的,但equals可以根据需求重写。= =如果比较的是两个值类型的话,就是比较它们之间是否相等,如果是引用类型,则比较的是地址。
2)为什么重写equals一定要重写hash code?
默认的hash code方法是根据对象的内存地址经过哈希算法得到的,如果不重写的话,那么在两个相同的对象使用equals时就可能得到不同的结果,比如map里面,如果以对象为key,会导致逻辑上的key相同但值不同。
3)Integer与int的= =比较是怎样的?
1 | public static void main(String[] args){ |
Integer在int比较的时候,会自动拆箱,再做值比较,所以返回true;
Integer在于Integer比较的时候,除了new Integer之外,其他比较的都是同一段地址(3),而new的新对象则不是,所以返回false。
4)接口和抽象类的区别?
接口中所有的方法都是抽象的,而抽象类可以有抽象和非抽象;
类可以实现多个接口,但只能继承一个抽象类;
(?)类可以不实现抽象类和接口声明的所有方法,但是该类必须声明成抽象的;
接口的成员方法默认是public,而抽象类的成员可以是private、protected、public;
JDK1.8 开始,接口中可以包含default方法(可以进行实现),但是抽象类没有。
5)java的异常处理机制,Error和Exception的区别?
二者都有共同的父类:Throwable
Error:表示程序发生错误,是程序无法处理、不可恢复的,如OutOfMemoryError(内存溢出)、VirtualMachineError(虚拟机错误)、、ThreadDeath(线程死锁);
Exception:表示程序可处理的异常,又分为CheckedException(受检异常)、UncheckedException(非受检异常)。受检异常发生在编译期,必须要使用try…catch或者throws抛出异常,否则编译不通过(IOException、多线程之类);非受检异常发生在运行期,具有不确定性,主要由程序的逻辑问题引起,如NullPointException参数值为null(空指针),IndexOutOfBoundsException下标参数越界。
有哪些Exception?设计模式、mapreduce
6)++和–是否为原子操作,为什么?
不是原子操作。原子操作意思是操作不可分割,但是++和–可以分为三个步骤:
1.从栈读取值
2.进行加1的操作
3.将值压回栈
在多线程时就会导致自增或者自减不准确。
7)面向对象的三大特性是什么?
封装、继承、多态。
封装:把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。通过这种方式,对象对内部数据提供了不同级别的保护,防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。
继承:指让某个类型的对象获得另一个类型的对象的属性和方法。可以使用现有类的所有功能,并在无需重新编写原来的类的情况下,对这些功能进行扩展。
实现继承:直接使用基类的属性和方法,无需额外编码;
接口继承:仅使用属性和方法的名称,但子类必须提供实现的能力。
多态:指一个类实例的相同方法在不同的情形有不同的表现。
8)JAVA中具体如何实现多态?
接口
implements A,B
除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。
接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。
接口不能包含成员变量,除了 static 和 final 变量。
接口不能用于实例化对象。
接口没有构造方法。
接口中所有的方法必须是抽象方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14public interface A{
public void setNameA(String name);
}
public interface B extends A,C{ // 接口继承
public void setNameB(String name);
}
public class D implements B{ // 实现接口
public void setNameA(String name){
System.out.println("A,"+name);
}
public void setNameB(String name){
System.out.println("B,"+name);
}
}重写(overriding)与重载(overloading)
重写 重载 子类对父类允许访问的方法的实现过程进行重新编写,返回值和形参都不变。 在一个类中,方法名字相同,而参数不同,返回类型可以不同。 声明为final和static的方法不能被重写,但能够被再次声明。 被重载的方法可以改变访问修饰符 构造方法不能被重写。 最常见的就是构造器重载。 被重载的方法不可以声明新的或更广的检查异常,但可以减少或删除 被重载的方法可以声明新的或更广的检查异常 不能做更严格的访问限制 可以修改访问的限制 抽象类和抽象方法
1 | public abstract class employee{ //抽象类 |
9)面向对象和面向过程的区别?
内容 | 介绍 | 优点 |
---|---|---|
面向对象 | 把数据和数据操作放在一起,组成对象;对同类的对象抽象出其共性组成类;类通过简单的接口与外界发生联系,对象和对象之间通过消息进行通信。 | 易维护、易复用、易扩展,由于面向对象有封装、继承、多态的特性,可以设计出低耦合的系统。 |
面向过程 | 以过程为中心开发,自顶向下进行,程序结构按照功能划分成若干个基本模块,这些模块形成树状结构。 | 性能比面向对象高,因为类调用时需要实例化,开销大,消耗资源;比如嵌入式开发、linux/unix等一般采用面向过程开发,性能优先。 |
10)String/StringBuffer/StringBuilder的区别?
字符串直接相加本质也是转换成StringBuilder调用append,但是会产生大量的StringBuilder对象,所以不如直接new一个StringBuffer来用效率高。
1 | String s1 = "123"; // 存储在公共池中 |
String | StringBuffer | StringBuilder |
---|---|---|
不可变字符序列 | 可变字符序列 | 可变字符序列 |
能被多次修改且不产生新的未使用对象 | ||
线程安全(Synchronized) | 非线程安全 | |
效率低 | 效率高 | |
11)什么是面向函数式编程?
12)谈谈static、final关键字?(JVM和内存模型)
final 把类定义为不能继承的最终类,或者用于修饰方法,使得该方法不能被子类重写。
1 | final class A{//} // 太监类hhh |
符号 | Static | Final |
---|---|---|
全局、静态,修饰成员变量和成员方法 | 修饰类、属性和方法 | |
不依赖类特定的实例,被类的所有实例共享 | 修饰基本类型,放的就是值,值不可被改变;修饰引用类型,引用地址不可变,地址指向的对象或数组内容可以变。 | |
只要这个类被加载,Java虚拟机就能根据类名在运行时数据区内找到它们,因此static对象可以在它任何对象创建之前访问,无需引用任何对象 | ||
Class A{ static int a = 1;} A.a | ||
…… |
1 | public final static int ABC=100;//全局常量 |
13)谈谈volatile、synchronized关键字?
线程安全的两个方面:执行控制和内存可见。
执行控制的目的是控制代码执行顺序以及是否可以并发执行。
内存可见控制的是线程执行结果在内存中对其他线程的可见性。JAVA内存模型的实现,线程在具体执行时,会先拷贝主存数据到线程本地(CPU缓存),操作完成后再把结果从线程本地刷新到主存。
synchronized关键字解决的是执行控制的问题,它会阻止其他线程获取当前对象的监控锁,使得当前对象中被synchronized关键字保护的代码块无法被其他线程访问,也就无法并发执行。同时它会创建一个内存屏障,内存屏障指令保证了所有CPU操作结果都会直接刷到主存中,从而保证了操作的内存可见性。
volatile关键字解决内存可见性问题,对所有volatile变量的读写都会直接刷新到主存,即保证了变量的可见性。满足一些对变量可见性有要求而对读取顺序没有要求的需求。
区别:volatile本质是再告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量,只有当前的线程可以访问该变量,其他线程都会被阻塞。
关键字 | volatile | synchronized |
---|---|---|
本质 | 告诉jvm,当前的变量在寄存器中不确定,需要从主存中读取 | 锁定当前变量,只有当前线程可以访问该变量,其他线程都会被阻塞 |
应用级别 | 变量 | 变量、方法、类 |
线程阻塞 | 不会造成 | 可能会造成 |
变量修改可见性和原子性 | 仅实现变量的修改可见性,不能保证原子性 | 保证变量的修改可见性和原子性 |
编译器优化 | 不会 | 可以 |
14)谈谈深拷贝和浅拷贝?
浅拷贝:1. 数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象;2.数据类型是引用类型的成员变量,比如某个数组、某个类的对象,会进行引用传递,即将内存地址复制一份给新的对象,这种情况下,在一个对象中修改该成员变量会影响到另一个对象。
方式 | 浅拷贝 | 深拷贝 |
---|---|---|
介绍 | 1.基本数据类型:直接值传递; 2.引用类型(某个数组、类的对象):引用传递,即将内存地址复制一份给新的对象,这种情况下,在一个对象中修改会影响到另一对象 |
对象图。对象进行深拷贝要对整个对象图进行拷贝。对引用数据类型的成员变量的对象图中所有对象都开辟了内存空间。 |
实现方式 | 1.拷贝构造函数 2.重写clone() |
1.重写clone() |
1 | public class A implements Cloneable{ // 浅拷贝 |
https://www.cnblogs.com/shakinghead/p/7651502.html
15)JAVA线程和系统线程的区别?
16)开多个JAVA进程和多个线程的区别?
17)什么是同步与异步,阻塞和非阻塞?
18)多进程之间如何通信?
19)枚举enum
1 | enum Color{ |
20)JVM垃圾回收机制
方法 | 内容 |
---|---|
引用计数 | 给对象添加一个引用计数器,但难以解决循环引用问题。 |
可达性分析 | 通过一系列的GC Roots的对象作为起点,从起点出发所走过的路径称为引用链。当一个对象到起点没有任何引用链时,说明不可用。 |
回收算法 | 方法 | 优缺点 |
---|---|---|
标记-清除 | 直接标记清除 | 效率不高 空间产生大量碎片 |
复制法 | 把空间分为两块,每次对一块进行GC,当这块内存用完,就将还存活的对象复制到另一块,然后这块全部清空 | 空间利用率低下,多数新生代熬不过第一次GC |
标记-整理 | 针对老年代,把存活对象移到内存一端 | |
分代回收 | 分为新生代和老年代,新生代每次都有大量对象死去,因此选择复制法;老年代对象存活率高,使用标记清除法或标记整理 |
21)Redis 非关系型数据库
22)Java设计模式与实现
23)Java引用类型
类型 | 介绍 |
---|---|
强引用 | 一个对象被人拥有强引用,那么垃圾回收器不会回收它。当内存不足,JVM宁可抛出OutOfMemoryError,也随意回收 |
软引用 | 如果内存足够,垃圾回收器不会回收;如果内存不够之前,就会回收 |
弱引用 | 可有可无的对象,只要被gc扫描到了,就随时被回收。 |
虚引用 | 任何时候都可能被回收,必须与引用队列联合使用 |