Java基础

17 阅读6分钟

Java基础

面向对象

面向对象的特征

封装、继承、多态

多态的实现

运行时多态和编译时多态

接口、继承重写、方法重载

运行时多态:动态绑定技术,执行期间判断所引用对象的实际类型。

抽象类和接口

都不能够实例化

  1. 抽象类可以有构造方法,接口中不能有构造方法。

  2. 抽象类中可以有普通成员变量,接口中没有普通成员变量

  3. 抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。

  4. 抽象类中的抽象方法的访问类型可以是public,protected,但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。

  5. 抽象类中可以包含静态方法,接口中不能包含静态方法

  6. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。

  7. 一个类可以实现多个接口,但只能继承一个抽象类。

基础

Java中基本数据类型

有八个,byte、char、short、int、long、float、double、boolean

除了基本类型还有枚举类型

抽象方法是否可以是静态的?是否可以是本地方法?是否可以被synchronize修饰

都不能

如何实现对象克隆

  1. 实现Cloneable接口并重写clone()

  2. 实现Serializable接口,通过序列化和反序列化实现克隆,实现的是深拷贝克隆

String s = new String("test")创建了几个字符串对象

至少两个,一个是静态区域的,另一个是new创建在堆上的对象

final关键字修饰的作用

类不能被继承

方法不能被重写

变量不能被更改

常见的异常

ArithmeticException

ClassCastException

IllegalArgumentException

IndexOutOfBoundException

NullPointException

FileNotFoundException

内部类的作用

提供了更好的封装,除了外围类,其他类都不能访问

内部类可以有多个实例

集合

ArrayList、Vector的区别

都是基于数组实现,ArrayList是非同步,Vector是同步的

ArrayList、Vector、LinkedList的实现方式

ArrayList、Vector都是基于数组实现,LinkedList基于双向链表

HashMap和HashTable的区别

HashMap允许键和值为null,而HashTable不允许

HashTable是同步的,而HashMap不是

HashMap和ConcurrentHashMap的区别

  1. ConcurrentHashMap对整个桶数组进行了分段,而HashMap没有

  2. ConcurrentHashMap在每一个分段上都用锁进行保护,而HashMap没有锁机制

ConcurrentHashMap的实现原理

采用了分段锁,就是把Map分成了N个Segment,put和get的时候,都是根据key.hashCode()算出放到哪个Sagement中

线程

线程实现的方式

  1. 继承Thread类

  2. 实现Runnable接口

  3. 实现Callable接口通过FutureTask包装器来创建Thread线程

  4. 使用线程池接口ExecutorService结合Callable、Future实现有返回结果的线程

ThreadLocal是什么?和Thread有什么关系?

ThreadLocal用于存储Thread的局部变量,从而达到各个Thread之间的隔离运行。但是使用不好会导致内存泄漏问题。

手动释放ThreadLocal遗留存储?你怎么去设计/实现?

这里主要是强化一下手动remove的思想和必要性,设计思想与连接池类似。

包装其父类remove方法为静态方法,如果是spring项目, 可以借助于bean的声明周期, 在拦截器的afterCompletion阶段进行调用。

弱引用导致内存泄漏,那为什么key不设置为强引用

如果key设置为强引用, 当threadLocal实例释放后, threadLocal=null, 但是threadLocal会有强引用指向threadLocalMap,threadLocalMap.Entry又强引用threadLocal, 这样会导致threadLocal不能正常被GC回收。

弱引用虽然会引起内存泄漏, 但是也有set、get、remove方法操作对null key进行擦除的补救措施, 方案上略胜一筹。

线程执行结束后会不会自动清空Entry的value

事实上,当currentThread执行结束后, threadLocalMap变得不可达从而被回收,Entry等也就都被回收了,但这个环境就要求不对Thread进行复用,但是我们项目中经常会复用线程来提高性能, 所以currentThread一般不会处于终止状态。

常见的线程池

Executors.newCachedThreadPool :创建可缓存的线程池

特点:核心线程数0,工作队列SynchronizedQueue是一个不存储元素的队列,可以理解为里面永远是满的,最终会创建非核心线程来执行任务.非核心线程空闲回收时间为60s因为Integer.MAX_VALUE非常大,可以认为可以无限制的创建,所以在资源有限的情况下,容易造成OOM

Executors:newSingleThreadExecutor:创建一个单线程的线程池

特点:只有一个核心线程,超过核心线程数,会放入队列中,LinkedBlockingQueue是长度为Integer.MAX_VALUE,所以可以认为无界,那往队列里面插入任务,容易造成OOM.因为无界,所以,最大线程数和空闲时间这两个参数是无效的.

Executor.newFixedThreadPool:创建固定长度的线程池

特点:固定的核心线程池由用户传入.这个和SingleThreadExecutor相似,只是核心线程数不同,所以,在大量线程时容易造成OOM

为什么不推荐Executors直接创建线程池,而用ThreadPoolExecutor

  1. 缓存队列 LinkedBlockingQueue 没有设置固定容量大小

  2. 最大线程数量是 Integer.MAX_VALUE

  3. 不支持自定义拒绝策略

  4. 创建线程 或 线程池时请指定有意义的线程名称,方便出错时回溯(这个不是重点)

sleep()、join()、yeild()有什么区别

sleep()不考虑其他线程运行机会的优先级,yeild()会给同级别或者更高

执行sleep后会进入阻塞状态,执行yeild后会进入就绪状态

sleep有InterruptedException异常,yeild没有任何异常

join() 方法会使当前线程等待调用 join() 方法的线程结束后才能继续执行

sleep()和wait()有什么区别

sleep()是让出cpu,而wait()是放弃当前持有的锁

wait()与notify()/notifyAll()在放弃对象监视器上有什么区别

wait()方法是立即释放锁,notify()/notifyAll()是等待线程执行完成后释放锁

线程有哪几种锁

  1. 自旋锁

  2. 偏向锁:偏向于第一个获取他的线程,如果该锁没有被其他线程获取,那么持有偏向锁的线程不需要再进行同步。

  3. 轻量级锁