面试题简单整理-JavaSE基础

面试题整理-JavaSE基础

Java三大特性

1 封装
2 继承
3 多态

若有人问第四个特性则说抽象

基本数据类型

  • 整型
    • byte 1字节
    • int 2字节
    • short 4字节
    • long 8字节
  • 浮点型
    • float 4字节
    • doublue 8字节
  • 字符型
    • char 2字节
  • 布尔型
    • boolean (暂不确定 不到1字节)

Object类常用方法

  1. wait()
  2. sleep()
  3. getClass()
  4. notify()/notifyAll()
wait与sleep区别

最大的不同是在等待时 wait 会释放锁,而 sleep 一直持有锁。

Clone 深拷贝与浅拷贝

User user1 = new User('张三',15);
User user2 = user1;
System.out.println(user1);
System.out.println(user2);
//user1与user2地址相同 属于对象引用

User user1 = new User('张三',15);
User user2 = (User)user1.clone();
System.out.println(user1);
System.out.println(user2);
//user1与user2地址不同 属于对象复制 使用clone方法创建了一个新的对象

浅拷贝:被复制对象的所有值属性都含有与原来对象的相同,且对象地址值相同。
深拷贝:在浅拷贝操作基础上,创建一个新的对象,地址值与原对象不同。

如果想要深拷贝一个对象,这个对象必须要实现 Cloneable 接口,实现clone方法,并且在 clone 方法内部,把该对象引用的其他对象也要 clone 一份,这就要求这个被引用的对象必须也要实现Cloneable 接口并且实现 clone 方法。

运算符

逻辑与短路

&&之所以称为短路运算是因为,如果&&左边的表达式的值是 false,右边的表达式会被直接短路掉,不会进行运算。很多时候我们可能都需要用&&而不是&,例如在验证用户登录时判定用户名不是 null 而且不是空字符串,应当写为 username != null &&!username.equals(""),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的 equals 比较,否则会产生 NullPointerException 异常。注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此

==与equals方法区别
  1. ==是运算符 equals是方法
  2. ==如果比较的是基本数据类型 则是比较他们的值 如果是对象 则比较他们的地址值
  3. equals用来比较两个对象的值是否相等,但要重写hashcode方法

下面内容来自JAVA中Integer的==和equals注意l

equals(Object obj)方法,在equals(Object obj)方法中,会先判断参数中的对象obj是否是Integer同类型的对象,如果是则判断值是否相同,值相同则返回true,值不同则返回false,如果obj不是Integer类的对象,则返回false。
需要注意的是:当参数是基本类型int时,编译器会给int自动装箱成Integer类,然后再进行比较。

  1. 基本类型(值类型)之间无法使用equals比较。
  2. equals参数为值类型,则参数会进行自动装箱为包装类型,之后请参见第3点。
  3. equals参数为包装类型,则先比较是否为同类型,非同类型直接返回false,同类型再比较值。

示例:
new Long(0).equals(0) 为 false,equals参数默认为int类型,装箱为Integer类型,不同类型直接返回false
new Integer(500).equals(500) 为 true,equals参数默认为int类型,装箱为Integer类型,相同类型再比较值返回true
new Integer(500).equals((short)500) 为 false,equals参数为byte类型,装箱为Byte类型,不同类型直接返回false
new Long(0).equals(0L) 为 true,equals参数为long类型,装箱为Long类型,相同类型再比较值返回true

“==”比较

  1. 基本类型之间互相比较:以值进行比较
  2. 一边是基本类型,一边是包装类型
    同类型的进行比较,如Integer 与int,Long与long进行==比较时,会自动拆箱比较值
    不同类型之间进行比较,则会自动拆箱,且会进行自动向上转型再比较值(低级向高级是隐式类型转换如:byte<short<int<long<float<double,高级向低级必须强制类型转换)
  3. 两边都是包装类型则直接比较引用地址,但是要注意IntegerCache除外。
+=(含隐性强制类型转换)
byte i = 1;
i = i + 1;
//不能编译成功,这是两个动作,先求和再赋值,求和时i自动类型提升,求和结果是int类型,
//但是因为编译器无法判断数值大小,所以无法为我们强制转换类型
byte i = 0;
i += 1;
//+=是一个赋值运算符,在底层是一个动作并且有一个强制转换的一个过程

方法重载与方法重写

方法重载
  1. 方法名相同,参数列表顺序,名称,类型,个数不同
  2. 与返回值无关,可以存在于父类子类同类中
  3. 可以有不同的修饰符,抛出不同的异常
方法重写
  1. 参数列表类型个数和返回值类型必须与被重写方法一致
  2. 构造方法不能被重写,final修饰的方法不能被重写,static修饰的方法不能被重写
  3. 访问权限不能比父类中被重写方法的权限低
  4. 重写后的方法可以抛出任何非强制性异常,无论被重写方法是否抛出异常,但重写方法就不能抛出新的强制性异常,或者比被重写方法更广泛的异常,反之则可以。

String/StringBuffer/StringBuilder

String

final修饰类,不可变,线程安全。 注:final修饰的方法/类,不能被重写/继承
属于引用数据类型

StringBuffer与StringBuilder

StringBuffer是线程安全,执行效率较慢,适用于多线程下操作字符串缓冲区,大量数据。
StringBuilder是线程不安全的,适用于单线程下操作字符串缓冲区大量数据。

异常处理

Exception
  • CheckedException编译时异常
  • RuntimeException运行时异常
    • 常见异常
      • 1)java.lang.NullPointerException 空指针异常;出现原因:调用了未经初始化的对象或者是不存在的对象。
      • 2)java.lang.ClassNotFoundException 指定的类找不到;出现原因:类的名称和路径加载错误;通常都是程序试图通过字符串来加载某个类时可能引发异常。
      • 3)java.lang.NumberFormatException 字符串转换为数字异常;出现原因:字符型数据中包含非数字型字符。
      • 4)java.lang.IndexOutOfBoundsException 数组角标越界异常,常见于操作数组对象时发生。
      • 5)java.lang.IllegalArgumentException 方法传递参数错误。
      • 6)java.lang.ClassCastException 数据类型转换异常。
      • 7)java.lang.NoClassDefFoundException 未找到类定义错误。
      • 8)SQLException SQL 异常,常见于操作数据库时的 SQL 语句错误。
      • 9)java.lang.InstantiationException 实例化异常。
      • 10)java.lang.NoSuchMethodException 方法不存在异常。
Error

是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM出现的问题。

异常处理流程

系统对异常的处理使用统一的异常处理流程:

1、自定义异常类型。

2、自定义错误代码及错误信息。

3、对于可预知的异常由程序员在代码中主动抛出,由SpringMVC统一捕获。

4、对于不可预知的异常(运行时异常)由SpringMVC统一捕获Exception类型的异常。

5、可预知的异常及不可预知的运行时异常最终会采用统一的信息格式(错误代码+错误信息)来表示,最终也会随请求响应给客户端。

在这里插入图片描述

//自定义异常类
public class CustomException extends RuntimeException {
	private ResultCode resultCode;
	public CustomException(ResultCode resultCode) {
		//异常信息为错误代码+异常信息
		super("错误代码:"+resultCode.code()+"错误信息:"+resultCode.message());
		this.resultCode = resultCode;
	}
	public ResultCode getResultCode(){
		return this.resultCode;
	}
}

//控制器增强
@ControllerAdvice
public class ExceptionCatch {
	static{
		//在这里加入一些基础的异常类型判断
		builder.put(HttpMessageNotReadableException.class,CommonCode.INVALIDPARAM);
		builder.put(NullPointerException.class,CommonCode.DATAISNULL);
	}
	private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionCatch.class);
	//使用EXCEPTIONS存放异常类型和错误代码的映射,ImmutableMap的特点的一旦创建不可改变,并且线程安全
	private static ImmutableMap<Class<? extends Throwable>,ResultCode> EXCEPTIONS;
	//使用builder来构建一个异常类型和错误代码的异常
	protected static ImmutableMap.Builder<Class<? extends Throwable>,ResultCode> builder =
	ImmutableMap.builder();
	//捕获Exception异常
	@ResponseBody
	@ExceptionHandler(Exception.class)
	public ResponseResult exception(Exception e) {
		LOGGER.error("catch exception : {}\r\nexception: ",e.getMessage(), e);
		if(EXCEPTIONS == null){
			EXCEPTIONS = builder.build();
			final ResultCode resultCode = EXCEPTIONS.get(e.getClass());
			final ResponseResult responseResult;
			if (resultCode != null) {
				responseResult = new ResponseResult(resultCode);
			} else {
				responseResult = new ResponseResult(CommonCode.SERVER_ERROR);
		}
		return responseResult;
	}
	
	//捕获 CustomException异常
	@ExceptionHandler(CustomException.class)
	@ResponseBody
	public ResponseResult customException(CustomException e) {
		LOGGER.error("catch exception : {}\r\nexception: ",e.getMessage(), e);
		ResultCode resultCode = e.getResultCode();
		ResponseResult responseResult = new ResponseResult(resultCode);
		return responseResult;
	}
}

I/O

字节流
  • 输入流(inputStream)
    • FileInputStream(多用于文件读取)
    • BufferedInputStream
  • 输出流(outputStream)
    • FileOutStream(多用于文件写入)
    • BufferedOutStream
字符流
  • 输入流(Reader)
    • InputStreamReader(字节转换字符流)
    • BufferedReader
    • FileReader(多用于读取文本文件)
  • 输出流(Writer)
    • OutputStreamWriter(字节转换字符流)
    • FileWriter(多用于写入文本文件)

字符流适用于文本较多的传输,对于视频、图片这类的文件只能通过字节流传输

集合

  • Iterator
    • Map
      • HashMap(数组+链表,1.8后容量超过8时链表变为红黑树,无序,支持null值和键)
      • LinkedHashMap(在HashMap的基础上保持了顺序)
      • HashTable(线程安全,关键方法用sychornized修饰,不支持null值和键)
      • TreeMap
    • List
      • ArrayList(底层数组,增删慢,查询快)
      • LinkedList(底层链表,增删快,查询慢)
      • Vector(底层数组,线程安全,增删查询慢)
    • Set
      • HashSet(无序)
      • LinkedHashSet(有序)
      • TreeSet

多线程

创建多线程的方式
  1. 继承Thread类
  2. 实现Runnable接口
  3. 使用Callable和Future创建线程
  4. 使用线程池Executor框架
线程池作用
  1. 降低资源消耗
  2. 提高响应速度
  3. 提高线程客观理性
为什么使用线程池?

减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务
可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为因为消耗过多的内存,而把服务器累趴下

并发

并发包
名称作用
Lock
ConditionCondition的功能类似于在传统的线程技术中的Object.wait()和Object.notify()的功能
Executors线程池
ReentrantLock可重入的互斥锁
ConcurrentHashMap其内部使用锁分段技术,维持这锁Segment的数组,在Segment数组中又存放着Entity[]数组,内部hash算法将数据较均匀分布在不同锁中
AtomicInteger原子类
并发队列

1.阻塞队列(锁机制实现)
2.非阻塞队列(CAS实现)

CAS算法是由硬件直接支持来保证原子性的,有三个操作数:内存中的值V、旧值A和新值B,当且仅当V符合预期值A时,CAS用新值B原子化地更新V的值,否则什么都不做

死锁
产生条件
  1. 互斥条件:线程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某 资源仅为一个线程所占有
  2. 不剥夺条件:线程所获得的资源在未使用完毕之前,不能被其他线程强行夺走,即只能由获得该资源的线程自己来释放
  3. 请求和保持条件:线程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他线程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放
  4. 循环等待条件:存在一种线程资源的循环等待链,链中每一个线程已获得的资源同时被链中下一个线程所请求
如何避免
  1. 注意加锁顺序
  2. 设置加锁时限
  3. 对代码进行检测
数据结构

数组

固定长度,添加数据时,会添加索引,根据索引确定值的位置,查找速度很快,但添加需要确定索引位置后将数据添加入对应的位置

在这里插入图片描述
链表

链表添加数据时,将之前的数据指向添加的数据,用指针连接,新添加的数据会在头部,添加速度比数组快,但查询时,若要查的数据在链表最后一位,那么所消耗时间很长(On)

在这里插入图片描述

二叉树

二叉树的结构由根节点出发,左边是比根节点小的数,右边是比根节点大的数,查询耗时复杂度On

在这里插入图片描述
红黑树

简而言之,就是会自动平衡的二叉树,有几个特性:

  1. 节点是红色或黑色。
  2. 根节点是黑色。
  3. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
  4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点

在这里插入图片描述
B-Tree

B-tree是一种常见的数据结构。使用B-tree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度。这个数据结构一般用于数据库的索引,综合效率较高。

在这里插入图片描述
B+Tree

对于B+树,其结点结构与B-tree相同,不同的是各结点的关键字和可以拥有的子结点数。
这两种处理索引的数据结构的不同之处:
1.B树中同一键值不会出现多次,并且它有可能出现在叶结点,也有可能出现在非叶结点中。而B+树的键一定会出现在叶结点中,并且有可能在非叶结点中也有可能重复出现,以维持B+树的平衡
2.因为B树键位置不定,且在整个树结构中只出现一次,虽然可以节省存储空间,但使得在插入、删除操作复杂度明显增加。B+树相比来说是一种较好的折中
3.B树的查询效率与键在树中的位置有关,最大时间复杂度与B+树相同(在叶结点的时候),最小时间复杂度为1(在根结点的时候)。而B+树的时间复杂度对某建成的树是固定的

在这里插入图片描述
可以自行去测试,数据结构

JMM线程内存模型

在这里插入图片描述

volatile关键字
  1. 可见性
  2. 有序性(禁止指令重排序)
  3. 不保证原子性

保证变量在多线程中的可见性
底层通过汇编语言lock前缀指令,锁定这块内存区域的缓存并写回主程序,lock指令作用:
1.将缓存数据立即写到系统内存
2.开启MESI协议(总线嗅探机制)

底层实现
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值