java面试题

本文详细梳理了Java面试中的常见问题,涵盖了JavaSE部分的关键知识点,如数据类型转换、逻辑运算符的区别、switch语句的支持类型、面向对象特征、抽象类与接口的区别、线程与异常处理、集合类的区别、并发编程中的 volatile 关键字、线程状态、序列化与反序列化、线程池、异常处理、以及JVM内存模型。此外,还涉及到Spring框架的IOC和AOP概念、Spring中Bean的获取方式、事务管理、MyBatis的特性、MVC模式以及Redis和Nginx的使用场景和特性。这些问题都是Java开发者在面试中可能会遇到的经典题目。
摘要由CSDN通过智能技术生成

希望对大家有帮助!!!

##JavaSE部分
###基本数据类型之间的转换方式?
1)隐式转换—从小类型到大类型可以自动完成
2)强制转化—从大类型到小类型需要强制转换
因为大类型的精度值大于小类型,取值范围大于小类型,所以,当使用强制转化时,有可能会造成精度的损失或者溢出,所以,在使用强制转化时要求显式的告诉编译器,正在进行强制转换。

###&和&&的区别?
两者都可以当逻辑运算符使用,表示‘与’运算,&&有短路的说法,&没有
&可以当按位运算符使用(两边都是整数时),&&不可以

###switch分支语句可以作用在哪些数据类型上?
支持的类型有:byte,short,int,char,String(jdk1.7后),枚举

###面向对象的特征有哪些?
抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面
封装:把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口
继承: 继承是从已有类得到继承信息创建新类的过程,提供继承信息的类被称为父类(超类、基类);
得到继承信息的类被称为子类(派生类)
多态:指允许不同子类型的对象对同一行为作出不同的响应

###抽象类和接口的区别?
抽象类可以有构造方法,接口中不能有构造方法。
抽象类中可以有普通成员变量,接口中没有普通成员变量。
抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽
象的普通方法。
抽象类中的抽象方法的访问类型可以是public,protected和默认default,但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
抽象类中可以包含静态方法(static),接口中不能包含静态方法。
抽象类和接口中都可以包含静态成员变量(static),抽象类中的静态成员变量的访问类型
可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public
static final类型。
一个类可以实现多个接口,但只能继承一个抽象类。

###Java中值传递指的是什么?
1)“在Java里面参数传递都是值传递”这句话的意思是:值传递是传递值的拷贝,
按引用传递其实传递的是引用的地址值,所以统称值传递。
2)在Java里面只有基本类型和按照下面这种定义方式的String是值传递,其它的都是
引用传递,就是直接使用双引号定义字符串方式:String str = “Welcome to Tedu”;

###Override与Overload两者之间的区别?
重载(Overload):同类内部,同名不同参(参数类型不同,顺序不同,个数不同)
重写(Override):父子类之间,同名且同参,遵循2小1大原则

  1. 子类声明抛出的异常必须小于等于父类
  2. 子类返回类型必须小于等于父类
  3. 子类的访问控制修饰符必须大于等于父类

###JavaBean有哪些规范?
Java Bean: 类型符合特定规则的Java 对象

  1. 实现Serializable接口
  2. 提供无参构造器
  3. 为私有属性提供 getter / setter /isXXX 方法
  4. 可以有少量的业务实现

必须有包

  • 必须有无参数构造器
  • 实现序列化接口
  • 可以包含 getXxx setXxx 声明的 Bean属性 xxx
    • Bean 属性就是指 get 和 set 方法, Bean属性不是对象属性!
    • boolean类型的Bean属性, 可以 getXxx 或 isXxx

###造成Java类加载时机有哪些?

  1. 创建该类对象
  2. 包含了静态代码块
  3. 访问了类中的静态成员
  4. 使用反射机制(.class 或 getClass())

###String,StringBuffer, StringBuilder的区别是什么?
String是字符串常量,StringBuffer和StringBuilder是字符串变量;
StringBuffer是线程安全的,StringBuilder是非线程安全的;
具体来说String是一个不可变的对象,每次修改String对象实际上是创新新对象,并将引用指向新对象。效率很低。StringBuffer是可变的,即每次修改只是针对其本身,大部分情况下比String效率高,StringBuffer保证同步(synchronized),所以线程安全。StringBuilder没有实现同步,所以非线程安全。

###简述JVM垃圾回收机制?
垃圾回收器(Garbage Collection,GC)是JVM自带的一个线程(自动运行着的程序),用于回收没有任何引用所指向的对象。
GC线程会从栈中的引用变量开始跟踪,从而判定哪些内存是正在使用的,若GC无法跟踪到某一块堆内存,那么GC就认为这块内存不再使用了,即为可回收的,但是,java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。

###volatile关键字
一、volatile的内存语义是:
当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值立即刷新到主内存中。
当读一个volatile变量时,JMM会把该线程对应的本地内存设置为无效,直接从主内存中读取共享变量。
二、volatile底层的实现机制
如果把加入volatile关键字的代码和未加入volatile关键字的代码都生成汇编代码,会发现加入volatile关键字的代码会多出一个lock前缀指令。
1 、重排序时不能把后面的指令重排序到内存屏障之前的位置
2、使得本CPU的Cache写入内存
3、写入动作也会引起别的CPU或者别的内核无效化其Cache,相当于让新写入的值对别的线程可见。
三、volatile的使用场景
1、修饰状态变量
2、单例模式的实现,双重检查锁定

###简述final、finally、finalize的区别?
final:java中的关键字,修饰符
1 .如果一个类被声明为final,就意味着它不能再派生出新的子类,不能作为父类被继承。 因此,一个类不能同时被声明为absrtact抽象类的和final的类。
2.如果将变量或者方法声明为final,可以保证它们在使用中不被改变。
2.1 被声明为final的变量必须在声明时给初值,而在以后的引用中只能读取,不可修改。
2.2被声明final的方法只能使用,不能重写。

finally:java的一种异常处理机制
finally是对Java 异常处理模型的最佳补充。finally 结构使代码总会执行,而不管有无异常发生。使用 finally 可以维护对象的内部状态,并可以清理非内存资源。特别是在关闭数据库连接这方面,如果程序员把数据库连接的close()方法放到finally中,就会大大降低程序出错的几率。

finalize:Java中的一个方法名
Java使用finalize()方法在垃圾收集器将对象从内存中清除出去前,做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在Object类中定义的,因此所有的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的

###简述对Java异常的理解?
异常继承关系
Throwable
|-Error
| - StackOverflowError 死递归
| - OutOfMemoryError 垃圾对象太多
|-Exception
| - RuntimeException(运行时异常) - 未检查异常
NullPointerException
ArrayIndexOutOfBoundsException
ClassCastException
ArithmeticException
| - 非RuntimeException(编译时异常) - 已检查异常
IOException
FileNotFoundException
SQLException
InterruptedException
1)未检查异常:
常是程序粗心造成的,如果编程人员足够的认真和细致,这种异常可以避免出现
这种异常可处理可不处理
2) 已检查异常:
程序员已经对代码进行了足够认真细致的检查,但是还不能避免异常的出现
这种异常必须要做出处理
处理方法2种:
1) 抛出: throws XXXException
2) 捕获: try{…} catch(XXXException e){…}finally{ {…}
处理原则: 谁知情谁处理,谁造成谁处理

###简述ArrayList与Vector的区别?
1)Vector是线程安全的(方法上都有同步锁),ArrayList是非线程安全的(JDK5.0后)
2) Vector线程安全,但是性能低,ArrayList性能高,保证不了安全性
3) ArrayList扩容时: 增长大约0.5倍,Vector扩容时: 增长1倍 ArrayList、Vector默认初始容量为10
ArrayList实现了List接口,继承了AbstractList,底层是数组实现的,一般我们把它认为是可以自增扩容的数组。它是非线程安全的,一般多用于单线程环境下,它实现了Serializable接口,因此它支持序列化,能够通过序列化传输(实际上java类库中的大部分类都是实现了这个接口的),实现了RandomAccess接口,支持快速随机访问(只是个标注接口,并没有实际的方法),这里主要表现为可以通过下标直接访问(底层是数组实现的,所以直接用数组下标来索引),实现了Cloneable接口,能被克隆。

###简述HashMap和Hashtable的区别?
历史原因:Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现
同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的
值:只有HashMap可以让你将空值作为一个表的条目的key或value
HashMap 初始化大小是 16 ,扩容因子默认0.75(可以指定初始化大小,和扩容因子)
扩容机制.(当前大小 和 当前容量 的比例超过了 扩容因子,就会扩容,扩容后大小为 一倍。例如:初
始大小为 16 ,扩容因子 0.75 ,当容量为12的时候,比例已经是0.75 。触发扩容,扩容后的大小为
32.)

###ConcurrentModificationException产生的原因及如果避免?
通过迭代器迭代集合,并用集合自身的删除方法进行元素操作时,
容易发生: ConcurrentModificationException

  1. 使用迭代器自身的删除方法
  2. 使用线程安全的CopyOnWriteArrayList解决

###简述Iterator 与 Iterable 的关系?
Colletion实现了Iterable接口,这个接口中提供了iterator方法,该方法返回Iterator接口类型,Iterator接口中提供了三个方法:分别是: hasNext,next,remove,这样在List及Set的实现类中就可以使用集合的迭代的相关方法。

###如何实现java序列化及反序列化?
序列化:将java对象转换为可保持或可传输的格式,即转换为二进制字节序列(字
节流)的形式的过程。
反序列化:将二进制字节序列(字节流)形式的java对象解析出来的过程。
序列化过程:
实现Serializable接口,使用默认的方式来进行序列化,这种序列化方式仅仅对对象的非transient的实例变量进行序列化,而不会序列化对象的transient的实例变量,也不会序列化静态变量,所以我们对不想持久化的变量可以加上transient关键字。注意使用默认机制,在序列化对象时,不仅会序列化当前对象本身,还会对该对象引用的其它对象也进行序列化,同样地,这些其它对象引用的另外对象也将被序列化,以此类推。所以,如果一个对象包含的成员变量是容器类对象,而这些容器所含有的元素也是容器类对象,那么这个序列化的过程就会较复杂,开销也较大。
序列化代码:

FileOutputStream os = new FileOutputStream("file.dat");  
ObjectOutputStream oos = new ObjectOutputStream(os);  
oos.writeObject(obj);  
反序列化代码:
FileInputStream fs = new FileInputStream("file.dat");  
	ObjectInputStream ois = new ObjectInputStream(fs);  
	Object obj = (Object) ois.readObject();

###简述线程有哪些状态?

1、通过new关键字创建后,进入到新生状态
2、调用start后进入就绪状态
3、CPU调度到本线程后,本线程开始执行。进入到运行状态
4、运行中遇到join,yield,sleep造成阻塞,进入阻塞状态。阻塞完成后,又回到就绪状态
5、线程正常执行完,或者遇到异常终止后,进入死亡状态

初始状态:
新建一个线程的对象。
实现Runnable接口和继承Thread可以得到一个线程类,new一个实例出来,线程就进入了初始状态
就绪状态:
当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。
运行状态:
可运行的线程获取了cpu的使用权,执行程序代码
阻塞状态:
所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。
① 线程通过调用sleep方法进入睡眠状态;
② 线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
③ 线程试图得到一个锁,而该锁正被其他线程持有;
④ 线程在等待某个触发条件;
死亡状态:
有两个原因会导致线程死亡:
① run方法正常退出而自然死亡;
② 一个未捕获的异常终止了run方法而使线程猝死;
③ 线程调用 stop()方法、destory()方法或 run()方法
为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法,如果是可运行或被阻塞,这个方法返回true;如果线程仍旧是new状态且不是可运行的,或者线程死亡了,则返回false。

###ThreadLocal与其它同步机制的比较?
Threadlocal和其他所有的同步机制都是为了解决多线程中的对同一变量的访问冲突,在普通的同步机制中,是通过对对象加锁来实现多个线程对同一变量的安全访问的。这时该变量是多个线程共享的,使用这种同步机制需要很细致的分析在什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放该对象的索等等。所有这些都是因为多个线程共享了该资源造成的。Threadlocal就从另一个角度来解决多线程的并发访问,Threadlocal会为每一个线程维护一个和该线程绑定的变量副本,从而隔离了多个线程的数据共享,每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
简述sleep,yeild,join方法的区别?
sleep()方法给其它线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)
状态;
3)sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;
4)sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。
sleep() wait() yield() join()用法与区别
1.sleep()方法
在指定时间内让当前正在执行的线程暂停执行,但不会释放“锁标志”。不推荐使用。
sleep()使当前线程进入阻塞状态,在指定时间内不会执行。

2.wait()方法
在其他线程调用对象的notify或notifyAll方法前,导致当前线程等待。线程会释放掉它所占有的“锁标志”,从而使别的线程有机会抢占该锁。
当前线程必须拥有当前对象锁。如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常。
唤醒当前对象锁的等待线程使用notify或notifyAll方法,也必须拥有相同的对象锁,否则也会抛出IllegalMonitorStateException异常。
waite()和notify()必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。

3.yield方法
暂停当前正在执行的线程对象。
yie

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值