参考:
1、Java 语言有哪些特点?
- 面向对象(封装,继承,多态);
- 跨平台( Java 虚拟机实现平台无关性);
- 可靠性;
- 安全性;
- 支持网络编程并且很方便( Java 语言诞生本身就是为简化网络编程设计的,因此 Java 语言不仅支持网络编程而且很方便);
- 编译与解释并存;
2、排序算法
3、 双重指针
4、Java Object类有什么方法
hashcode(), equals(), clone(), toString(), getClass(), finalize(), notify(), notifyAll(), wait()
5、解释一下 JVM
6、 JRE和JDK的区别
为什么JDK中包含一个JRE呢?
7、Java 与 C++ 的区别
- Java 是纯粹的面向对象语言,所有的对象都继承自 java.lang.Object,C++ 为了兼容 C 既支持面向对象也支持面向过程。
- Java 通过虚拟机从而实现跨平台特性,但是 C++ 依赖于特定的平台。
- Java 的 goto 是保留字,但是不可用,C++ 可以使用 goto。
- Java 支持自动垃圾回收,而 C++ 需要手动回收。
- Java 没有指针,它的引用可以理解为安全指针,而 C++ 具有和 C 一样的指针。
- Java 不支持多重继承,只能通过实现多个接口来达到相同目的,而 C++ 支持多重继承。
- Java 不支持操作符重载,虽然可以对两个 String 对象执行加法运算,但是这是语言内置支持的操作,不属于操作符重载,而 C++ 可以。
- Java 不支持条件编译,C++ 通过 #ifdef #ifndef 等预处理命令从而实现条件编译。
8、面向对象和面向过程的区别
9、c++11新特性
10、C++里的HashMap底层是怎么实现的
11、C++的内存分区
12、觉得编码时要遵循哪些设计原则
-
1.模块化编程,提高模块的独立性,从而增强代码的可读性和可维护性
-
2. 模块规模应该适中,且应该极力降低模块接口的复杂程度
-
3. 命名规范,比如使用对应的英文单词或者使用驼峰命名
-
4. 注释规范,比如注释不能有歧义等
13、JDK 5 - JDK 8 的新特性
JDK1.5新特性:
1.自动装箱与拆箱:
2.枚举
3.静态导入,如:import staticjava.lang.System.out
4.可变参数(Varargs)
5.泛型(Generic)(包括通配类型/边界类型等)
6.For-Each循环
7.注解
JDK1.7 新特性
1.对Java集合(Collections)的增强支持,可直接采用[]、{}的形式存入对象,采用[]的形式按照索引、键值来获取集合中的对象。如:
List<String>list=[“item1”,”item2”];//存
Stringitem=list[0];//直接取
Set<String>set={“item1”,”item2”,”item3”};//存
Map<String,Integer> map={“key1”:1,”key2”:2};//存
Intvalue=map[“key1”];//取
2.在Switch中可用String
3.数值可加下划线用作分隔符(编译时自动被忽略)
4.支持二进制数字,如:int binary= 0b1001_1001;
JDK1.8 新特性
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
})
对于函数体只有一行代码的,你可以去掉大括号{}以及return关键字。如:
Collections.sort(names,(String a, String b) -> b.compareTo(a));
或:Collections.sort(names, (a, b) -> b.compareTo(a));
2. 一组全新的时间日期API。
3 .多重注解:允许我们把同一个类型的注解使用多次,只需要给该注解标注一下@Repeatable即可
4. 接口的默认方法
5. 并行Streams
前面提到过Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。
14、字符型常量和字符串常量的区别?
- 形式上: 字符常量是单引号引起的一个字符; 字符串常量是双引号引起的若干个字符
- 含义上: 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)
- 占内存大小 字符常量只占 2 个字节; 字符串常量占若干个字节 (注意: char 在 Java 中占两个字节)
15、 构造器 Constructor 是否可被 override?
Constructor 不能被 override(重写),但是可以 overload(重载),所以你可以看到一个类中有多个构造函数的情况。
16、重载与重写
重写:
- 子类方法的访问权限必须大于等于父类方法;
- 子类方法的返回类型必须是父类方法返回类型或为其子类型。
- 子类方法抛出的异常类型必须是父类抛出异常类型或为其子类型
重载:
存在于同一个类中,指一个方法与已经存在的方法名称上相同,但是参数类型、个数、顺序至少有一个不同。应该注意的是,返回值不同,其它都相同不算是重载。
17、 怎么解释“重载是编译时的多态性,重写是运行时的多态性”
18、 Java 面向对象编程三大特性: 封装 继承 多态
封装
封装把一个对象的属性私有化,同时提供一些可以被外界访问属性的方法,保证了属性的安全
继承
多态
就是用基类的引用指向子类的对象, 具体访问时实现方法的动态绑定。在需要使用子类的地方声明为父类的引用,这样传入不同的子类对象,可以有不同的解释,产生不同的执行结果,这就是多态。
多态有什么好处?
- 多态使用了继承,所以有继承的好处,即子类可以复用父类的代码,大大提高程序的可复用性。//继承
- 父类的方法或引用变量可以调用被子类重写的功能,在需要使用子类的地方声明为父类的引用,可以提高可扩充性和可维护性,降低程序与对象的耦合度。 //多态的真正作用
19、简述一下 快排的过程
1. 首先对整个数组选定一个主元,然后根据这个主元将整个数组分成小于主元的左区间,和所有元素都大于主元的右区间,然后分别对左右区间递归进行刚才的选主元划分左右集合的操作。
快排的最坏复杂度是多少
快排最好的情况是,每次正好中分,复杂度为O(nlogn)。最差情况,就是已经有序的情况下,如果每次选定的主元是区间的第一个元素,那么复杂度为O(n^2),退化成冒泡排序,因为每次快排都必须遍历整个区间的所有元素,所以这里就有一个O(n)的算法复杂度,但是因为它不能将元素划分成左右两个集合,所以不能将递归深度降到O(logn), 而是O(n),所以复杂度是O(n^2).
为什么快排的复杂度是O(nlogn)
如何优化快排
1. 随机选取主元
2. 小数组切换到插入排序
3. 三数取中法
20、==和equals的区别?
== 判断是否是同一个对象,equals 判段对象是否等价
21、讲一讲你对hashcode和equal这两个函数的认识
因为存在 hash 冲突的情况,所以hash 值相同的两个对象不一定等价。
22、String、StringBuffer、StringBuilder三者的区别?
1. 可变性
2. 线程安全
23、抽象类与接口的区别
比较
- 从设计层面上看,抽象类提供了一种 IS-A 关系(父子关系),那么就必须满足里式替换原则,即子类对象必须能够替换掉所有父类对象,子类会继承父类所有的属性和方法。而接口更像是一种 LIKE-A 关系(师徒关系),它只是提供一种方法实现契约,需要实现什么样的功能就实现什么样的接口。
- 从使用上来看,一个类可以实现多个接口,但是不能继承多个抽象类。
- 接口的字段只能是 static 和 final 类型的,而抽象类的字段没有这种限制。
- 接口的成员只能是 public 的,而抽象类的成员可以有多种访问权限。
- 在 jdk8 以前,接口中的方法默认全是抽象方法,不能有方法体,而 抽象类中可以有不声明为抽象方法的方法,这些方法可以有方法体。但是jdk 8以后,接口也支持有方法体的默认方法了。
- 接口的体量相对都比较小,而类的体量相对就比较大,体量大的话会增大维护成本和降低使用效率
使用选择
使用接口的场景:
使用抽象类的场景:
24、 基础数据类型和包装类对象,需要使用包装类的场景
有了基本类型为什么还要有包装类型呢?
基本类型与包装类型的异同:
1、在Java中,一切皆对象,但八大基本类型却不是对象。
2、声明方式的不同,基本类型无需通过new关键字来创建,而封装类型则需new关键字。
3、存储方式及位置的不同,基本类型是直接存储变量的值,保存在堆栈中能高效的存取;封装类型需要通过引用指向实例,具体的实例保存在堆中;
4、初始值的不同,封装类型的初始值为null,基本类型的的初始值视具体的类型而定,比如int类型的初始值为0,boolean类型为false;
5、使用场景的不同,包装类的使用场景更加多样。比如与集合类合作使用时只能使用包装类型。
6、什么时候该用包装类,什么时候该用基本类型,看基本的业务来定:这个字段允不允许null值,如果允许,则必然要用封装类;否则,基本类型就可以了。如果用到比如泛型和反射调用函数,就需要用包装类!
包装类的使用场景:
- 集合类中只能使用包装类
- 泛型中使用包装类
- 反射调用函数中使用包装类
- 数据库查询的结果为null时,不能赋值给基本类型,应该使用包装类
25、在一个静态方法内调用一个非静态成员为什么是非法的?
因为非静态成员只有存在于一个对象中才有意义,但是由于静态方法可以不通过对象进行调用,因此在静态方法里,不能调用其他非静态变量,也不可以访问非静态成员方法。
26、 在 Java 中定义一个不做事且没有参数的构造方法的作用
为了子类对象能够正确的初始化。在执行子类的构造方法之前,如果没有显示的调用 super()函数
来指定所调用的父类特定的构造方法,则会默认调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,则编译时将发生错误,因为 Java 程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。
27、构造方法作用和有哪些特性?
特性:
- 名字与类名相同。
- 没有返回值,但不能用 void 声明构造函数。
- 生成类的实例
- 对象时自动执行,无需调用。
28、静态方法和实例方法有何不同
- 静态方法属于类,而实例方法属于对象,实例方法只能通过对象调用,而静态方法还可以通过类名.静态方法来使用
- 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制。
29、final 关键字的作用
1. 变量
- 对于基本类型,final 使数值不变;
- 对于引用类型,final 使引用不变,也就不能引用其它对象,但是被引用的对象本身是可以修改的。
2. 方法
3. 类
30、异常体系
1. 所有异常继承公共祖先【throwable类】
2. 异常分为两大类 : Exception & Error
(1) Error 是【程序无法处理】的错误,大部分是代码在JVM运行时出现问题。代码逻辑错误或者外部环境错误
如 程序申请内存时,内存资源不足。抛出OOM
Error发生时,JVM一般会【终止】线程
(2) Exception是【程序可以处理】的错误
常见Exception:
ArithmeticException 算数异常
NullPointException 空指针异常
ArrayIndexOutOfBoundsException 下标越界
31、内存泄漏
- 程序没有释放已经不再使用的内存,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,因此这段内存一直被占用,无法释放,造成空间的浪费。
- 长生命周期的引用指向了短生命周期的对象
内存泄漏案例
1. 单例模式
Instance可能早已不被使用,
但是类仍持有Instance的【引用】。
因此Intance【生命周期】和引用相同,造成内存泄漏。
2. 容器
容器内的【键值对】不被使用时,
Map仍持有key对象& value对象的【引用】,
则会造成内存泄漏。
怎么查内存泄漏
《Java线上内存溢出问题排查步骤》
32、内存溢出
要求分配的内存超过了系统能给我的,系统不能满足需求。内存泄漏的堆积如果不及时处理最终会导致内存溢出
33、Java 中 IO 流分为几种?
- 按照流的流向分,可以分为输入流和输出流;
- 按照操作单元划分,可以划分为字节流和字符流;
35、为什么 Java 不支持运算符重载? 另一个类似棘手的 Java 问题。为什么 C++ 支持运算符重载而 Java 不支持?
有人可能会说+运算符在 Java 中已被重载用于字符串连接,不要被这些论据所欺骗。 与 C++ 不同,Java 不支持运算符重载。Java 不能为程序员提供自由的标准算术运算符重载,例如+, - ,*和/等。如果你以前用过 C++,那么 Java 与 C++ 相比少了很多功能,例如 Java 不支持多重继承,Java 中没有指针,Java 中没有引用传递。另一个类似的问题是关于 Java 通过引用传递,这主要表现为 Java 是通过值还是引用传参。虽然我不知道背后的真正原因,但我认为以下说法有些道理,为什么 Java 不支持运算符重载。
(1)简单性和清晰性。
清晰性是 Java 设计者的目标之一。设计者不是只想复制语言,而是希望拥有一种清晰,真正面向对象的语言。添加运算符重载比没有它肯定会使设计更复杂,并且它可能导致更复杂的编译器, 或减慢 JVM,因为它需要做额外的工作来识别运算符的实际含义,并减少优化的机会, 以保证 Java 中运算符的行为。
(2)避免编程错误。
Java 不允许用户定义的运算符重载,因为如果允许程序员进行运算符重载,将为同一运算符赋予多种含义,这将使任何开发人员的学习曲线变得陡峭,事情变得更加混乱。据观察,当语言支持运算符重载时,编程错误会增加,从而增加了开发和交付时间。由于 Java 和 JVM 已经承担了大多数开发人员的责任,如在通过提供垃圾收集器进行内存管理时,因为这个功能增加污染代码的机会, 成为编程错误之源, 因此没有多大意义。
(3)JVM 复杂性。
从 JVM 的角度来看,支持运算符重载使问题变得更加困难。通过更直观,更干净的方式使用方法重载也能实现同样的事情,因此不支持 Java 中的运算符重载是有意义的。与相对简单的 JVM 相比,复杂的 JVM 可能导致 JVM 更慢,并为保证在 Java 中运算符行为的确定性从而减少了优化代码的机会。 4)让开发工具处理更容易。这是在 Java 中不支持运算符重载的另一个好处。省略运算符重载使语言更容易处理,这反过来又更容易开发处理语言的工具,例如 IDE 或重构工具。Java 中的重构工具远胜于 C++。
36、假设你有一个类,它序列化并存储在持久性中, 然后修改了该类以添加新字段。如果对已序列化的对象进行反序列化, 会发生什么情况
这取决于类是否具有其自己的 serialVersionUID。正如我们从上面的问题知道, 如果我们不提供 serialVersionUID, 则 Java 编译器将生成它, 通常它等于对象的哈希代码。通过添加任何新字段, 有可能为该类新版本生成的新 serialVersionUID 与已序列化的对象不同, 在这种情况下, Java 序列化 API 将引发 java.io.InvalidClassException, 因此建议在代码中拥有自己的 serialVersionUID, 并确保在单个类中始终保持不变。
37、Java 序列化机制中的兼容更改和不兼容更改是什么?
真正的挑战在于通过添加任何字段、方法或删除任何字段或方法来更改类结构, 方法是使用已序列化的对象。根据 Java 序列化规范, 添加任何字段或方法都面临兼容的更改和更改类层次结构或取消实现的可序列化接口, 有些接口在非兼容更改下。对于兼容和非兼容更改的完整列表, 我建议阅读 Java 序列化规范。 4.我们可以通过网络传输一个序列化的对象吗 是的 ,你可以通过网络传输序列化对象, 因为 Java 序列化对象仍以字节的形式保留, 字节可以通过网络发送。你还可以将序列化对象存储在磁盘或数据库中作为 Blob。 在 Java 序列化期间,哪些变量未序列化? 这个问题问得不同, 但目的还是一样的, Java 开发人员是否知道静态和瞬态变量的细节。由于静态变量属于类, 而不是对象, 因此它们不是对象状态的一部分, 因此在 Java 序列化过程中不会保存它们。由于 Java 序列化仅保留对象的状态,而不是对象本身。瞬态变量也不包含在 Java 序列化过程中, 并且不是对象的序列化状态的一部分。在提出这个问题之后,面试官会询问后续内容, 如果你不存储这些变量的值, 那么一旦对这些对象进行反序列化并重新创建这些变量, 这些变量的价值是多少?这是你们要考虑的。
38、Java 中,嵌套公共静态类与顶级类有什么不同?
类的内部可以有多个嵌套公共静态类,但是一个 Java 源文件只能有一个顶级公共类,并且顶级公共类的名称与源文件名称必须一致。