您好,欢迎来到赋能网!

Java SE相关面试题汇总

赋能网 2023-06-11 147

1 你是怎样理解面向对象的

面向对象是利用编程语言对现实事物进行抽象。面向对象具有以下四大特征:

(1)继承:继承是从已有类得到继承信息创建新类的过程

(2)封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。

(3)多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。

(4)抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。

2 int和Integer有什么区别,以及以下程序结果

(1)Integer是int的包装类,int则是java的一种基本数据类型

(2)Integer变量必须实例化后才能使用,而int变量不需要

(3)Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值

(4)Integer的默认值是null,int的默认值是0

 package com.atguigu.interview.chapter03;

public class Test01 {

public static void main(String[] args) {

Integer a = 127;

Integer b = 127;

Integer c = 128;

Integer d = 128;

System.out.println(a == b); //true

System.out.println(c == d); //false

}

}

3 ==和Equals区别

(1) ==

如果比较的是基本数据类型,那么比较的是变量的值

如果比较的是引用数据类型,那么比较的是地址值(两个对象是否指向同一块内存)

(2)equals

如果没重写equals方法比较的是两个对象的地址值

如果重写了equals方法后我们往往比较的是对象中的属性的内容

equals()方法最初在Object类中定义的,默认的实现就是使用==

4 谈谈你对反射的理解

(1)反射机制:

所谓的反射机制就是java语言在运行时拥有一项直观的能力。通过这种能力可以彻底地了解自身的情况为下一步的动作做准备。

Java的反射机制的实现要借助于4个类:Class,Constructor,Field,Method;

其中Class代表的是类对 象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象。通过这四个对象我们可以粗略地看到一个类的各个组 成部分。

(2)Java反射的作用:

在Java运行时环境中,对于任意一个类,可以知道这个类有哪些属性和方法。对于任意一个对象,可以调用它的任意一个方法。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。

(3)Java 反射机制提供功能

在运行时判断任意一个对象所属的类。

在运行时构造任意一个类的对象。

在运行时判断任意一个类所具有的成员变量和方法。

在运行时调用任意一个对象的方法

5 ArrarList和linkedList区别

(1)ArrayList是实现了基于动态数组的数据结构,linkedList基于链表的数据结构。

(2)对于随机访问get和set,ArrayList绝对优于linkedList,因为linkedList要移动指针。

(3)对于插入和删除操作add和remove,linkedList比较占优势,因为ArrayList每插入或删除一条数据,都要移动插入点或删除点及之后的所有数据。

6 HashMap底层源码,数据结构

HashMap的底层结构在jdk1.7中由数组+链表实现,在jdk1.8中由数组+链表+红黑树实现,以数组+链表的结构为例。

JDK1.8之前put方法:

JDK1.8之后put方法:

Java SE相关面试题汇总

7 HashMap和Hashtable区别

(1)线程安全性不同

HashMap是线程不安全的,Hashtable是线程安全的,其中的方法是Synchronized的,在多线程并发的情况下,可以直接使用Hashtable,但是使用HashMap时必须自己增加同步处理。

(2)是否提供contains方法

HashMap只有containsValue和containsKey方法;Hashtable有contains、containsKey和containsValue三个方法,其中contains和containsValue方法功能相同。

(3)key和value是否允许null值

Hashtable中,key和value都不允许出现null值。HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。

(4)数组初始化和扩容机制

Hashtable在不指定容量的情况下的默认容量为11,而HashMap为16,Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。

Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。

3.8 TreeSet和HashSet区别

HashSet是采用hash表来实现的。其中的元素没有按顺序排列,add()、remove()以及contains()等方法都是复杂度为O(1)的方法。

TreeSet是采用树结构实现(红黑树算法)。元素是按顺序进行排列,但是add()、remove()以及contains()等方法都是复杂度为O(log (n))的方法。它还提供了一些方法来处理排序的set,如first(), last(), headSet(), tailSet()等等。

9 StringBuffer和StringBuilder区别

(1)StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,

(2)只是StringBuffer 中的方法大都采用了 synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是线程不安全的。

(3)在单线程程序下,StringBuilder效率更快,因为它不需要加锁,不具备多线程安全而StringBuffer则每次都需要判断锁,效率相对更低

10 Final、Finally、Finalize

final:修饰符(关键字)有三种用法:修饰类、变量和方法。修饰类时,意味着它不能再派生出新的子类,即不能被继承,因此它和abstract(abstract修饰的类通常都需要子类来继承)在使用上可以理解为互斥的。修饰变量时,该变量使用中不被改变,必须在声明时给定初值,在引用中只能读取不可修改,即为常量。修饰方法时,也同样只能使用,不能在子类中被重写。

finally:通常放在try…catch的后面构造最终执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中。

finalize:Object类中定义的方法,Java中允许使用finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize() 方法可以整理系统资源或者执行其他清理工作。

11 什么是 java 序列化,如何实现 java 序列化?

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。

序 列 化 的 实 现 : 将 需 要 被 序 列 化 的 类 实 现 Serializable 接 口 , 该 接 口 没 有 需 要 实 现 的 方 法 , implements Serializable 只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用 ObjectOutputStream 对象的 writeObject(Object obj)方法就可以将参数为 obj 的对象写出(即保存其状态),要恢复的话则用输入流。

12 Object中有哪些方法

(1)protected Object clone()—>创建并返回此对象的一个副本。
(2)boolean equals(Object obj)—>指示某个其他对象是否与此对象“相等”。
(3)protected void finalize()—>当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
(4)Class<? extends Object> getClass()—>返回一个对象的运行时类。
(5)int hashCode()—>返回该对象的哈希码值。
(6)void notify()—>唤醒在此对象监视器上等待的单个线程。
(7)void notifyAll()—>唤醒在此对象监视器上等待的所有线程。
(8)String toString()—>返回该对象的字符串表示。
(9)void wait()—>导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
void wait(long timeout)—>导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll()方法,或者超过指定的时间量。
void wait(long timeout, int nanos)—>导致当前的线程等待,直到其他线程调用此对象的 notify()

13 线程有几种状态,产生的条件是什么

14 产生死锁的基本条件

产生死锁的原因:

(1) 因为系统资源不足。
(2) 进程运行推进的顺序不合适。
(3) 资源分配不当等。
如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则
就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
死锁的解除与预防:

理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和
解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确
定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态
的情况下占用资源。因此,对资源的分配要给予合理的规划。

15 什么是线程池,如何使用?

线程池就是事先将多个线程对象放到一个容器中,当使用的时候就不用 new 线程而是直接去池中拿线程即可,节省了开辟子线程的时间,提高的代码执行效率。

在 JDK 的

java.util.concurrent.Executors 中提供了生成多种线程池的静态方法。

ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();

ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(4);

ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(4);

ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();

然后调用他们的 execute 方法即可。

优点:

第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

16 Java自带有哪几种线程池?

一、ThreadPoolExecutor

ThreadPoolExecutor提供了四个构造方法:

我们以最后一个构造方法(参数最多的那个),对其参数进行解释:

 public ThreadPoolExecutor(int corePoolSize, // 1

int maximumPoolSize, // 2

long keepAliveTime, // 3

TimeUnit unit, // 4

BlockingQueue < Runnable > workQueue, // 5

ThreadFactory threadFactory, // 6

RejectedExecutionHandler handler) { // 7

if (corePoolSize < 0 || maximumPoolSize <= 0 ||

maximumPoolSize < corePoolSize || keepAliveTime < 0)

throw new IllegalArgumentException();

if (workQueue == null || threadFactory == null || handler == null)

throw new NullPointerException();

this.corePoolSize = corePoolSize;

this.maximumPoolSize = maximumPoolSize;

this.workQueue = workQueue;

this.keepAliveTime = unit.tonanos(keepAliveTime);

this.threadFactory = threadFactory;

this.handler = handler;

}

Java SE相关面试题汇总

二、预定义线程池

JDK给我们预定义的几种线程池

1、FixedThreadPool

 public static ExecutorService newFixedThreadPool(int nThreads) {

return new ThreadPoolExecutor(nThreads, nThreads,

0L, TimeUnit.MILLISECONDS,

new linkedBlockingQueue<Runnable>());

}

  • corePoolSize与maximumPoolSize相等,即其线程全为核心线程,是一个固定大小的线程池,是其优势;
  • keepAliveTime = 0 该参数默认对核心线程无效,而FixedThreadPool全部为核心线程;
  • workQueue 为linkedBlockingQueue(无界阻塞队列),队列最大值为Integer.MAX_VALUE。如果任务提交速度持续大于任务处理速度,会造成队列大量阻塞。因为队列很大,很有可能在拒绝策略前,内存溢出。是其劣势;
  • FixedThreadPool的任务执行是无序的;

适用场景:可用于Web服务瞬时削峰,但需注意长时间持续高峰情况造成的队列阻塞。

2、CachedThreadPool

 public static ExecutorService newCachedThreadPool() {

return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

60L, TimeUnit.SECONDS,

new SynchronousQueue<Runnable>());

}

  • corePoolSize = 0,maximumPoolSize = Integer.MAX_VALUE,即线程数量几乎无限制;
  • keepAliveTime = 60s,线程空闲60s后自动结束。
  • workQueue 为 SynchronousQueue 同步队列,这个队列类似于一个接力棒,入队出队必须同时传递,因为CachedThreadPool线程创建无限制,不会有队列等待,所以使用SynchronousQueue;

适用场景:快速处理大量耗时较短的任务,如Netty的NIO接受请求时,可使用CachedThreadPool。

3、SingleThreadExecutor

 public static ExecutorService newSingleThreadExecutor() {

return new FinalizableDelegatedExecutorService(

new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,

new linkedBlockingQueue<Runnable>()));

}

这里多了一层

FinalizableDelegatedExecutorService包装,以下代码解释一下其作用:

 public static void main(String[] args) {

ExecutorService fixedExecutorService = Executors.newFixedThreadPool(1);

ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) fixedExecutorService;

System.out.println(threadPoolExecutor.getMaximumPoolSize());

threadPoolExecutor.setCorePoolSize(8);

ExecutorService singleExecutorService = Executors.newSingleThreadExecutor();

// 运行时异常 java.lang.ClassCastException

//ThreadPoolExecutor threadPoolExecutor2 = (ThreadPoolExecutor) singleExecutorService;

}

对比可以看出,FixedThreadPool可以向下转型为ThreadPoolExecutor,并对其线程池进行配置,而SingleThreadExecutor被包装后,无法成功向下转型。因此,SingleThreadExecutor被定以后,无法修改,做到了真正的Single。

4、ScheduledThreadPool

 public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {

return new ScheduledThreadPoolExecutor(corePoolSize);

}

newScheduledThreadPool调用的是ScheduledThreadPoolExecutor的构造方法,而ScheduledThreadPoolExecutor继承了ThreadPoolExecutor,构造是还是调用了其父类的构造方法。

public ScheduledThreadPoolExecutor(int corePoolSize) {

super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,

new DelayedWorkQueue());

}

三、自定义线程池

以下是自定义线程池,使用了有界队列,自定义ThreadFactory和拒绝策略的demo:

public class ThreadTest {

public static void main(String[] args) throws InterruptedException, IOException {

int corePoolSize = 2;

int maximumPoolSize = 4;

long keepAliveTime = 10;

TimeUnit unit = TimeUnit.SECONDS;

BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);

ThreadFactory threadFactory = new NameTreadFactory();

RejectedExecutionHandler handler = new MyIgnorePolicy();

ThreadPoolExecutor executor

= new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit,

workQueue, threadFactory, handler);

executor.prestartAllCoreThreads(); // 预启动所有核心线程

for (int i = 1; i <= 10; i++) {

MyTask task = new MyTask(String.valueOf(i));

executor.execute(task);

}

System.in.read(); //阻塞主线程

}

static class NameTreadFactory implements ThreadFactory {

private final AtomicInteger mThreadNum = new AtomicInteger(1);

@Override

public Thread newThread(Runnable r) {

Thread t = new Thread(r, "my-thread-" + mThreadNum.getAndIncrement());

System.out.println(t.getName() + " has been created");

return t;

}

}

public static class MyIgnorePolicy implements RejectedExecutionHandler {

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

doLog(r, e);

}

private void doLog(Runnable r, ThreadPoolExecutor e) {

// 可做日志记录等

System.err.println( r.toString() + " rejected");

// System.out.println("completedTaskCount: " + e.getCompletedTaskCount());

}

}

static class MyTask implements Runnable {

private String name;

public MyTask(String name) {

this.name = name;

}

@Override

public void run() {

try {

System.out.println(this.toString() + " is running!");

Thread.sleep(3000); //让任务执行慢点

} catch (InterruptedException e) {

e.printStackTrace();

}

}

public String getName() {

return name;

}

@Override

public String toString() {

return "MyTask [name=" + name + "]";

}

}

}

17 Java 中有几种类型的流

18 字节流如何转为字符流

字节输入流转字符输入流通过 InputStreamReader 实现,该类的构造函数可以传入 InputStream 对象。

字符输出流转字节输出流通过OutputStreamWriter 实现,该类的构造函数可以传入 OutputStream 对象。

3.19 请写出你最常见的5个Exception

(1)

java.lang.NullPointerException 空指针异常;出现原因:调用了未经初始化的对象或者是不存在的对象。

(2)

java.lang.ClassNotFoundException 指定的类找不到;出现原因:类的名称和路径加载错误;通常都是程序试图通过字符串来加载某个类时可能引发异常。

(3)

java.lang.NumberFormatException 字符串转换为数字异常;出现原因:字符型数据中包含非数字型字符。

(4)

java.lang.IndexOutOfBoundsException 数组角标越界异常,常见于操作数组对象时发生。

(5)

java.lang.IllegalArgumentException 方法传递参数错误。

(6)

java.lang.ClassCastException 数据类型转换

Java SE相关面试题汇总

标签:java面试题

本文链接:

本文章“Java SE相关面试题汇总”已帮助 147 人

免责声明:本信息由用户发布,本站不承担本信息引起的任何交易及知识产权侵权的法律责任!

本文由赋能网 整理发布。了解更多培训机构》培训课程》学习资讯》课程优惠》课程开班》学校地址等机构信息,可以留下您的联系方式,让课程老师跟你详细解答:
咨询热线:4008-569-579

如果本页不是您要找的课程,您也可以百度查找一下: