珠海网站开发维护科技公司,长沙百度网站制作,网站开发中心,郑州网站制作费用本篇文章会对面试中常遇到的Java技术点进行全面深入的总结#xff0c;帮助我们在面试中更加得心应手#xff0c;不参加面试的同学也能够借此机会梳理一下自己的知识体系#xff0c;进行查漏补缺。 1. Java中的原始数据类型都有哪些#xff0c;它们的大小及对应的封装类是什… 本篇文章会对面试中常遇到的Java技术点进行全面深入的总结帮助我们在面试中更加得心应手不参加面试的同学也能够借此机会梳理一下自己的知识体系进行查漏补缺。 1. Java中的原始数据类型都有哪些它们的大小及对应的封装类是什么 1boolean boolean数据类型非true即false。这个数据类型表示1 bit的信息但是它的大小并没有精确定义。 《Java虚拟机规范》中如是说“虽然定义了boolean这种数据类型但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令Java语言表达式所操作的boolean值在编译之后都使用Java虚拟机中的int数据类型来代替而boolean数组将会被编码成Java虚拟机的byte数组每个元素boolean元素占8位”。这样我们可以得出boolean类型单独使用是4个字节在数组中又是1个字节。那虚拟机为什么要用int来代替boolean呢为什么不用byte或short这样不是更节省内存空间吗实际上使用int的原因是对于当下32位的CPU来说一次进行32位的数据交换更加高效。 综上我们可以知道官方文档对boolean类型没有给出精确的定义《Java虚拟机规范》给出了“单独时使用4个字节boolean数组时1个字节”的定义具体还要看虚拟机实现是否按照规范来所以1个字节、4个字节都是有可能的。这其实是一种时空权衡。 boolean类型的封装类是Boolean。 2byte——1 byte——Byte 3short——2 bytes——Short 4int——4 bytes——Integer 5long——8 bytes——Long 6float——4 bytes——Float 7double——8 bytes——Double 8char——2 bytes——Character 2. 谈一谈”“与”equals()的区别。 《Think in Java》中说“关系操作符生成的是一个boolean结果它们计算的是操作数的值之间的关系”。 判断的是两个对象的内存地址是否一样适用于原始数据类型和枚举类型它们的变量存储的是值本身而引用类型变量存储的是引用equals是Object类的方法Object对它的实现是比较内存地址我们可以重写这个方法来自定义“相等”这个概念。比如类库中的String、Date等类就对这个方法进行了重写。 综上对于枚举类型和原始数据类型的相等性比较应该使用对于引用类型的相等性比较应该使用equals方法。 3. Java中的四种引用及其应用场景是什么 强引用: 通常我们使用new操作符创建一个对象时所返回的引用即为强引用 软引用: 若一个对象只能通过软引用到达那么这个对象在内存不足时会被回收可用于图片缓存中内存不足时系统会自动回收不再使用的Bitmap 弱引用: 若一个对象只能通过弱引用到达那么它就会被回收即使内存充足同样可用于图片缓存中这时候只要Bitmap不再使用就会被回收 虚引用: 虚引用是Java中最“弱”的引用通过它甚至无法获取被引用的对象它存在的唯一作用就是当它指向的对象回收时它本身会被加入到引用队列中这样我们可以知道它指向的对象何时被销毁。 4. object中定义了哪些方法 clone(), equals(), hashCode(), toString(), notify(), notifyAll(), wait(), finalize(), getClass() 5. hashCode的作用是什么 请参见散列表的基本原理与实现 6. ArrayList, LinkedList, Vector的区别是什么 ArrayList: 内部采用数组存储元素支持高效随机访问支持动态调整大小 LinkedList: 内部采用链表来存储元素支持快速插入/删除元素但不支持高效地随机访问 Vector: 可以看作线程安全版的ArrayList 7. String, StringBuilder, StringBuffer的区别是什么 String: 不可变的字符序列若要向其中添加新字符需要创建一个新的String对象 StringBuilder: 可变字符序列支持向其中添加新字符无需创建新对象 StringBuffer: 可以看作线程安全版的StringBuilder 8. Map, Set, List, Queue、Stack的特点及用法。 MapK, V: Java中存储键值对的数据类型都实现了这个接口表示“映射表”。支持的两个核心操作是get(Object key)以及put(K key, V value)分别用来获取键对应的值以及向映射表中插入键值对。 SetE: 实现了这个接口的集合类型中不允许存在重复的元素代表数学意义上的“集合”。它所支持的核心操作有add(E e), remove(Object o), contains(Object o)分别用于添加元素删除元素以及判断给定元素是否存在于集中。 ListE: Java中集合框架中的列表类型都实现了这个接口表示一种有序序列。支持get(int index), add(E e)等操作。 QueueE: Java集合框架中的队列接口代表了“先进先出”队列。支持add(E element), remove()等操作。 StackE: Java集合框架中表示堆栈的数据类型堆栈是一种“后进先出”的数据结构。支持push(E item), pop()等操作。 更详细的说明请参考官方文档对相关数据结构不太熟悉的同学可以参考《算法导论》或其他相关书籍。 9. HashMap和HashTable的区别 HashTable是线程安全的而HashMap不是 HashMap中允许存在null键和null值而HashTable中不允许 更加详细的分析请参考深入解析HashMap、HashTable 10. HashMap的实现原理 简单的说HashMap的底层实现是“基于拉链法的散列表”。详细分析请参考深入解析HashMap、HashTable 11. ConcurrentHashMap的实现原理 ConcurrentHashMap是支持并发读写的HashMap它的特点是读取数据时无需加锁写数据时可以保证加锁粒度尽可能的小。由于其内部采用“分段存储”只需对要进行写操作的数据所在的“段”进行加锁。关于ConcurrentHashMap底层实现的详细分析请参考Java并发编程并发容器之ConcurrentHashMap 12. TreeMap, LinkedHashMap, HashMap的区别是什么 HashMap的底层实现是散列表因此它内部存储的元素是无序的 TreeMap的底层实现是红黑树所以它内部的元素的有序的。排序的依据是自然序或者是创建TreeMap时所提供的比较器Comparator对象。 LinkedHashMap能够记住插入元素的顺序。 更加详细的说明请参考HashMapLinkedMapTreeMap的区别 13. Collection与Collections的区别是什么 CollectionE是Java集合框架中的基本接口Collections是Java集合框架提供的一个工具类其中包含了大量用于操作或返回集合的静态方法。 对Java集合框架还不太熟悉的小伙伴请参考Java核心技术点之集合框架 14. 对于“try-catch-finally”若try语句块中包含“return”语句finally语句块会执行吗 答案是会执行。只有两种情况finally块中的语句不会被执行 调用了System.exit()方法 JVM“崩溃”了。 15. Java中的异常层次结构 Java中的异常层次结构如下图所示 我们可以看到Throwable类是异常层级中的基类。Error类表示内部错误这类错误使我们无法控制的Exception表示异常RuntimeException及其子类属于未检查异常这类异常包括ArrayIndexOutOfBoundsException、NullPointerException等我们应该通过条件判断等方式语句避免未检查异常的发生。IOException及其子类属于已检查异常编译器会检查我们是否为所有可能抛出的已检查异常提供了异常处理器若没有则会报错。对于未检查异常我们无需捕获当然Java也允许我们捕获但我们应该做的事避免未检查异常的发生。 16. Java面向对象的三个特征与含义 三大特征封装、继承、多态。详细介绍请戳Java面向对象三大特性 17. Override, Overload的含义与区别 Override表示“重写”是子类对父类中同一方法的重新定义 Overload表示“重载”也就是定义一个与已定义方法名称相同但签名不同的新方法 18. 接口与抽象类的区别 接口是一种约定实现接口的类要遵循这个约定抽象类本质上是一个类使用抽象类的代价要比接口大。接口与抽象类的对比如下 抽象类中可以包含属性方法包含抽象方法与有着具体实现的方法常量接口只能包含常量和方法声明。 抽象类中的方法和成员变量可以定义可见性比如public、private等而接口中的方法只能为public缺省为public。 一个子类只能有一个父类具体类或抽象类而一个接口可以继承一个多个接口一个类也可以实现多个接口。 子类中实现父类中的抽象方法时可见性可以大于等于父类中的而接口实现类中的接口 方法的可见性只能与接口中相同public。 19. 静态内部类与非静态内部类的区别 静态内部类不会持有外围类的引用而非静态内部类会隐式持有外围类的一个引用。 欲进一步了解内部类请戳Java核心技术点之内部类 20. Java中多态的实现原理 所谓多态指的就是父类引用指向子类对象调用方法时会调用子类的实现而不是父类的实现。多态的实现的关键在于“动态绑定”。详细介绍请戳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: 尝试获取锁的线程可以被中断并可以设置超时参数。 更加详细的介绍请戳Java核心技术点之多线程 23. 简述Java中具有哪几种粒度的锁 Java中可以对类、对象、方法或是代码块上锁。更加详细的介绍请戳Java核心技术点之多线程 24. 给出“生产者-消费者”问题的一种解决方案 使用阻塞队列 public class BlockingQueueTest {private int size 20;private ArrayBlockingQueueInteger 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{Overridepublic void run() {while(true){try {//从阻塞队列中取出一个元素queue.take();System.out.println(队列剩余 queue.size() 个元素);} catch (InterruptedException e) {}}}}class Producer extends Thread{ Overridepublic 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的实现原理分析请戳深入剖析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方法来关闭它。 关于线程池的详细介绍以及实现原理分析请戳深入理解Java之线程池 30. for-each与常规for循环的效率对比 关于这个问题我们直接看《Effective Java》给我们做的解答 for-each能够让代码更加清晰并且减少了出错的机会。下面的惯用代码适用于集合与数组类型 for (Element e : elements) {doSomething(e);} 使用for-each循环与常规的for循环相比并不存在性能损失即使对数组进行迭代也是如此。实际上在有些场合下它还能带来微小的性能提升因为它只计算一次数组索引的上限。 31. 简述Java IO与NIO的区别 Java IO是面向流的这意味着我们需要每次从流中读取一个或多个字节直到读取完所有字节NIO是面向缓冲的也就是说会把数据读取到一个缓冲区中然后对缓冲区中的数据进行相应处理。 Java IO是阻塞IO而NIO是非阻塞IO。 Java NIO中存在一个称为选择器selector的东西它允许你把多个通道channel注册到一个选择器上然后使用一个线程来监视这些通道若这些通道里有某个准备好可以开始进行读或写操作了则开始对相应的通道进行读写。而在等待某通道变为可读/写期间请求对通道进行读写操作的线程可以去干别的事情。 更进一步的说明请戳Java NIO与IO 32. 反射的作用与原理 反射的作用概括地说是运行时获取类的各种定义信息比如定义了哪些属性与方法。原理是通过类的class对象来获取它的各种信息。 详细介绍请参见Java核心技术点之反射 33. Java中的泛型机制 关于泛型机制的详细介绍请直接戳Java核心技术点之泛型 34. Java 7与Java 8的新特性 这里有两篇总结的非常好的Java 7的新特性 Java 8的新特性 35. 常见设计模式 所谓“设计模式”不过是面向对象编程中一些常用的软件设计手法并且经过实践的检验这些设计手法在各自的场景下能解决一些需求因此它们就成为了如今广为流传的”设计模式“。也就是说正式因为在某些场景下产生了一些棘手的问题才催生了相应的设计模式。明确了这一点我们在学习某种设计模式时要充分理解它产生的背景以及它所解决的主要矛盾是什么。 常用的设计模式可以分为以下三大类 创建型模式: 包括工厂模式又可进一步分为简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式、单例模式。 结构型模式: 包括适配器模式、桥接模式、装饰模式、外观模式、享元模式、代理模式。 行为型模式: 包括命令模式、中介者模式、观察者模式、状态模式、策略模式。 关于每个模式具体的介绍请参考图说设计模式 36. JNI的基本用法 关于JNI这里有篇好文Android中的JNI 37. 动态代理的定义、应用场景及原理 关于动态代理请直接参见Java核心技术点之动态代理 38. 注解的基本概念与使用 注解可以看作是“增强版的注释”它可以向编译器、虚拟机说明一些事情。 注解是描述Java代码的代码它能够被编译器解析注解处理工具在运行时也能够解析注解。注解本身是“被动”的信息只有主动解析它才有意义。 除了向编译器/虚拟机传递信息我们也可以使用注解来生成一些“模板化”的代码。 关于注解更进一步的分析请参考Java核心技术点之注解 这些就够了吗当然不够。上面列出了面试中关于Java的常见问题同时大多也是Java技术体系的核心技术点通过这些问题而引发出的一系列问题正是为我们指出了完善自身知识体系的一条道路我们要做的是顺着这条道路坚持走下去