最新java面试题

最新整理的JAVA面试题


最近快要学完java面试,然后系统性的整理一下java的面试题。我主要分为,JavaSE,JavaEE,MySQL,Web,第三方库来总结的。

JavaSE常见的面试题

1:JDK和JRE和JVM和JIT有什么不同?

JDK:全称Java Developement Kit,Java开发工具包,提供了java的开发环境和运行环境。
JRE:全称Java Runtime Environment,Java运行环境,为Java的运行提供了所需要的环境
JVM:全称Java Virtual Machine,Java虚拟机,(主要就是就是JVM内存模型,在这道题不做过多的讲解)
JIT:全称是just in time,及时编译器,它通过有效的把字节码变成机器码来提高JVM的效率
JDK包含了JRE,对程序员来讲需要编写Java程序,则要安装JDK;对普通用户来讲,需要运行Java程序,只需要安装JRE就可以了。

2:JAVA的数据类型有哪些?

Java的数据类型分为,原生类型和引用类型
基础数据类型是:byte,8;short 16;int 32;long 64;float,32;double,64;boolean,1\8\16;char 无符号16
引用类型:String和数组

3:i++和++i的区别?

同:
1:i++和++i都是变量自增1,都等价于i=i+1
2:i++和++i的使只能针堆变量,5++和++5会报错,5不是变量。
不同:
1:i++是运算后+1;
2:++i是先增1在运算。

4:&和&&的区别。|和||的区别?

&和&&的相同点:
都可以用作逻辑与运算符
&和&&的不同点:
短路。
&逻辑运算符称为逻辑与运算符,&&逻辑运算符称为短路与运算符,也可叫逻辑与运算符。
对于&:无论任何情况,&两边的操作数或表达式都会参与计算。
对于&&:当&&左边的操作数为false或左边表达式结果为false时,&&右边的操作数或表达式将不参与计算,此时最终结果都为false。
&还可以用作位运算符。当&两边操作数或两边表达式的结果不是boolean类型时,&用于按位与运算符的操作。

|和||相同点:
都是逻辑或。
|和||不同点:
||表示短路或,当运算符左边的值为true时,右边的表达式不会进行运算。

5:面向对象和面向过程的区别?

两者都是软件开发思想,先有面向过程,后有面向对象。在大型项目中,针对面向过程的不足推出了面向对象开发思想。
区别
编程思路不同: 面向过程以实现功能的函数开发为主,而面向对象要首先抽象出类、属性及其方法,然后通过实例化类、执行方法来完成功能。
封装性:都具有封装性,但是面向过程是封装的是功能,而面向对象封装的是数据和功能。
面向对象具有继承性和多态性,而面向过程没有继承性和多态性,所以面向对象优势是明显。

6:方法重载和方法重写的区别?

同:都是实现多态的方式。
不同:
方法重载:在一个类里面,有多个名称相同的方法,但是参数列表不同,参数列表不同体现在参数类型,参数个数和参数顺序的不同上。
方法重写:父类方法无法满足子类的要求,子类通过方法重写满足要求。

7:this和super关键字的作用

1:this是对象内部指代自身的引用
2:this可以调用成员变量,通常用于解决成员变量和局部变量同名冲突
3:this可以调用成员方法
4:this可以在构造方法中调用重载的构造方法,且必须是构造方法的第一条语句。
super代表对当前对象的直接父类对象的引用
1:super可以调用直接父类的成员变量(注意权限修饰符的影响,比如不能访问private成员)
2:super可以调用直接父类的成员方法(注意权限修饰符的影响,比如不能访问private成员)
3:super可以调用直接父类的构造方法,只限构造方法中使用,且必须是第一条语句。

8:final和abstract关键字的作用

final和abstract是功能相反的两个关键字
1:abstract可以用来修饰类和方法,不能用来修饰属性和构造方法;使用abstract修饰的类是抽象类,需要被继承,使用abstract修饰的方法是抽象方法,需要子类被重写。
2:final可以用来修饰类、方法和属性,不能修饰构造方法。使用final修饰的类不能被继承,使用final修饰的方法不能被重写,使用final修饰的变量的值不能被修改,所以就成了常量。
3:特别注意:final修饰基本类型变量,其值不能改变。但是final修饰引用类型变量,栈内存中的引用不能改变,但是所指向的堆内存中的对象的属性值仍旧可以改变。

9:final、finally、finalize的区别?

1:final修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载。
2:finally在异常处理时提供 finally 块来执行任何清除操作。如果有finally的话,则不管是否发生异常,finally语句都会被执行。
3:finalize方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要清理工作。finalize() 方法是在垃圾收集器删除对象之前被调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。

10:==和equals的区别和联系?

==
a)基本类型,比较的是值
b) 引用类型,比较的是地址
c) 不能比较没有父子关系的两个对象
equals()
a) 系统类一般已经覆盖了equals(),比较的是内容。
b) 用户自定义类如果没有覆盖equals(),将调用父类的equals(比如是Object),而Object的equals的比较是地址(return (this == obj);)
c) 用户自定义类需要覆盖父类的equals()
注意:Object的==和equals比较的都是地址,作用相同

11:多态相关的知识点:

实现多态的三个条件
1:继承的存在;(继承是多态的基础,没有继承就没有多态)
2:子类重写父类的方法。(多态下会调用子类重写后的方法)
3:父类引用变量指向子类对象。(涉及子类到父类的类型转换)
向上转型 Student person = new Student()
1:将一个父类的引用指向一个子类对象,成为向上转型,自动进行类型转换。
2:此时通过父类引用变量调用的方法是子类覆盖或继承父类的方法,而不是父类的方法
3:此时通过父类引用变量无法调用子类特有的方法
向下转型 Student stu = (Student)person;
1:将一个指向子类对象的引用赋给一个子类的引用,成为向下转型,此时必须进行强制类型转换。
2:向下转型必须转换为父类引用指向的真实子类类型,,否则将出现ClassCastException,不是任意的强制转换
3:向下转型时可以结合使用instanceof运算符进行强制类型转换,比如出现转换异常。

12:接口和抽象类的异同之处

相同点
1:抽象类和接口均包含抽象方法,类必须实现所有的抽象方法,否则是抽象类
2:抽象类和接口都不能实例化,他们位于继承树的顶端,用来被其他类继承和实现
两者的区别:
实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
构造函数:抽象类可以有构造函数;接口不能有。
实现数量:类可以实现很多个接口;但只能继承一个抽象类(java只支持单继承)。
访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的抽象方法可以使用Public和Protected修饰,如果抽象方法修饰符为Private,则报错

13:Error和Exception的区别?

1:Error类,表示仅靠程序本身无法恢复的严重错误,比如说内存溢出、动态链接异常、虚拟机错误。应用程序不应该抛出这种类型的对象。假如出现这种错误,除了尽力使程序安全退出外,在其他方面是无能为力的。所以在进行程序设计时,应该更关注Exception类。
2:Exception类,由Java应用程序抛出和处理的非严重错误,比如所需文件没有找到、零作除数,数组下标越界等。它的各种不同子类分别对应不同类型异常。可分为两类:Checked异常和Runtime异常

14:Checked异常和Runtime异常的区别?

1:运行时异常:包括RuntimeaException及其所有子类。不要求程序必须对它们作出处理,比如InputMismatchException、ArithmeticException、NullPointerException等。即使没有使用try-catch或throws进行处理,仍旧可以进行编译和运行。如果运行时发生异常,会输出异常的堆栈信息并中止程序执行。
2:Checked异常(非运行时异常):除了运行时异常外的其他异常类都是Checked异常。程序必须捕获或者声明抛出这种异常,否则出现编译错误,无法通过编译。处理方式包括两种:通过try-catch捕获异常,通过throws声明抛出异常从而交给上一级调用方法处理。

15:异常处理中throws和throw的区别?

1:作用不同:throw用于程序员自行产生并抛出异常;throws用于声明在该方法内抛出了异常
2:使用的位置不同:throw位于方法体内部,可以作为单独语句使用;throws必须跟在方法参数列表的后面,不能单独使用。
3:内容不同:throw抛出一个异常对象,且只能是一个;throws后面跟异常类,而且可以有多个

16:String、StringBuffer、StringBuilder区别与联系?

1:String类是不可变类,即一旦一个String对象被创建后,包含在这个对象中的字符序列是不可改变的,直至这个对象销毁。
2:StringBuffer类则代表一个字符序列可变的字符串,可以通过append、insert、reverse、setChartAt、setLength等方法改变其内容。一旦生成了最终的字符串,调用toString方法将其转变为String
3:JDK1.5新增了一个StringBuilder类,与StringBuffer相似,构造方法和方法基本相同。不同是StringBuffer是线程安全的,而StringBuilder是线程不安全的,所以性能略高。通常情况下,创建一个内容可变的字符串,应该优先考虑使用StringBuilder

17:List、Set、Collection、Map的区别和联系?

Collection 接口存储一组不唯一,无序的对象
List 接口存储一组不唯一,有序(插入顺序)的对象
Set 接口存储一组唯一,无序的对象
Map接口存储一组键值对象,提供key到value的映射。Key无序,唯一。value不要求有序,允许重复。(如果只使用key存储,而不使用value,那就是Set)

18:ArrayList和LinkedList的区别和联系?

1:两者都实现了List接口,都具有List中元素有序、不唯一的特点。
2:ArrayList实现了长度可变的数组,在内存中分配连续空间。遍历元素和随机访问元素的效率比较高;
3:LinkedList采用链表存储方式。插入、删除元素时效率比较高。

19:Vector和ArrayList的区别和联系?

实现原理相同,功能相同,都是长度可变的数组结构,很多情况下可以互用
两者的主要区别如下
1:Vector是早期JDK接口,ArrayList是替代Vector的新接口
2:Vector线程安全,ArrayList重速度轻安全,线程非安全
3:长度需增长时,Vector默认增长一倍,ArrayList增长50%

20:Array 和 ArrayList 有何区别?

1:Array 可以存储基本数据类型和对象,ArrayList 只能存储对象。
2:Array 是指定固定大小的,而 ArrayList 大小是自动扩展的。
3:Array 内置方法没有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList 有。

21:HashMap和Hashtable的区别和联系?

实现原理相同,功能相同,底层都是哈希表结构,查询速度快,在很多情况下可以互用
两者的主要区别如下
1:HashMap的key-value支持key-value,null-null,key-null,null-value四种。而Hashtable只支持key-value一种(即key和value都不为null这种形式)。
2:继承的类不同:
Hashtable继承Dictionary类,HashMap实现Map接口
3:线程安全不同:
a)Hashtable线程安全,HashMap线程非安全。
b)HashMap的方法都没有使用synchronized关键字修饰,都是非线程安全的,而Hashtable的方法几乎都是被synchronized关键字修饰的
4:初始容量大小和扩充容量的大小不同:
a)Hashtable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。
b)HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。

22:HashMap 的实现原理?

HashMap 基于 Hash 算法实现的,我们通过 put(key,value)存储,get(key)来获取。当传入 key 时,HashMap 会根据 key. hashCode() 计算出 hash 值,根据 hash 值将 value 保存在 bucket 里。当计算出的 hash 值相同时,我们称之为 hash 冲突,HashMap 的做法是用链表和红黑树存储相同 hash 值的 value。当 hash 冲突的个数比较少时,使用链表否则使用红黑树。

23:HashSet 的实现原理?

HashSet 是基于 HashMap 实现的,HashSet 底层使用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值。

24:TreeSet的原理和使用

1:TreeSet中的元素不允许重复,但是有序
2:TreeSet采用树结构存储数据,存入元素时需要和树中元素进行对比,需要指定比较策略。可以通过Comparable和Comparator来指定比较策略。
3:实现了Comparable的系统类可以顺利存入TreeSet。自定义类可以实现Comparable接口来指定比较策略。
4:可创建Comparator接口实现类来指定比较策略,并通过TreeSet构造方法参数传入。这种方式尤其对系统类非常适用。

25:Collection和Collections的区别?

Collection 是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法,所有集合都是它的子类,比如 List、Set 等。
Collections 是一个包装类,包含了很多静态方法,不能被实例化,就像一个工具类,比如提供的排序方法:Collections. sort(list)。

26:进程和线程的关系和区别?

一个程序下至少有一个进程,一个进程下至少有一个线程,一个进程下也可以有多个线程来增加程序的执行速度。
进程和线程的关系:
(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。
(3)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
(4)处理机分给线程,即真正在处理机上运行的是线程。
(5)线程是指进程内的一个执行单元,也是进程内的可调度实体。

.线程与进程的区别:
(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位。
(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行。
(3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源。
(4)系统开销:在创建或撤销进程的时候,由于系统都要为之分配和回收资源,导致系统的明显大于创建或撤销线程时的开销。但进程有独立的地址空间,进程崩溃后,在保护模式下不会对其他的进程产生影响,而线程只是一个进程中的不同的执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但是在进程切换时,耗费的资源较大,效率要差些

27:Java创建线程后,调用start()方法和run()的区别

两种方法的区别
1) start:
用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里方法run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。
2) run:
run()方法只是类的一个普通方法而已,如果直接调用run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待
run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。
总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。
这两个方法应该都比较熟悉,把需要并行处理的代码放在run()方法中,start()方法启动线程将自动调用 run()方法,这是由jvm的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void。
两种方式的比较 :
实际中往往采用实现Runable接口,一方面因为java只支持单继承,继承了Thread类就无法再继续继承其它类,而且Runable接口只有一个run方法;另一方面通过结果可以看出实现Runable接口才是真正的多线程。
run() 可以重复调用,而 start() 只能调用一次。

28:多线程有几种实现方式?

有4种,分别是:
继承Thread类
实现Runnable接口
实现Callable接口通过FutureTask包装器来创建Thread线程
通过线程池创建线程,使用线程池接口ExecutorService结合Callable、Future实现有返回结果的多线程。
前面两种【无返回值】原因:通过重写run方法,run方法的返回值是void,所以没有办法返回结果。
后面两种【有返回值】原因:通过Callable接口,就要实现call方法,这个方法的返回值是Object,所以返回的结果可以放在Object对象中。

29:线程有哪些状态?

线程的6种状态:
初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
阻塞(BLOCKED):表示线程阻塞于锁。
等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
终止(TERMINATED):表示该线程已经执行完毕。

30:线程池都有哪些状态?

RUNNING:这是最正常的状态,接受新的任务,处理等待队列中的任务。
SHUTDOWN:不接受新的任务提交,但是会继续处理等待队列中的任务。
STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。
TIDYING:所有的任务都销毁了,workCount 为 0,线程池的状态在转换为 TIDYING 状态时,会执行钩子方法 terminated()。
TERMINATED:terminated()方法结束后,线程池的状态就会变成这个。

31:sleep() 和 wait() 有什么区别?

类的不同:sleep() 来自 Thread,wait() 来自 Object。
释放锁:sleep() 不释放锁;wait() 释放锁。
用法不同:sleep() 时间到会自动恢复;wait() 可以使用 notify()/notifyAll()直接唤醒。

32:notify()和 notifyAll()有什么区别?

notifyAll()会唤醒所有的线程,notify()之后唤醒一个线程。notifyAll() 调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而 notify()只会唤醒一个线程,具体唤醒哪一个线程由虚拟机控制。

33:synchronized 和 Lock 有什么区别?

synchronized 可以给类、方法、代码块加锁;而 lock 只能给代码块加锁。
synchronized 不需要手动获取锁和释放锁,使用简单,发生异常会自动释放锁,不会造成死锁;而 lock 需要自己加锁和释放锁,如果使用不当没有 unLock()去释放锁就会造成死锁。
通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到。(以上是简单回答,下面是详细的回答)
1)Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;
2)Lock和synchronized有一点非常大的不同,采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。
区别:
1.用法不一样。synchronized既可以加在方法上,也可以加载特定的代码块上,括号中表示需要锁的对象。而Lock需要显示地指定起始位置和终止位置。synchronzied是托管给jvm执行的,Lock锁定是通过代码实现的。
2.在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
3.锁的机制不一样。synchronized获得锁和释放的方式都是在块结构中,而且是自动释放锁。而Lock则需要开发人员手动去释放,并且必须在finally块中释放,否则会引起死锁问题的发生。
4.Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
5.synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
6.Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。Lock可以提高多个线程进行读操作的效率。

34:什么是死锁:

当线程 A 持有独占锁a,并尝试去获取独占锁 b 的同时,线程 B 持有独占锁 b,并尝试获取独占锁 a 的情况下,就会发生 AB 两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁。

35:怎么防止死锁?

尽量使用 tryLock里面的方法,设置超时时间,超时可以退出防止死锁。
尽量使用 Java. util. concurrent 并发类代替自己手写锁。
尽量降低锁的使用粒度,尽量不要几个功能用同一把锁。
尽量减少同步的代码块。

36:什么是反射?

反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。

37:什么是 Java 序列化?什么情况下需要序列化?

Java 序列化是为了保存各种对象在内存中的状态,并且可以把保存的对象状态再读出来。
以下情况需要使用 Java 序列化:
想把的内存中的对象状态保存到一个文件中或者数据库中时候;
想用套接字在网络上传送对象的时候;
想通过RMI(远程方法调用)传输对象的时候。

38:设计模式

设计模式是一套被反复使用的、多数人知晓、经过分类编目的优秀代码设计经验的总结。特定环境下特定问题的处理方法。
1:重用设计和代码 重用设计比重用代码更有意义,自动带来代码重用
2:提高扩展性 大量使用面向接口编程,预留扩展插槽,新的功能或特性很容易加入到系统中来
3:提高灵活性 通过组合提高灵活性,可允许代码修改平稳发生,对一处修改不会波及到其他模块
4:提高开发效率 正确使用设计模式,可以节省大量的时间

39:面向对象设计原则有哪些?

面向对象设计原则是面向对象设计的基石,面向对象设计质量的依据和保障,设计模式是面向对象设计原则的经典应用
1:单一职责原则SRP
2:开闭原则OCP
3:里氏替代原则LSP
4:依赖注入原则DIP
5:接口分离原则ISP
6:迪米特原则LOD
7:组合/聚合复用原则CARP
开闭原则具有理想主义的色彩,它是面向对象设计的终极目标。其他设计原则都可以看作是开闭原则的实现手段或方法

JavaSE的面试题就先总结到这里,如果后面还有在加吧。就先看看,有哪里没说正确的,欢迎留言。
然后,我目前只写了JavaSE的,还有的等更新!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值