架构社区SSM社区SSH社区

【面试】java面试题集锦(一)

2017-05-22  本文已影响141人  慕凌峰
HashMap的实现原理图

11. ConcurrentHashMap的实现原理

ConcurrentHashMap是支持并发读写的HashMap,它的特点是读取数据时无需加锁,写数据时可以保证加锁粒度尽可能的小。由于其内部采用“分段存储”,只需对要进行写操作的数据所在的“段”进行加锁。关于ConcurrentHashMap底层实现的详细分析请参考 Java并发编程:并发容器之ConcurrentHashMap

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

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

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

LinkedHashMap能够记住插入元素的顺序。

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

Collection<E>是Java集合框架中的基本接口;

Collections是Java集合框架提供的一个工具类,其中包含了大量用于操作或返回集合的静态方法。
对Java集合框架还不太熟悉的小伙伴请参考 Java核心技术点之集合框架

14、对于“try-catch-finally”,若try语句块中包含“return”语句,finally语句块会执行吗?

答案是会执行。只有两种情况finally块中的语句不会被执行

15. Java中的异常层次结构

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

16. Java面向对象的三个特征与含义

三大特征:封装、继承、多态。

封装:封装也称信息隐藏,是指利用抽象数据类型把数据和基于数据的操作封装起来,使其成为一个不可分割的整体,数据隐藏在抽象数据内部,尽可能的隐藏数据细节,只保留一些接口使其与外界发生联系。也就是说用户无需知道内部的数据和方法的具体实现细节,只需根据留在外部的接口进行操作就行。

  • 封装的好处
    • 实现了专业的分工
    • 良好的封装能够减少耦合
    • 类内部的结构能够自有修改
    • 可以对成员进行更精确的控制
    • 隐藏信息,实现细节
  • Java继承是面向对象的最显著的一个特征。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。JAVA不支持多继承,单继承使JAVA的继承关系很简单,一个类只能有一个父类,易于管理程序,父类是子类的一般化,子类是父类的特化(具体化)
  • 继承所表达的就是一种对象类之间的相交关系,它使得某类对象可以继承另外一类对象的数据成员和成员方法。若类B继承类A,则属于B的对象便具有类A的全部或部分性质(数据属性)和功能(操作),我们称被继承的类A为基类、父类或超类,而称继承类B为A的派生类或子类。
  • 继承避免了对一般类和特殊类之间共同特征进行的重复描述。同时,通过继承可以清晰地表达每一项共同特征所适应的概念范围——在一般类中定义的属性和操作适应于这个类本身以及它以下的每一层特殊类的全部对象。运用继承原则使得系统模型比较简练也比较清晰。
  • 继承关系是传递的。若类C继承类B,类B继承类A(多继承),则类C既有从类B那里继承下来的属性与方法,也有从类A那里继承下来的属性与方法,还可以有自己新定义的属性和方法。继承来的属性和方法尽管是隐式的,但仍是类C的属性和方法。
  • 继承提供了软件复用功能。若类B继承类A,那么建立类B时只需要再描述与基类(类A)不同的少量特征(数据成员和成员方法)即可。这种做法能减小代码和数据的冗余度,大大增加程序的重用性。
  • 继承通过增强一致性来减少模块间的接口和界面,大大增加了程序的易维护性。

方法的重写、重载与动态连接构成多态性

Java之所以引入多态的概念,原因之一是它在类的继承问题上和C++不同,后者允许多继承,这确实给其带来的非常强大的功能,但是复杂的继承关系也给C++开发者带来了更大的麻烦,为了规避风险,Java只允许单继承,派生类与基类间有IS-A的关系(即“猫”is a “动物”)。这样做虽然保证了继承关系的简单明了,但是势必在功能上有很大的限制,所以,Java引入了多态性的概念以弥补这点的不足,此外,抽象类和接口也是解决单继承规定限制的重要手段。同时,多态也是面向对象编程的精髓所在。

  • 向上转型
    定义一个父类类型的引用指向一个子类的对象既可以使用子类强大的功能,又可以抽取父类的共性。
  • 父类引用只能调用父类中存在的方法和属性,不能调用子类的扩展部分;因为父类引用指向的是堆中子类对象继承的父类;(但是如果强制把超类转换成子类的话,就可以调用子类中新添加而超类没有的方法了。)
  • 重写
    • 父类中的一个方法只有在父类中定义而在子类中没有重写的情况下,才可以被父类类型的引用调用;
    • 对于父类中定义的方法,如果子类中重写了该方法,那么父类类型的引用将会调用子类中的这个方法,这就是动态连接。

17. Override, Overload的含义与区别

18. 接口与抽象类的区别

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

19. 静态内部类与非静态内部类的区别

http://www.cnblogs.com/absfree/p/5324695.html

/* 下面程序演示如何在java中创建静态内部类和非静态内部类 */
class OuterClass{
  private static String msg = "GeeksForGeeks";
  // 静态内部类
  public static class NestedStaticClass{
    // 静态内部类只能访问外部类的静态成员
    public void printMessage() {
     // 试着将msg改成非静态的,这将导致编译错误 
     System.out.println("Message from nested static class: " + msg); 
    }
  }
  // 非静态内部类
  public class InnerClass{
    // 不管是静态方法还是非静态方法都可以在非静态内部类中访问
    public void display(){
     System.out.println("Message from non-static nested class: "+ msg);
    }
  }
} 
class Main
{
  // 怎么创建静态内部类和非静态内部类的实例
  public static void main(String args[]){
    // 创建静态内部类的实例
    OuterClass.NestedStaticClass printer = new OuterClass.NestedStaticClass();
    // 创建静态内部类的非静态方法
    printer.printMessage();  
    // 为了创建非静态内部类,我们需要外部类的实例
    OuterClass outer = new OuterClass();    
    OuterClass.InnerClass inner = outer.new InnerClass();
    // 调用非静态内部类的非静态方法
    inner.display();
    // 我们也可以结合以上步骤,一步创建的内部类实例
    OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();
    // 同样我们现在可以调用内部类方法
    innerObject.display();
  }
}

20. Java中多态的实现原理

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

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

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

Java之多线程编程核心技术的6点整理

23. 简述Java中具有哪几种粒度的锁

Java中可以对类、对象、方法或是代码块上锁。更加详细的介绍请戳 Java核心技术点之多线程

24. 给出“生产者-消费者”问题的一种解决方案

使用阻塞队列:

public class BlockingQueueTest {
    private int size = 20;
    private ArrayBlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(size);

    public static void main(String[] args) {
        BlockingQueueTest test = new BlockingQueueTest();
        Producer producer = test.new Producer();
        Consumer consumer = test.new Consumer();
        producer.start();
        consumer.start();
    }

    class Consumer extends Thread {
        @Override
        public void run() {
            while (true) {
                try { // 从阻塞队列中取出一个元素
                    queue.take();
                    System.out.println("队列剩余" + queue.size() + "个元素");
                } catch (InterruptedException e) {
                }
            }
        }
    }

    class Producer extends Thread {
        @Override
        public void run() {
            while (true) {
                try { // 向阻塞队列中插入一个元素
                    queue.put(1);
                    System.out.println("队列剩余空间:" + (size - queue.size()));
                } catch (InterruptedException e) {
                }
            }
        }
    }
}

25. ThreadLocal的设计理念与作用

ThreadLocal的作用是提供线程内的局部变量,在多线程环境下访问时能保证各个线程内的ThreadLocal变量各自独立。也就是说,每个线程的ThreadLocal变量是自己专用的,其他线程是访问不到的。ThreadLocal最常用于以下这个场景:多线程环境下存在对非线程安全对象的并发访问,而且该对象不需要在线程间共享,但是我们不想加锁,这时候可以使用ThreadLocal来使得每个线程都持有一个该对象的副本。
关于ThreadLocal的实现原理分析请戳 Java核心技术点之动态代理

请关注,共同进步
上一篇 下一篇

猜你喜欢

热点阅读