Java面试知识点总结(下)

来源:互联网 发布:linux 本地 编辑:程序博客网 时间:2024/06/07 19:45

8. Map, Set, List, Queue、Stack的特点及用法。

  • Map<K, V>: Java中存储键值对的数据类型都实现了这个接口,表示“映射表”。支持的两个核心操作是get(Object key)以及put(K key, V value),分别用来获取键对应的值以及向映射表中插入键值对。

  • Set<E>: 实现了这个接口的集合类型中不允许存在重复的元素,代表数学意义上的“集合”。它所支持的核心操作有add(E e),remove(Object o)contains(Object o),分别用于添加元素,删除元素以及判断给定元素是否存在于集中。

  • List<E>: Java中集合框架中的列表类型都实现了这个接口,表示一种有序序列。支持get(int index)add(E e)等操作。

  • Queue<E>: Java集合框架中的队列接口,代表了“先进先出”队列。支持add(E element)remove()等操作。

  • Stack<E>: Java集合框架中表示堆栈的数据类型,堆栈是一种“后进先出”的数据结构。支持push(E item)pop()等操作。

更详细的说明请参考官方文档,对相关数据结构不太熟悉的同学可以参考《算法导论》或其他相关书籍。

9. HashMap和HashTable的区别

  • HashTable是线程安全的,而HashMap不是

  • HashMap中允许存在null键和null值,而HashTable中不允许

10. HashMap的实现原理
简单的说,HashMap的底层实现是“基于拉链法的散列表”。

11. ConcurrentHashMap的实现原理
ConcurrentHashMap是支持并发读写的HashMap,它的特点是读取数据时无需加锁,写数据时可以保证加锁粒度尽可能的小。由于其内部采用“分段存储”,只需对要进行写操作的数据所在的“段”进行加锁。

12. TreeMap, LinkedHashMap, HashMap的区别是什么?

  • HashMap的底层实现是散列表,因此它内部存储的元素是无序的;

  • TreeMap的底层实现是红黑树,所以它内部的元素的有序的。排序的依据是自然序或者是创建TreeMap时所提供的比较器(Comparator)对象。

  • LinkedHashMap可以看作能够记住插入元素的顺序的HashMap。

13. Collection与Collections的区别是什么?

  • Collection<E>是Java集合框架中的基本接口;
  • Collections是Java集合框架提供的一个工具类,其中包含了大量用于操作或返回集合的静态方法。

14. 对于“try-catch-finally”,若try语句块中包含“return”语句,finally语句块会执行吗?
会执行。只有两种情况finally块中的语句不会被执行:**

  • 调用了System.exit()方法;

  • JVM“崩溃”了。

15. Java中的异常层次结构
Java中的异常层次结构如下图所示:

<code class="php">我们可以看到Throwable类是异常层级中的基类。Error类表示内部错误,这类错误使我们无法控制的;<span class="hljs-keyword" style="color: rgb(0, 0, 136);">Exception</span>表示异常,RuntimeException及其子类属于未检查异常,这类异常包括ArrayIndexOutOfBoundsException、NullPointerException等,我们应该通过条件判断等方式语句避免未检查异常的发生。IOException及其子类属于已检查异常,编译器会检查我们是否为所有可能抛出的已检查异常提供了异常处理器,若没有则会报错。对于未检查异常,我们无需捕获(当然Java也允许我们捕获,但我们应该做的事避免未检查异常的发生)。</code>

16. Java面向对象的三个特征与含义
三大特征:封装、继承、多态。

17. Override, Overload的含义与区别

  • Override表示“重写”,是子类对父类中同一方法的重新定义

  • Overload表示“重载”,也就是定义一个与已定义方法名称相同但签名不同的新方法**

18. 接口与抽象类的区别

  • 接口是一种约定,实现接口的类要遵循这个约定;
  • 抽象类本质上是一个类,使用抽象类的代价要比接口大。

  • 接口与抽象类的对比如下:

    • 抽象类中可以包含属性,方法(包含抽象方法与有着具体实现的方法),常量;接口只能包含常量和方法声明。

    • 抽象类中的方法和成员变量可以定义可见性(比如public、private等);而接口中的方法只能为public(缺省为public)。

    • 一个子类只能有一个父类(具体类或抽象类);而一个接口可以继承一个多个接口,一个类也可以实现多个接口。

    • 子类中实现父类中的抽象方法时,可见性可以大于等于父类中的;而接口实现类中的接口 方法的可见性只能与接口中相同(public)。

19. 静态内部类与非静态内部类的区别
静态内部类不会持有外围类的引用,而非静态内部类会隐式持有外围类的一个引用。

20. Java中多态的实现原理
所谓多态,指的就是父类引用指向子类对象,调用方法时会调用子类的实现而不是父类的实现。多态的实现的关键在于“动态绑定”。

21. 简述Java中创建新线程的两种方法

  • 继承Thread类(假设子类为MyThread),并重写run()方法,然后new一个MyThread对象并对其调用start()即可启动新线程。

  • 实现Runnable接口(假设实现类为MyRunnable),而后将MyRunnable对象作为参数传入Thread构造器,在得到的Thread对象上调用start()方法即可。

22. 简述Java中进行线程同步的方法

  • volatile: Java Memory Model保证了对同一个volatile变量的写happens before对它的读;

  • synchronized: 可以来对一个代码块或是对一个方法上锁,被“锁住”的地方称为临界区,进入临界区的线程会获取对象的monitor,这样其他尝试进入临界区的线程会因无法获取monitor而被阻塞。由于等待另一个线程释放monitor而被阻塞的线程无法被中断。

  • ReentrantLock: 尝试获取锁的线程可以被中断并可以设置超时参数。

23. 简述Java中具有哪几种粒度的锁
Java中可以对类、对象、方法或是代码块上锁。

24. 给出“生产者-消费者”问题的一种解决方案
使用阻塞队列:

<code class="scala">public <span class="hljs-class"><span class="hljs-keyword" style="color: rgb(0, 0, 136);">class</span> <span class="hljs-title" style="color: rgb(102, 0, 102);">BlockingQueueTest</span> {</span>  <span class="hljs-keyword" style="color: rgb(0, 0, 136);">private</span> int size = <span class="hljs-number" style="color: rgb(0, 102, 102);">20</span>;  <span class="hljs-keyword" style="color: rgb(0, 0, 136);">private</span> <span class="hljs-type">ArrayBlockingQueue</span><<span class="hljs-type">Integer</span>> blockingQueue = <span class="hljs-keyword" style="color: rgb(0, 0, 136);">new</span> <span class="hljs-type">ArrayBlockingQueue</span><>(size);  public static void main(<span class="hljs-type">String</span>[] args) {    <span class="hljs-type">BlockingQueueTest</span> test = <span class="hljs-keyword" style="color: rgb(0, 0, 136);">new</span> <span class="hljs-type">BlockingQueueTest</span>();     <span class="hljs-type">Producer</span> producer = test.<span class="hljs-keyword" style="color: rgb(0, 0, 136);">new</span> <span class="hljs-type">Producer</span>();     <span class="hljs-type">Consumer</span> consumer = test.<span class="hljs-keyword" style="color: rgb(0, 0, 136);">new</span> <span class="hljs-type">Consumer</span>();     producer.start(); consumer.start();   }   <span class="hljs-class"><span class="hljs-keyword" style="color: rgb(0, 0, 136);">class</span> <span class="hljs-title" style="color: rgb(102, 0, 102);">Consumer</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136);"><span class="hljs-keyword">extends</span></span> <span class="hljs-title" style="color: rgb(102, 0, 102);">Thread</span>{</span>     <span class="hljs-annotation" style="color: rgb(155, 133, 157);">@Override</span>     public void run() {       <span class="hljs-keyword" style="color: rgb(0, 0, 136);">while</span>(<span class="hljs-literal" style="color: rgb(0, 102, 102);">true</span>){         <span class="hljs-keyword" style="color: rgb(0, 0, 136);">try</span> {           <span class="hljs-comment" style="color: rgb(136, 0, 0);">//从阻塞队列中取出一个元素 </span>          queue.take();           <span class="hljs-type">System</span>.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0);">"队列剩余"</span> + queue.size() + <span class="hljs-string" style="color: rgb(0, 136, 0);">"个元素"</span>);         } <span class="hljs-keyword" style="color: rgb(0, 0, 136);">catch</span> (<span class="hljs-type">InterruptedException</span> e) {         }       }     }   }   <span class="hljs-class"><span class="hljs-keyword" style="color: rgb(0, 0, 136);">class</span> <span class="hljs-title" style="color: rgb(102, 0, 102);">Producer</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136);"><span class="hljs-keyword">extends</span></span> <span class="hljs-title" style="color: rgb(102, 0, 102);">Thread</span>{</span>     <span class="hljs-annotation" style="color: rgb(155, 133, 157);">@Override</span>     public void run() {       <span class="hljs-keyword" style="color: rgb(0, 0, 136);">while</span> (<span class="hljs-literal" style="color: rgb(0, 102, 102);">true</span>) {         <span class="hljs-keyword" style="color: rgb(0, 0, 136);">try</span> {           <span class="hljs-comment" style="color: rgb(136, 0, 0);">//向阻塞队列中插入一个元素 </span>          queue.put(<span class="hljs-number" style="color: rgb(0, 102, 102);">1</span>);           <span class="hljs-type">System</span>.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0);">"队列剩余空间:"</span> + (size - queue.size()));         } <span class="hljs-keyword" style="color: rgb(0, 0, 136);">catch</span> (<span class="hljs-type">InterruptedException</span> e) {         }       }     }   }}</code>

25. ThreadLocal的设计理念与作用
ThreadLocal的作用是提供线程内的局部变量,在多线程环境下访问时能保证各个线程内的ThreadLocal变量各自独立。也就是说,每个线程的ThreadLocal变量是自己专用的,其他线程是访问不到的。ThreadLocal最常用于以下这个场景:多线程环境下存在对非线程安全对象的并发访问,而且该对象不需要在线程间共享,但是我们不想加锁,这时候可以使用ThreadLocal来使得每个线程都持有一个该对象的副本。

26. concurrent包的整体架构


27. ArrayBlockingQueue, CountDownLatch类的作用

  • CountDownLatch: 允许线程集等待直到计数器为0。适用场景: 当一个或多个线程需要等待指定数目的事件发生后再继续执行。

  • ArrayBlockingQueue: 一个基于数组实现的阻塞队列,它在构造时需要指定容量。当试图向满队列中添加元素或者从空队列中移除元素时,当前线程会被阻塞。通过阻塞队列,我们可以按以下模式来工作:工作者线程可以周期性的将中间结果放入阻塞队列中,其它线程可以取出中间结果并进行进一步操作。若工作者线程的执行比较慢(还没来得及向队列中插入元素),其他从队列中取元素的线程会等待它(试图从空队列中取元素从而阻塞);若工作者线程执行较快(试图向满队列中插入元素),则它会等待其它线程取出元素再继续执行。

28. wait(),sleep() 的区别

  • wait(): Object类中定义的实例方法。在指定对象上调用wait方法会让当前线程进入等待状态(前提是当前线程持有该对象的monitor),此时当前线程会释放相应对象的monitor,这样一来其它线程便有机会获取这个对象的monitor了。当其它线程获取了这个对象的monitor并进行了所需操作时,便可以调用notify方法唤醒之前进入等待状态的线程。

  • sleep(): Thread类中的静态方法,作用是让当前线程进入休眠状态,以便让其他线程有机会执行。进入休眠状态的线程不会释放它所持有的锁。

29. 线程池的用法与优势

  • 优势: 实现对线程的复用,避免了反复创建及销毁线程的开销;使用线程池统一管理线程可以减少并发线程的数目,而线程数过多往往会在线程上下文切换上以及线程同步上浪费过多时间。

  • 用法: 我们可以调用ThreadPoolExecutor的某个构造方法来自己创建一个线程池。但通常情况下我们可以使用Executors类提供给我们的静态工厂方法来更方便的创建一个线程池对象。创建了线程池对象后,我们就可以调用submit方法提交任务到线程池中去执行了;线程池使用完毕后我们要记得调用shutdown方法来关闭它。

30. for-each与常规for循环的效率对比
关于这个问题我们直接看《Effective Java》给我们做的解答:

for-each能够让代码更加清晰,并且减少了出错的机会。
下面的惯用代码适用于集合与数组类型:

<code class="css"><span class="hljs-tag">for</span> (<span class="hljs-tag">Element</span> <span class="hljs-rule"><span class="hljs-attribute">e </span>:<span class="hljs-value"> elements) {    <span class="hljs-function" style="color: rgb(0, 102, 102);">doSomething</span>(e)</span></span>;}</code>

使用for-each循环与常规的for循环相比,并不存在性能损失,即使对数组进行迭代也是如此。实际上,在有些场合下它还能带来微小的性能提升,因为它只计算一次数组索引的上限。

31. 简述Java IO与NIO的区别

  • Java IO是面向流的,这意味着我们需要每次从流中读取一个或多个字节,直到读取完所有字节;NIO是面向缓冲的,也就是说会把数据读取到一个缓冲区中,然后对缓冲区中的数据进行相应处理。

  • Java IO是阻塞IO,而NIO是非阻塞IO。

  • Java NIO中存在一个称为选择器(selector)的东西,它允许你把多个通道(channel)注册到一个选择器上,然后使用一个线程来监视这些通道:若这些通道里有某个准备好可以开始进行读或写操作了,则开始对相应的通道进行读写。而在等待某通道变为可读/写期间,请求对通道进行读写操作的线程可以去干别的事情。

32. 反射的作用与原理
反射的作用概括地说是运行时获取类的各种定义信息,比如定义了哪些属性与方法。原理是通过类的class对象来获取它的各种信息。

33. 常见设计模式
所谓“设计模式”,不过是面向对象编程中一些常用的软件设计手法,并且经过实践的检验,这些设计手法在各自的场景下能解决一些需求,因此它们就成为了如今广为流传的”设计模式“。也就是说,正式因为在某些场景下产生了一些棘手的问题,才催生了相应的设计模式。明确了这一点,我们在学习某种设计模式时要充分理解它产生的背景以及它所解决的主要矛盾是什么。

常用的设计模式可以分为以下三大类:

  • 创建型模式: 包括工厂模式(又可进一步分为简单工厂模式、工厂方法模式、抽象工厂模式)、建造者模式、单例模式。

  • 结构型模式: 包括适配器模式、桥接模式、装饰模式、外观模式、享元模式、代理模式。

  • 行为型模式: 包括命令模式、中介者模式、观察者模式、状态模式、策略模式。

34. 注解的基本概念与使用
注解可以看作是“增强版的注释”,它可以向编译器、虚拟机说明一些事情。
注解是描述Java代码的代码,它能够被编译器解析,注解处理工具在运行时也能够解析注解。注解本身是“被动”的信息,只有主动解析它才有意义。
除了向编译器/虚拟机传递信息,我们也可以使用注解来生成一些“模板化”的代码。

学习Java的同学注意了!!! 
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:454297367  我们一起学Java!

0 0
原创粉丝点击