面试题

网上看了一些关于java的面试题,总结一下

  • 关系型数据库和非关系型数据库之间的优缺点
    关系型数据库:mysql、Oracle、DB2、sqlserver等,支持复杂查询,支持事务

非关系型数据库:MongoDB、Redis等,性能好,可扩展性强

层次数据库:IMS,模型简单,但对插入和删除的限制比较多

  • 守护线程

java中线程分为2类,即守护线程和用户线程,只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。(守护线程类似于非守护线程的保姆)

作用:为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器)

  • volatile关键字

    • 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
    • 禁止进行指令重排序。
  • transient关键字

只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中

  • 存在使i + 1 < i的数吗

如果i为int型,那么当i为int能表示的最大整数时,i+1就溢出变成负数了

  • Java接口的修饰符可以为?

接口的方法默认是public abstract,接口的属性默认是public static final 常量,且必须赋初值

注意:final和abstract不能同时出现

  • Java创建对象的几种方式

使用New关键字、使用Class类的newInstance方法、使用Constructor类的newInstance方法、使用Clone方法(不会调用构造函数)、使用反序列化(不会调用构造函数)

  • ArrayList初始长度为10

  • null可以强转为任何java类型

  • 对象初始化顺序

子类没有显示调用父类构造函数,不管子类构造函数是否带参数都默认调用父类无参的构造函数,若父类没有则编译出错

首先静态代码块(从父到子) –> 进入main方法打印“main start” –> 发现类HelloB有父类HelloA所以先执行HelloA类中的方法 –> 执行HelloA中的初始化块 –> 执行HelloA构造函数 –> 返回HelloB类 –> 执行HelloB类中的初始化块 –> 执行HelloB构造函数 –> 打印“main end”

总结:1.静态块 –> 初始化块 –> 构造函数 2.有父类先从父类开始执行

注意:静态代码块只被执行一次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class HelloA {

public HelloA() {
System.out.println("HelloA");
}

{ System.out.println("I'm A class"); }

static { System.out.println("static A"); }

}

public class HelloB extends HelloA {
public HelloB() {
System.out.println("HelloB");
}

{ System.out.println("I'm B class"); }

static { System.out.println("static B"); }

public static void main(String[] args) {

System.out.println("-------main start-------");
new HelloB();
new HelloB();
System.out.println("-------main end-------");
}
}

static A
static B
-------main start-------
I'm A class
HelloA
I'm B class
HelloB
I'm A class
HelloA
I'm B class
HelloB
-------main end-------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class Dervied extends Base {

private String name = "dervied";

public Dervied() {
tellName();
printName();
}

public void tellName() {
System.out.println("Dervied tell name: " + name);
}

public void printName() {
System.out.println("Dervied print name: " + name);
}

public static void main(String[] args) {

new Dervied();
}
}

class Base {

private String name = "base";

public Base() {
//返回Dervied类的tellName方法(容易出错),方法名相同,子类覆盖父类
tellName();
//返回Dervied类的printName方法(容易出错)
printName();
}

public void tellName() {
System.out.println("Base tell name: " + name);
}

public void printName() {
System.out.println("Base print name: " + name);
}
}
-------------------------------------------------------------------
Dervied tell name: null
Dervied print name: null
Dervied tell name: dervied
Dervied print name: dervied
  • catch异常的顺序

有次序之分,一般将父类异常类即Exception放在catch语句块的最后一个,中途如果有捕获到异常,则接下去的catch都不会执行

  • 关于String类型不会改变的问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Example {

String str = new String("good");

char[] ch = { 'a', 'b', 'c' };

public static void main(String args[]) {

Example ex = new Example();

ex.change(ex.str, ex.ch);

System.out.print(ex.str + " and ");

System.out.print(ex.ch);

}

public void change(String str, char ch[]) {

//String一旦赋值就不会改变了,改变里面的内容等于新生成一个String
str = "test ok";

ch[0] = 'g';

}
}

//最后结果:good and gbc
  • 关于文件流
1
2
3
4
5
6
7
8
9
10
11
12
FileInputStream in = new FileInputStream("file.dat");
in.skip(9); // 跳过前面的9个字节
int c = in.read();
System.out.println(c); // 输出为10
in.close();

//关于RandomAccessFile,查看源码后发现构造器有2个参数
RandomAccessFile in=new RandomAccessFile("file.dat","r");
in.skipBytes(9); // 跳过前面的9个字节
int c=in.readByte();
System.out.println(c); // 输出为10
in.close();
  • 关于switch…case 问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static int getValue(int i) {
int result = 0;
switch (i) {
case 1:
result = result + i;
//没有break,所以程序运行了case2,还会继续运行case3
case 2:
result = result + i * 2;
case 3:
result = result + i * 3;
}
return result;
}

//如果i为2的话,那么结果为10
  • 抽象类问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public abstract class foo {

public int constInt = 5;

public void a() {
}

public abstract void method(int a);

//不知道constInt是哪个类
constInt =constInt +5;

//抽象类方法不能有返回体
public abstract void anotherMethod() {
}
//不是抽象类方法必须要有返回体
public int method();
}

注意

abstract关键字只能修饰类和方法,不能修饰字段

普通方法一定要实现,变量可以初始化或不初始化但不能初始化后在抽象类中重新赋值或操作该变量(只能在子类中改变该变量)。

抽象类中的抽象方法(加了abstract关键字的方法)不能实现

含有抽象方法的类必须定义成抽象类

  • 抽象类与接口的区别

同:抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用。一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类。

异:接口比抽象类更加抽象,因为抽象类中可以定义构造器,可以有抽象方法和具体方法,而接口中不能定义构造器而且其中的方法全部都是抽象方法。抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的。抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法

  • 关于序列化
  1. 父类实现了Serializable,子类自动实现Serializable,不需要显式实现Serializable接口
  2. 子类自动实现Serializable,父类并不会自动实现
  • 多态

好处:

A:提高了代码的维护性(继承保证)

B:提高了代码的扩展性(由多态保证)

坏处:

无法直接使用自类的特有功能,解决方法,向下转型Base b = new Dervied();`Dervied d = (Dervied)b;`

  • 堆和栈

堆是栈的一个组成元素,栈是一种线形集合,其添加和删除元素的操作应在同一段完成

  • 关于自动拆箱和封装的问题

这里有一个需要注意的地方,常量池缓存[-127,128],所以在这个范围内的相同的数字引用地址相等

1
2
3
4
5
6
7
 public static void main(String[] args) {
Integer a = new Integer(3);
Integer b = 3; // 将3自动装箱成Integer类型
int c = 3;
System.out.println(a == b); // false 两个引用没有引用同一对象
System.out.println(a == c); // true a自动拆箱成int类型再和c比较
}
  • 关于hashcode()和eqauls()
  1. 如果两个对象eqauls()相同,那么其hashcode()一定相同
  2. 如果两个对象hashcode()相同,eqauls()不一定相同
  • 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

Java语言的方法调用只支持参数的值传递

  • JVM类的加载机制

JVM类的装载是由类加载器(ClassLoader)及其子类实现的,

1.装载:将Java二进制代码导入jvm中,生成Class文件。

2.连接:a)校验:检查载入Class文件数据的正确性 b)准备:给类的静态变量分配存储空间 c)解析:将符号引用转成直接引用

3:初始化:对类的静态变量,静态方法和静态代码块执行初始化工作。

  • 类加载器双亲委派模型

如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完全这个加载请求时,子加载器才会尝试自己去加载

  • 是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用?

静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,在调用静态方法时可能对象并没有被初始化

  • 将基本数据类型转换为字符串

一种方法是将基本数据类型与空字符串(””)连接(+)即可获得其所对应的字符串(String s = "" + i ;);另一种方法是调用String 类中的valueOf()方法返回相应字符串(String.valueOf(12);)

  • lambda表达式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 启动线程代替匿名内部类
new Thread(()-> System.out.println("lambda")).start();

//迭代
list.forEach(a -> System.out.println(a));

//map函数的使用
list.stream().map(integer -> integer*2).forEach(integer -> System.out.println(integer));

//使用reduce函数,合并
Integer integer = list.stream().reduce((sum, x) -> sum + x).get();

//使用filter函数,过滤大于15的元素
list.stream().filter(integer -> integer>15).forEach(integer -> System.out.println(integer));
  • try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后?

如果存在finally代码块,try中的return语句不会立马返回调用者,而是记录下返回值待finally代码块执行完毕之后再向调用者返回其值

  • 受检异常和运行时异常

运行时异常表示程序设计的可能有问题,受检异常跟程序运行的上下文环境有关,即使程序设计无误,也可能出现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//关于异常捕获
class Human {

public static void main(String[] args)
throws Exception {
try {
try {
throw new Annoyance();
}
catch ( Annoyance a ) {
System.out.println("Caught Annoyance");
//值得注意的是这里抛出了一个a,如果没有抛出a,则会出现编译错误,因为接下去的捕获异常是进行不到的
throw a;
}
}
catch ( Sneeze s ) {
System.out.println("Caught Sneeze");
return ;
}
finally {
System.out.println("Hello World!");
}
}
}
  • HashMap 和 TreeMap

    • (1) HashMap:适用于在Map中插入、删除和定位元素。
      • (2)Treemap:适用于按自然顺序或自定义顺序遍历键(key)。
      • (3)HashMap通常比TreeMap快一点(树和哈希表的数据结构使然),建议多使用HashMap,在需要排序的Map时候才用TreeMap.
      • (4)HashMap 非线程安全 TreeMap 非线程安全
      • (5)HashMap的结果是没有排序的,而TreeMap输出的结果是排好序的。
  • 线程的sleep()方法和yield()方法有什么区别

    • ① sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
    • ② 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
  • java写一个单例

实现一个单例有两点注意事项,①将构造器私有,不允许外界通过构造器创建对象;②通过公开的静态方法向外界返回类的唯一实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//饿汉式
//第一步,私有化构造器,防止外部生成新的实例
private Singleton() {

}
//创建一个实例
private static Singleton instance = new Singleton();
//将实例通过一个公共静态方法返回
public static Singleton getInstance() {
return instance;
}


//懒汉式
private Singleton() {

}

private static Singleton instance = null;

public static Singleton getInstance() {
if (instance == null){
instance = new Singleton();
}
return instance;
}
  • 排序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//冒泡
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - i - 1; j++) {
if (a[j] > a[j + 1]) {
int temp = a[j + 1];
a[j + 1] = a[j];
a[j] = temp;
}
}
}

//选择
for (int i = 0; i < a.length - 1; i++) {
for (int j = i + 1; j < a.length; j++) {
if (a[j] > a[i]) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
  • 乐观锁和悲观锁

悲观锁,每次去拿数据都会上锁,这样其他线程想拿这个数据就会block直到它拿到锁,如读锁,写锁,表锁

乐观锁,去拿数据不会上锁,但是更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制查看,乐观锁适用于多读的应用类型,这样可以提高吞吐量

  • 线程池的作用
  1. 降低资源消耗,不用每次都去创建一个新的线程
  2. 提高响应速度,任务到达不需要等到线程创建就能立即执行
  3. 提高线程可管理性
  • Class.forName()ClassLoader的区别

ClassLoader会将文件加载进jvm,不会执行static中的内容, Class.forName()不但会加载进jvm,还会对类进行解释,执行其static块

  • java的基本类型和字节

    • boolean 环境而定
    • byte 1字节
    • short 2字节
    • char 2字节
    • int 4字节
    • long 8字节
    • float 4字节
    • double 8字节
  • 为什么String类型为final类型

    • 设计安全–不允许任何人定义String的子类,引用String一定是引用一个String对象,而不可能是其他的类
    • 一旦被创建是不能够被修改的
    • 设计成final,JVM不用对相关方法在虚函数表中查询。而是直接定位到该相关方法上,提交效率
  • arraylist 和 linkedlist 区别

    • ArrayList实现了List接口,它是以数组的方式来实现的,数组的特性是可以使用索引的方式来快速定位对象的位置,因此对于快速的随机取得对象的需求,使用ArrayList实现执行效率上会比较好
    • 在删除可插入对象的动作时,为什么ArrayList的效率会比较低呢?
      • 因为ArrayList是使用数组实现的,若要从数组中删除或插入某一个对象,需要移动后段的数组元素,从而会重新调整索引顺序,调整索引顺序会消耗一定的时间,所以速度上就会比LinkedList要慢许多. 相反,LinkedList是使用链表实现的,若要从链表中删除或插入某一个对象,只需要改变前后对象的引用即可!
  • 例举关于String的方法

    • trim
    • format
    • matches
    • startswith

      • 确定此字符串实例的开头是否与指定的字符串匹配。
    • endswith
    • getbytes
    • isEmpty
    • getchars
    • join

      • 官方案例String message = String.join("-", "Java", "is", "cool");message returned is: "Java-is-cool"
  • 给定链表头和尾中间颠倒,如a->b->c->d->e改成a->d->c->b->e该如何实现,并计算其大O算法

  • 给定4个数字,如何将它组成最大的数字,如18,6,70,9组成970618

  • 了解大O算法
  • list的remove方法,remove(2),指的是移除索引为2的数字,而不是移除数字2
  • 关于try中有return,那么finally的运行结果
  • 关于学生管理系统的数据库表设计
  • 需要自己写一个小项目,简单电商项目
  • 推荐书籍:Head First设计模式,Head First.OOA & D
    总结一下 :还是特么太闲,从基础开始抓起吧
赏个🍗吧
0%