[java] 面试题库

自己复习用

一、JavaSE部分

Java基础

关于声明一个字符串是否创建了对象

  • 由字面量声明的字符串不一定创建了对象

String a = “123”;是否创建了对象要看字符串常量池中,是否已经有了"123"这个对象,如果有,那么这句代码就没有创建对象,如果没有,那么就在字符串常量池中创建了一个"123"对象.

  • 通过new出来的字符串一定创建了对象

String a = new String(“123”),无论字符串常量池是否有"123"这个对象,这句代码都会创建对象,区别就在于创建了一个还是两个.假如常量池中没有,那么就分别在常量池和堆区都分别创建了"123"对象。如果常量池中有该对象,那么就只在堆区中创建一个"123"对象。

Integer类型的如果值超过了[-128,127]会新建一个对象,

Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 127;
Integer i4 = 127;
System.out.println(i1 == i2);//true
System.out.println(i3 == i4);//false

字符串常量池

https://tech.meituan.com/2014/03/06/in-depth-understanding-string-intern.html

4、== 比较的是什么?

“ == ”对比两个对象类型基于内存引用,如果两边是基本类型,就是比较数值是否相等。

9、为啥有时会出现 4.0-3.6=0.40000001 这种现象?

原因简单来说是这样:2 进制的小数无法精确的表达 10 进制小数,计算机在计算 10 进制小数的过程中要先转换为 2 进制进行计算,这个过程中出现了误差。可以使用Bigdecimal类进行浮点型数据的运算

19、&和&&的区别?

&运算符有两种用法:(1)按位与;(2)逻辑与。

&&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是 true 整个表达式的值才是true。&&之所以称为短路运算是因为,如果&&左边的表达式的值是 false,右边的表达式会被直接短路掉,不会进行运算。

23、Java 中是如何支持正则表达式操作的?

正则表达式就是记录文本规则的代码。正则表达式就是在进行字符串匹配和处理的时候最为强大的工具

Java 中的 String 类提供了支持正则表达式操作的方法,包括:matches()、replaceAll()、replaceFirst()、split()。此外,Java 中可以用 Pattern 类表示正则表达式对象,它提供了丰富的 API 进行各种正则表达式操作

float与double的区别

float是单精度类型,精度是8位有效数字
double是双精度类型,精度是17位有效数字
当你不声明的时候,默认小数都用double来表示,所以如果要用float的话,则应该在其后加上f
例如:float a=1.3;则会报错提示不能将double转化成float ,应该改成float a=1.3f
注意float是8位有效数字,第7位数字将会产生四舍五入
所以如果一个float变量 这样定义: float a=1.32344435; 则第7位将产生四舍五入(5及5以下的都将舍去)

69、a=a+b与a+=b有什么区别吗?

+= 操作符会进行隐式自动类型转换,此处a+=b隐式的将加操作的结果类型强制转换为持有结果的类型, 而a=a+b则不会自动进行类型转换.

short s1= 1;
s1 = s1 + 1;//报错:cannot convert from int to short
s1 += 1;//正确

静态变量使用场景

静态变量生命周期较长,而且不易被系统回收,因此如果不能合理地使用静态变量,就会适得其反,造成大量的内存浪费,所谓过犹不及。因此,建议在具备下列全部条件的情况下,尽量使用静态变量:

(1)变量所包含的对象体积较大,占用内存较多。 如果在变量A之前添加了static关键字,当你创建很多个类对象时系统中只保存着A对象的一份拷贝,而且该类的所有对象实例共享这份拷贝,这无疑节约了大量的不必要的内存开销。

(2)变量所包含的对象生命周期较长。

(3)变量所包含的对象数据稳定。

(4)该类的对象实例有对该变量所包含的对象的共享需求。

如果变量不具备上述特点建议你不要轻易地使用静态变量,以免弄巧成拙。

关键字

4、final 关键字怎么用的?

当用 final 修饰一个类时,表明这个类不能被继承。 断子绝孙final
final 类中的成员变量可以根据需要设为 final,但是要注意 final 类中的所有成员方法都会被隐式地指定为 final 方法。

对于一个 final 变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

7、”static”关键字是什么意思?

“static”关键字表明一个成员变量或者是成员方法可以在没有所属的类的实例变量的情况下被访问。
Java 中 static 方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而 static 方法是编译时静态绑定的。static 方法跟类的任何实例都不相关,所以概念上不适用。

26、throws,throw,try,catch,finally分别代表什么意义?

Java 的异常处理是通过 5 个关键词来实现的:try、catch、throw、throws和 finally。

一般情况下是用 try 来执行一段程序,如果出现异常,系统会抛出(throws)一个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)由缺省处理器来处理。

用 try 来指定一块预防所有”异常”的程序。紧跟在 try 程序后面,应包含一个 catch 子句来指定你想要捕捉的”异常”的类型。throw 语句用来明确地抛出一个”异常”。throws 用来标明一个成员函数可能抛出的各种”异常”。Finally 为确保一段代码不管发生什么”异常”都被执行一段代码。

面向对象

3、String 为啥不可变?

String 不可变是因为在 JDK 中 String 类被声明为一个 final 类,且类内部的 value 字节数组也是 final 的

如果字符串是可变的则会引起很严重的安全问题,譬如数据库的用户名密码都是以字符串的形式传入来获得数据库的连接,因为字符串是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子改变字符串指向的对象的值造成安全漏洞;

因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享

5、请列举你所知道的 Object 类的方法。

Object()默认构造方法。
clone() 创建并返回此对象的一个副本。
equals(Object obj) 指示某个其他对象是否与此对象“相等”。
toString()返回该对象的字符串表示。
getClass()返回一个对象的运行时类。
hashCode()返回该对象的哈希码值。
notify()唤醒在此对象监视器上等待的单个线程。
notifyAll()唤醒在此对象监视器上等待的所有线程。
wait()导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。

12、讲讲什么是泛型?

泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

13、解释 extends 和 super 泛型限定符-上界不存下界不取

泛型中上界和下界的定义

  • 上界 <? extend Fruit>
  • 下界 <? super Apple>

上界和下界的特点

  • 上界的 list 只能 get,不能 add(确切地说不能 add 出除 null 之外的对象,包括 Object)
  • 下界的 list 只能 add,不能 get

上界 <? extend Fruit> ,表示所有继承 Fruit 的子类,但是具体是哪个子类,无法确定,所以调用 add 的时候,要 add 什么类型,谁也不知道。但是 get 的时候,不管是什么子类,不管追溯多少辈,肯定有个父类是 Fruit,所以,我都可以用最大的父类 Fruit 接着,也就是把所有的子类向上转型为 Fruit。

下界 <? super Apple>,表示Apple的所有父类,包括Fruit,一直可以追溯到老祖宗Object 。那么当我 add 的时候,我不能 add Apple 的父类,因为不能确定 List 里面存放的到底是哪个父类。但是我可以 add Apple 及其子类。因为不管我的子类是什么类型,它都可以向上转型为 Apple及其所有的父类甚至转型为 Object 。但是当我 get 的时候,Apple 的父类这么多,我用什么接着呢,除了 Object,其他的都接不住。

18、Comparable 和 Comparator 接口是干什么的?列出它们的区别。

Comparable定义在java.lang包里。接口里只定义了compareTo()这一个方法,方法传入一个对象与自身进行比较,返回1,0,-1分别表示比自身大,相等,小

Comparator定义与java.util包中,代表着一个角色,这个角色的功能是对传入的两个元素进行大小的比较,并且返回结果。有两种应用:

  1. 一个对象不支持自己和自己比较(没有实现Comparable接口),但是又想对两个对象进行比较

  2. 一个对象实现了Comparable接口,但是开发者认为compareTo方法中的比较方式并不是自己想要的那种比较方式

23、内部类

public class Outer {//外部类
    
	public class Inner{//成员内部类
	}
	
	public static class Inner{//静态内部类
	//不能访问外部类的内容,除非外部类也是静态的
	}
	
	public void method(){
		class Inner{//局部内部类
		}
	}
	
	new Apple().eat();//匿名内部类
}
//一个java类中可以有多个class类,但是只能有一个public class类
class Apple{
	public void eat(){}
}

32、请问 Query 接口的 list 方法和 iterate 方法有什么区别?

  • list()方法无法利用一级缓存和二级缓存(对缓存只写不读),它只能在开启查询缓存的前提下使用查询缓存;iterate()方法可以充分利用缓存,如果目标数据只读或者读取频繁,使用 iterate()方法可以减少性能开销。
  • list()方法不会引起 N+1 查询问题,而 iterate()方法可能引起 N+1 查询问题

集合

16、快速失败(fail-fast)和安全失败(fail-safe)的区别是什么?

  • java.util 包下面的所有的集合类都是快速失败的,而 java.util.concurrent 包下面的所有的类都是安全失败的。

  • 迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量(表示修改次数)。集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否改变,否的话就返回遍历;否则抛出ConcurrentModificationException 异常(表示已经有其他线程修改了集合),终止遍历。

  • 采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,故不会抛 ConcurrentModificationException 异常

x、请你说说Static Nested Class静态内部类 和 Inner Class内部类的不同

Static Nested Class静态内部类可以在不创建实例的条件下直接创建,因为它只访问静态方法和成员,它和类直接绑定,并且不能访问任何非静态类型的方法和成员变量。但是Inner class内部类是和实例绑定的,他可以访问实例的成员变量和方法,所以在创建他之前必须先创建一个实例,然后通过实例创建它才行。

线程

85、在 java 中守护线程和本地线程区别

java 中的线程分为两种:守护线程(Daemon)和用户线程(User)。 任何线程都可以设置为守护线程和用户线程,通过方法 Thread.setDaemon(boolon);true 则把该线程设置为守护线程,反之则为用户线程。Thread.setDaemon()必须在 Thread.start()之前调用,否则运行时会抛出异常。
两者的区别:
唯一的区别是判断虚拟机(JVM)何时离开,Daemon 是为其他线程提供服务,如果全部的 User Thread 已经撤离,Daemon 没有可服务的线程,JVM 撤离。也可以理解为守护线程是 JVM 自动创建的线程(但不一定),用户线程是程序创建的线程;比如 JVM 的垃圾回收线程是一个守护线程,当所有线程已经撤离,不再产生垃圾,守护线程自然就没事可干了,当垃圾回收线程是 Java 虚拟机上仅剩的线程时,Java 虚拟机会自动离开。

14、如何理解 Java 多线程回调方法?

所谓回调,就是客户程序 C 调用服务程序 S 中的某个方法 A,然后 S 又在某个时候反过来调用 C 中的某个方法 B,对于 C 来说,这个 B 便叫做回调方法。

18、在监视器(Monitor)内部,是如何做线程同步的?

监视器和锁在 Java 虚拟机中是一块使用的。监视器监视一块同步代码块,确保一次只有一个线程执行同步代码块。每一个监视器都和一个对象引用相关联。线程在获取锁之前不允许执行同步代码。

12、为什么wait, notify 和 notifyAll这些方法不在thread类里面?

明显的原因是JAVA提供的锁是对象级的而不是线程级的,每个对象都有锁,通过线程获得。如果线程需要等待某些锁那么调用对象中的wait()方法就有意义了。如果wait()方法定义在Thread类中,线程正在等待的是哪个锁就不明显了。简单的说,由于wait,notify和notifyAll都是锁级别的操作,所以把他们定义在Object类中因为锁属于对象 。

保证接口幂等性

  1. 唯一id。每次操作,都根据操作和内容生成唯一的id,再执行之前判断id是否存在,如果不存在则执行后续操作并保存到redis中
  2. 服务端提供发送token的端口,业务调用接口前先获取token,然后调用业务接口时把token带过去,服务器判断token是否存在redis中,执行完需要删除redis中的token
  3. 表添加唯一约束
  4. 版本控制
  5. 状态控制。处于未支付的订单才能修改为已支付

JDK

2、JDK 和 JRE 的区别是什么?

JDK:java开发工具包
JRE:运行环境或运行时类库
JVM:java虚拟机

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值