【Java基础知识面试题 1】2020年6月19日 星期五

2020年6月18日  星期四

1、单例模式

(1)单例模式定义

小白:

单例模式是保证一个类只有一个实例,保证线程安全。

答案:

单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡 的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个 Printer Spooler,以避免 两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。 总之,选择单例模式就是为了避免不一致状态。

(2)单例模式特点

小白:

保证一个类只有一个实例,保证线程安全。

答案:

  1. 单例类只能有一个实例。
  2. 单例类必须自己创建自己的唯一实例。
  3. 单例类必须给所有其他对象提供这一实例。
  4. 单例模式保证了全局对象的唯一性,比如系统启动读取配置文件就需要单例保证配置的一致性。

(3)单例模式的四大原则

小白:唯一性,静态单例。

答案:

  1. 构造私有;
  2. 以静态方法或者枚举返回实例 ;
  3. 确保实例只有一个,尤其是多线程环境 ;
  4. 确保反序列换时不会重新构建对象。

(4)实现单例模式的方式

小白:

饿汉式、懒汉式、静态内部类、双重检索、枚举。

答案:

(1)饿汉式(立即加载);

(2)懒汉式(延迟加载);

(3)同步锁(解决线程安全问题):

(4)双重检查锁(提高同步锁的效率);

(5) 静态内部类;

(6)内部枚举类实现(防止反射攻击);

2、你是怎样理解面向对象的

小白:

面向对象三大特点

封装、继承、多态、

答案:

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

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

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

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

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

3、int和Integer有什么区别

(1)int是基本数据类型,Integer是int的封装类型;

(2)int可以没有初始值,Integer必须设置初始值;

(3)int默认为0,Integer默认为null;

4、==和equals的区别

==

(1)在基本类型比较时,比较的是数值;

(2)在封装类型比较时,比较的是地址值;

equals

(1)没重写equals方法时,比较的是地址值,因为equals在object类中的实现就是==;

(2)重写equals方法后,比较的是对象中的属性值;

5、谈谈你对反射的理解

(1)反射机制

小白:

反射机制是通过getClass方法获取java类自身的一些属性,比如类名、变量、方法等。

答案:

所谓的反射机制就是 java 语言在运行时拥有一项自观的能力。通过这种能力可以彻底的了解自身的情况为下一步的动作做准备。 Java 的反射机制的实现要借助于 4 个类:class,Constructor,Field,Method; 其中 class 代表的时类对 象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象。通过这四个对象我们可以粗略的看到一个 类的各个组 成部分。

(2)Java反射的作用

小白:

获取这个类的属性,比如类名、变量、方法、参数等。

答案:

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

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

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法;
  • 在运行时调用任意一个对象的方法;

6、ArrayList和LinkedList区别

小白:

(1)ArrayList的底层实现是数组,linkedlist的底层实现是链表;

(2)ArrayList的插入和更新更快,LinkedList的添加和删除更快,因为这也是数组和链表的区别;

答案:

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

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

(3)对于新增和删除操作 add 和 remove,LinkedList 比较占优势,因为 ArrayList 要移动数据。 这一点要看实际情况的。若只对单条数据插入或删除, ArrayList 的速度反而优于 LinkedList。但若是批量随机的插入删除数据,LinkedList 的速度大大优于 ArrayList. 因为 ArrayList 每插入一条数据,要移动 插入点及之后的所有数据。

7、HashMap底层源码

1.7之前是数组+链表的形式;

1.8开始是数组+链表+红黑树的形式;

8、HashMap和HashTable的区别

小白:

(1)HashMap线程不安全,HashTable线程安全,HashTable内部包含synchronized,HashMap要想线程安全,可以使用一些同步方法。

(2)HashMap的key和value允许为null,HashTable的key和value都不可以为null;

答案:

(1)线程安全性不同 HashMap 是线程不安全的,HashTable 是线程安全的,其中的方法是 Synchronize 的,在多线程并发的情况下,可以直接使用 HashTabl,但是使用 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 倍。

9、TreeSet和HashSet的区别

小白:

set是没有重复的元素;

TreeSet是有序的set;

HashSet是无序的Set;

答案:

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

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

10、StringBuffer和StringBuilder的区别

小白:

stringbuffer是线程安全的,stringbuilder是线程不安全的,stringbuilder速度比stringbuffer要快,因为没有同步方法;

答案:

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

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

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

11、Final、Finally、Finalize区别

(1)final可以修饰类、变量、方法

修饰类时,这个类不能被继承。

修饰变量时,这个变量必须赋值,在引用中只能读取不可修改,即为常量;

修饰方法时,这个方法不能被子类重写;

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

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

12、什么是Java序列化,如何实现Java序列化

小白:Java序列化是通过IO流的形式将对象存储在内存中,再通过反序列化将内存中的对象转为java对象,有助于对象的传输,实现serializable接口即可实现序列化,transient或static修饰的变量不会被序列化和反序列化。

答案:

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

序列化的实现:

  • 实现serializable接口,该接口没有需要实现的方法;然后使用一个输出流(FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,然后使用writeObject(Obejct obj)方法就可以将obj写出(即保存其状态),要恢复的话则用输入流。

13、Object中有哪些方法

  • getcode()
  • getClass()
  • toString()
  • equals()
  • finalize()
  • wait()
  • notify()
  • notifyAll()
  • clone()

14、线程由几种状态,产生的条件是什么

小白:

(1)创建状态:Thread thread = new Thread();

(2)就绪状态:调用start()后;

(3)执行状态:

(4)阻塞状态:

造成阻塞状态的三种原因:

  • 等待阻塞
  • 线程阻塞
  • sleep造成的阻塞

(5)死亡状态

答案:

(1)创建状态:Thread thread = new Thread();

(2)就绪状态:调用start()后;

(3)执行状态:只能从就绪状态进入执行状态;

(4)阻塞状态:阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行,直到线程进入就绪状态,才会有机会转到运行状态。

造成阻塞状态的三种原因:

  • 等待阻塞:通过调用线程的wait()方法,让线程等待某工作的完成。
  • 线程阻塞:线程获取synchronized同步锁失败(因为锁被其它线程锁占用),它会进入同步阻塞状态;
  • 其它阻塞:通过调用线程的sleep()或join()或发出了IO请求时,线程就会进入阻塞状态。当sleep()超时、join()等待线程终止或超时、或者IO处理完毕时,线程重新转入就绪状态。

(5)死亡状态:线程执行完了或者因异常退出了 run()方法,该线程结束生命周期。

15、产生死锁的基本条件

(1)产生死锁的原因

小白:不会

答案:

  • 因为系统资源不足;
  • 进程运行推进的顺序不合适;
  • 资源分配不当;

如果系统资源充足,进程的资源请求都能得到满足,死锁出现的可能性就会很低,否者就会因为争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。

(2)产生死锁的四个必要条件

小白:

  • 互斥条件
  • 请求和保持条件
  • 不剥夺条件
  • 环路等待条件

答案:

① 互斥条件:指进程对所分配到的资源进行排它性使用,在一段时间内某资源只由一个进程占用,如果此时还有其他进程请求资源,则请求者只能等待,直至占有资源的进程被释放。

② 请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。

③ 不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

④环路等待条件:在发生死锁时,必然存在一个进程,资源的唤醒链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。

(3)死锁的解除和预防

小白:

强制解锁;

答案:

如何不让四个条件成立,如何确定资源的合理分配,避免进程永久占据系统资源;

也要防止进程在处于等待状态的情况下占用资源。

猜你喜欢

转载自blog.csdn.net/guorui_java/article/details/106832849