面试专题(Java基础)

面向对象

1.面向对象和面向过程的区别java

面向过程关注于一个功能实现的步骤,按步骤编程实现功能。编程

面向对象关注于一个功能实现的行为,将一些行为封装为一个对象来统一调用。数组

 

面向过程是一种事件为中心的编程思想。就是分析出解决问题所需的步骤,而后用函数把这些步骤实现,并按顺序调用。面向过程是以对象为中心的编程思想。缓存

 

2.四个基本特性安全

抽象:Java中抽象的概念最直接的应用就是抽象类和接口,从复杂的业务逻辑中,提炼出它的本质。多线程

封装:封装将数据以及加在这些数据上的操做组织在一块儿,提供给可信的其余类或对象操做。并发

继承:继承就是从通常到特殊的过程。经过继承能够拥有现有类的全部功能,并在无需重修编写原来类的状况下对这些功能进行扩展。异步

多态:多态性是指容许不一样类的对象对同一消息做出响应。即同一消息能够根据发送对象的不一样而采用多种不一样的行为方式。(发送消息就是函数调用)。实现多态的两种方式:重写、重载。ide

 

封装考虑内部实现,抽象考虑的是外部行为。封装能够隐藏实现细节,使得代码模块化;继承能够扩展已存在的代码模块;他们都是为了解决代码重用。而多态是为了实现接口重用,为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确使用。模块化

 

3.抽象类和接口的区别

相同点:

都是上层的抽象;

都不能被实例化;

都能包含抽象方法。

不一样点:

在抽象类中能够写非抽象的方法,从而避免在子类中重复书写他们,提升代码的复用性;接口中只能有抽象方法(JDK1.8新特性:默认方法(子类不必定要实现)、JDK1.9新特性:私有方法(加强默认方法));

一个类只能继承一个直接父类(普通类或抽象类),可是能够实现多个接口。

 

4.访问控制符

private:同类可见

default:同包可见

protected:同包可见,子类可见

public:全局可见

 

5.重载和重写

重载是指一个类中容许存在多个同名函数,而这些函数的参数不一样;重写是指子类从新定义父类的方法。

 

6.构造器Constructor是否可被override

构造器不容许被重写。

构造器不是方法,全部用于修饰方法特性的修饰符,都不能用来修饰构造器。

构造器是实例化对象过程当中用来初始化这个对象用的。

 

语言特性

1.自动装箱与拆箱

以问题引入:

JDK实际编译的代码:

将Integer a = 120; 编译为:Integer a = Integer.valueOf(120); 就是JDK的自动装箱操做。

将int e = a; 编译为:int e = a.intValue(); 就是JDK的自动拆箱操做。

自动装箱也就是将基本数据类型封装到对象中的操做,自动拆箱也就是将对象中的基本数据从对象中自动取出。

 

2.String和StringBuffer、StringBuilder的区别

性能差异:StringBuilder > StringBuffer > String;

String对字符串的操做(修改、拼接)实际上是在建立新的对象,效率低下;

StringBuffer线程安全、StringBuilder线程不安全

 

3,hashCode和equals方法的关系

hashcode()方法是JDK根据对象的地址或者字符串的值计算出来的int类型的数值(哈希码值)。

同一对象屡次调用hashcode()方法,必须返回相同的数值。

若是两个对象根据equals()方法比较是相等的,那么两个对象调用hashcode()方法返回的结果必须相等。

若是两个对象根据equals()方法比较是不相等的,那么两个对象调用hashcode()方法返回的结果不必定不相等。

 

4.Java中的集合类

Collection下全部子类集合都用于存储Value,Map下全部子类集合都用于存储Key-Value。

ArrayList是线程不安全的,Vector是线程安全的(两者底层都是数组类型结构),LinkedList线程不安全(底层链表类型结构);

ArrayList每次扩容50%,而Vector每次扩容翻倍;

Set集合存储无序的不可重复元素,容许一个null元素。HashSet对象必须定义hashcode()方法,LinkedHashSet具有HashSet的性能,但内部使用链表维护元素的顺序(插入顺序)。TreeSet底层使用树结构维护有序的元素。

HashMap是线程不安全的,能够存储null值null键和;HashTable是线程安全的,不容许存储null值null键;HashTable由于是线程安全的,因此性能低于HashMap

 

5.什么是泛型为何要使用泛型擦除

泛型的本质是参数化类型,也就是说所操做的数据类型被指定为一个参数。

泛型(JDK1.5特性)以前,当方法的参数类型设置为基类,那么能够往方法中传入该基类下任意类型的对象,这样方法就更具备通用性。另外,将方法参数设置为接口,更加方便(可实现多个接口)。

这样存在的问题是,当须要获取一个值的时候,必须强制类型转换。而强制装换类型的时候,容易使用错误的类型转换致使报错。

泛型擦除是指:在Java中使用泛型建立对象时,在编译期间,全部的泛型信息都会被擦除,编译后会变成原始类型。

 

6.Java中的异常

IndexOutOfBoundsEecption:元素越界异常;

ArrayIndexOutOfBoundsEecption:多个元素越界异常;

ClassCastException:类型转换异常;

NullPointerException:空指针异常,null对象的应用;

RuntimeException:运行时异常;

IOException:IO操做异常;

ConnectException:链接失败异常;

 

7.Java中的BIO,NIO,AIO

BIO(同步阻塞IO):一个链接对应一个线程

当有客户端链接请求时,服务端须要启动一个线程进行处理,若是这个链接不作任何处理,会形成没必要要的线程开销,能够经过线程池机制改善,从而实现伪异步IO;

NIO(同步非阻塞IO):N个链接对应一个线程

客户端全部的链接请求都会注册到多路复用器上,服务端经过一个多路复用器来处理全部请求。

AIO(异步非阻塞IO):NIO的2.0版本,引入了异步通道的概念,能够实现异步调用。

异步实现方式:经过java.util.concurrent.Future类来表示异步操做的结果;

在执行异步操做的时候传入java.nio.channels。

 

8.序列化与反序列化

序列化是指将对象的状态信息转换为能够存储或传输的形式的过程,经过序列化能够将对象的状态保存为字节数组,须要的时候再将字节数组反序列化为对象。

 

9.IO和NIO区别

NIO是Java1.4的新特性,提供了与标准IO不一样的工做方式:

标准IO基于字节流和字符流进行操做,而NIO是基于通道(Channel)缓冲区(Buffer)进行操做,数据从通道读取到缓冲区中,或者从缓冲区写入到通道。

NIO引入了选择器(Selectors)概念,选择器用于监听多个通道的事件(好比:链接打开、可读、可写),所以NIO能够经过一个线程监听多个数据通道。相比标准IO为每个链接建立一个线程,NIO大大下降了线程建立的资源开销。

 

多线程

1.多线程的实现方式

一般使用继承Thread类或实现Runnable接口

还能够经过Callable接口实现。

 

2.线程的状态转换

new 新建线程

Runnable 可运行状态(执行start()方法,CPU决定是否运行)

Blocking 阻塞状态(线程被阻塞于锁)

Waiting 等待、计时等待(等待某些条件成熟)

Stop 终止状态(线程运行结束)

 

3.sleep和wait的区别

  1. sleep()是线程Thread的方法,而wait()是Object对象的方法。
  2. sleep()不会释放对象锁、wait()会释放对象锁
  3. sleep()能够在任何地方调用,wait()方法之能够在同步方法或同步块中使用。

yield() 当前线程出让cpu占有权,当前线程变成可运行状态。

wait()\notify()\notifyAll()

调用之前,当前线程必需要持有锁,调用它们线程会释放锁,等待通知机制。

notify() 唤醒一个线程(谨慎使用),具体唤醒哪一个线程,由CPU决定。

notifyAll() 全部在对象O上wait的线程所有唤醒(应用较多)

 

4.如何中止一个线程

  1. run方法代码执行完成
  2. 线程运行时抛出一个未捕获的异常,跳出线程
  3. 经过标志位跳出线程
  4. interrupt() 向须要中断的线程发送中止指令;isInterrupted() 线程检查本身的中断标志位;Thread.interrupted() 将中断标志位复位为false;

不安全方式

Stop() 马上中止线程,但不会释放线程运行所应用的资源

Suspend() 马上挂起线程,但不会释放线程运行锁应用的资源,容易形成死锁

 

5.volatile关键字

在多个线程之间,访问同一个被volatile修饰的对象时,全部线程共享这个对象的值。

可是volatile不是线程安全的(多个线程同时修改这个变量时,最终结果不必定是最后修改的那个值;能够保证线程的可见性,不能够保证操做的原子性)

 

6.synchronized如何使用

加锁

能够修饰方法或代码块以同步的方式执行(同一时间只会有一个线程执行)

类锁实例锁本质上是两把锁,类锁锁的是每个类的class对象。

 

7.synchronized和Lock的区别

synchronized是一个Java的关键字,Lock是一个接口;

synchronized代码块执行完或线程抛出异常时结束线程,Lock必须显示调用释放锁的方法:unlock();

synchronized修饰的锁其余线程在等待获取锁的阶段,会一直阻塞等待直到获得锁为止(不可中断锁);Lock有多种方式能够获取锁,不必定一直阻塞等待(可中断锁)。

synchronized没法判断锁的状态,Lock能够判断;

synchronized是非公平锁,而Lock能够设置为公平锁;

Lock用法:

lock()(阻塞线程等待获取锁)

lockInterruptibly():可中断(阻塞线程等待获取锁,会响应中断)

tryLock():尝试非阻塞的获取锁(非阻塞方式尝试获取锁,没法获取则返回false)

unlock()

公平锁与非公平锁:

公平锁,先对锁发出获取请求的必定先得到锁。非公平锁则反之(性能更高)。

ReentrantLock(boolean)可选择公平锁或非公平锁,默认使用非公平锁。

锁的可重入:

递归的时候发生锁的重入

synchronized隐式支持锁的重入

ReentrantLock的lock()支持锁的重入

排它锁:同一时刻只有一个线程获取锁;

读写锁:同一时刻运行多个读线程访问,可是只容许一个写线程,写锁会阻塞全部锁。(ReentrantReadWriteLock,相比synchronized速度更快)

 

Condition接口有何做用?

Condition接口与Lock配合,来实现等待通知机制。

 

8.什么是线程安全

当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的。

 

9.死锁

当一个锁未被释放,其余线程没法获取锁的时候,程序产生死锁状况。

死锁的两种状况:

  1. 线程thread1先获取锁locka,而后在同步块里嵌套竞争锁lockb。而线程thread2先获取锁lockb,而后在同步块里嵌套竞争锁locka。
  2. Lock.unlock()方法的错误使用,致使死锁。

 

10.Java线程池

什么是线程池?用于管理线程的一个工具。

线程池的做用?限制系统中执行线程的数量;下降资源的消耗、提升响应速度、提升线程的可管理性。

 

Java常见的线程池

Executors.newSingleThreadExecutor:单个线程的线程池;

Executors.newFixedThreadExecutor:固定线程数量的线程池;

Executors.newCacheThreadExecutor:可缓存线程;

Executors.newScheduledThreadPool:建立一个定长线程池,支持定时和周期性的执行线程;

 

11.并发工具类和并发容器类

经常使用的并发工具类

闭锁:CountDownLatch

栅栏:CyclicBarrier

信号量:Semaphore

交换者:Exchanger

 

CountDownLatch 闭锁容许一个线程或多个线程等待特定状况,同步完成线程中其余任务。

 

CyclicBarrierCountDownLatch均可以协同多个线程,让指定数量的线程等待期他全部的线程都知足某些条件以后才继续执行。CyclicBarrier能够重复使用(reset),而CountDownLatch只可以使用一次,若是还须要使用,必须重现new一个CountDownLatch对象。

构造方法CyclicBarrier(int, Runnable) 全部线程达到屏障后,执行Runnable。

 

Semaphore 型号量用来控制同时访问特定资源的线程数量。

 

Exchanger 交换者用于在两个线程之间传输数据,被调用后等待另外一个线程达到交换点,而后相互交互数据。

 

经常使用的并发容器

ConcurrentHashMap:JDK1.7实现:分段锁;JDK1.8实现:元素(key)锁+链表+红黑树

 

SkipList:跳表自动随机维护一套索引,用于高效的索引List中的有序数据。

ConcurrentSkipListMap:TreeMap的并发实现

ConcurrentSkipListSet:TreeSet的并发实现

ConcurrentLinkedQueue:LinkedList的并发实现

CopyOnWriteArrayList:写时复制,在添加元素是,复制一个新的容器,在新容器中新增元素;读数据都在Old容器中操做,进行读写分离。数据一致性较弱,适合读多写少的场景。

CopyOnWriteArraySet:同上

相关文章
相关标签/搜索