面试总结:Java高级篇(下),收藏慢慢看!

22.关于抽象类和接口的关系

简言之抽象类是一种功能不全的类,接口只是一个抽象方法声明和静态不能被修改的数据的集合,两者都不能被实例化。

从某种意义上说,接口是一种特殊形式的抽象类,在java语言中抽象类表示的是一种继承关系,一个类只能继承继承一个抽象类,而一个类却可以实现多个接口。在许多情况下,接口确实可以代替抽象类,如果你不需要刻意表达属性上的继承的话。

23.堆内存和栈内存的区别

寄存器:JVM内部虚拟寄存器,存取速度非常快,程序不可控制。

栈:保存局部变量的值包括:1.保存基本数据类型的值;2.保存引用变量,即堆区对象的引用(指针)。也可以用来保存加载方法时的帧。

堆:用来存放动态产生的数据,比如new出来的对象。注意创建出来的对象只包含属于各自的成员变量,并不包括成员方法。因为同一个类的对象拥有各自的成员变量,存储在各自的堆中,但是他们共享该类的方法,并不是每创建一个对象就把成员方法复制一次。

常量池:JVM为每个已加载的类型维护一个常量池,常量池就是这个类型用到的常量的一个有序集合。包括直接常量(基本类型,String)和对其他类型、方法、字段的符号引用(1)。池中的数据和数组一样通过索引访问。由于常量池包含了一个类型所有的对其他类型、方法、字段的符号引用,所以常量池在Java的动态链接中起了核心作用。常量池存在于堆中。

代码段:用来存放从硬盘上读取的源程序代码。

数据段:用来存放static修饰的静态成员(在java中static的作用就是说明该变量,方法,代码块是属于类的还是属于实例的)。

24.关于Java文件的内部类的解释?匿名内部类是什么?如何访问在其外面定义的变量?

java中的内部类总结
静态内部类不能访问外部类非静态的成员

25.关于重载和重写的区别

重载是overload,是一个类中同方法名的不同具体实现。然后重写是override,是子类重写父类中的方法。

26.String、StringBuffer与StringBuilder之间区别

1.三者在执行速度方面的比较:StringBuilder > StringBuffer > String
String:字符串常量
StringBuffer:字符串变量
StringBuilder:字符串变量

2.StringBuilder:线程非安全的,StringBuffer:线程安全的

对于三者使用的总结:
1.如果要操作少量的数据用 = String
2.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
3.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer

27.运行时异常与一般异常有何异同?常见异常

Java提供了两类主要的异常:runtime exception和checked exception
常见异常:NullPointerException、IndexOutOfBoundsException、ClassNotFoundException,IllegalArgumentException,ClassCastException(数据类型转换异常)

28.error和exception有什么区别?

error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。
exception表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。

29.Java异常处理机制


1.捕获异常:try、catch 和 finally
2.抛出异常
2.1. throws抛出异常

30.java中有几种方法可以实现一个线程?

1.class Thread1 extends Thread{},然后重写run方法
2.class Thread2 implements Runnable{},然后重写run方法
3.class Thread3 implements Callable{},然后new FutureTask(thread3),再用new Thread(future)封装。
1234567891011121314151617181920212223242526272
class Thread1 extends Thread {private String name;public Thread1(String name) {this.name = name;}@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(name + “运行—>>>” + i);}}public static void main(String[] args) {Thread1 mTh11=new Thread1(“A”);Thread1 mTh12=new Thread1(“B”);mTh1.start();mTh2.start();}}class Thread2 implements Runnable {private String name;private int count = 15;public Thread2() {}public Thread2(String name) {this.name = name;}public void run() {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + “运行 : ” + count–);}}public static void main(String[] args) {Thread2 mTh2 = new Thread2();new Thread(mTh2, “C”).start();new Thread(mTh2, “D”).start();}}class MyCallableThread implements Callable<Integer>{public Integer call() throws Exception {int i = 0;for(;i<100;i++){System.out.println(Thread.currentThread().getName()+” “+i);}return i;}public static void main(String[] args) {MyCallableThread mct = new MyCallableThread();FutureTask<Integer> ft = new FutureTask<Integer>(mct);for(int i = 0;i < 100;i++){System.out.println(Thread.currentThread().getName()+” 的循环变量i的值”+i);if(i==20){new Thread(ft,”有返回值的线程”).start();}}try{System.out.println(“子线程的返回值:”+ft.get());} catch (InterruptedException e){e.printStackTrace();} catch (ExecutionException e){e.printStackTrace();}}}


如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。

31.Java中常用的类,包,接口。

class: ‘Date’,’System’,’Calender’,’Math’,’ArrayList’,’HashMap’package: ‘java.lang’,’java.util’,’java.io’,’java.sql’,’java.net’interface: ‘Collection’,’Map’,’List’,’Runnable’,’Callable’

32.java在处理线程同步时,常用方法有:

1、synchronized关键字。
2、Lock显示加锁。
3、信号量Semaphore。
4、CAS算法
5、concurrent包

33.Spring IOC/AOP?

回答了IOC/DI、AOP的概念。
AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。

也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,
在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。

但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者 实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。不管是依赖注入,还是控制反转,都说明Spring采用动态、灵活的方式来管理各种对象。对象与对象之间的具体实现互相透明。

在理解依赖注入之前,看如下这个问题在各种社会形态里如何解决:一个人(Java实例,调用者)需要一把斧子(Java实例,被调用者)。

34.对JVM的垃圾回收的认识?

垃圾回收器的作用是查找和回收(清理)无用的对象。以便让JVM更有效的使用内存。

35.进程与线程的区别,及其通信方式

线程与进程的区别及其通信方式
区别
1.一个程序至少有一个进程,一个进程至少有一个线程.
2.进程在执行过程中拥有独立的内存单元,而多个线程共享内存
3.线程是进程的一个实体,是CPU调度和分派的基本单位

进程间通信

123456
1.管道(Pipe)及有名管道(named pipe)2.信号(Signal)3.消息队列(Message)4.共享内存5.信号量(semaphore)6.套接口(Socket)

36.JVM如何GC,新生代,老年代,持久代,都存储哪些东西?

JVM的GC算法有:引用计数器算法,根搜索方法
新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。
在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。
持久代主要存放的是Java类的类信息

37.JVM分为哪些区,每一个区干嘛的?

问:Java运行时数据区域?
回答:包括程序计数器、JVM栈、本地方法栈、方法区、堆

问:方法区里存放什么?
本地方法栈:和jvm栈所发挥的作用类似,区别是jvm栈为jvm执行java方法(字节码)服务,而本地方法栈为jvm使用的native方法服务。
JVM栈:局部变量表、操作数栈、动态链接、方法出口。
方法区:用于存储已被虚拟机加载的类信息,常量、静态变量、即时编译器编译后的代码等。
堆:存放对象实例。

38.GC用的引用可达性分析算法中,哪些对象可作为GC Roots对象?

虚拟机栈(栈帧中的本地变量表)中引用的对象;
方法区中类静态属性引用的对象;
方法区中常量引用的对象;
本地方法栈中JNI(即一般说的Native方法)引用的对象

39.用什么工具调试程序?jmap、jstack,JConsole,用过吗?

虚拟机性能监控与调优实战–博客

40.线程池用过吗?

线程池–并发编程网 – ifeve.com

线程池(Thread Pool)对于限制应用程序中同一时刻运行的线程数很有用。因为每启动一个新线程都会有相应的性能开销,每个线程都需要给栈分配一些内存等等。

我们可以把并发执行的任务传递给一个线程池,来替代为每个并发执行的任务都启动一个新的线程。只要池里有空闲的线程,任务就会分配给一个线程执行。在线程池的内部,任务被插入一个阻塞队列(Blocking Queue ),线程池里的线程会去取这个队列里的任务。当一个新任务插入队列时,一个空闲线程就会成功的从队列中取出任务并且执行它。

41.操作系统如何进行分页调度?–要考LRU

1.最讲置换原则-OPT
2.先进先出原则-FIFO
3.最近最少使用置换算法-LRU
4.时钟置换算法

123456789101112131415
//扩展一下LinkedHashMap这个类,让他实现LRU算法class LRULinkedHashMap<K,V> extends LinkedHashMap<K,V>{//定义缓存的容量private int capacity;private static final long serialVersionUID = 1L;//带参数的构造器LRULinkedHashMap(int capacity){//调用LinkedHashMap的构造器,传入以下参数super(16,0.75f,true);//传入指定的缓存最大容量this.capacity=capacity;}//实现LRU的关键方法,如果map里面的元素个数大于了缓存最大容量,则删除链表的顶端元素@Overridepublic boolean removeEldestEntry(Map.Entry<K, V> eldest){System.out.println(eldest.getKey() + “=” + eldest.getValue());return size()>capacity;}}

42.讲讲LinkedHashMap

Java8 LinkedHashMap工作原理及实现

LinkedHashMap是通过哈希表和链表实现的,它通过维护一个链表来保证对哈希表迭代时的有序性,而这个有序是指键值对插入的顺序。
LinkedHashMap 的大致实现如下图所示,当然链表和哈希表中相同的键值对都是指向同一个对象,这里把它们分开来画只是为了呈现出比较清晰的结构。


LinkedHashMap是Hash表和链表的实现,并且依靠着双向链表保证了迭代顺序是插入的顺序。
三个重点实现的函数
在HashMap中提到了下面的定义:

1234567
// Callbacks to allow LinkedHashMap post-actions//1.把当前节点e移至链表的尾部。因为使用的是双向链表,所以在尾部插入可以以O(1)的时间复杂度来完成。并且只有当accessOrder设置为true时,才会执行这个操作。在HashMap的putVal方法中,就调用了这个方法。void afterNodeAccess(Node<K,V> p) { }//2.afterNodeInsertion方法是在哈希表中插入了一个新节点时调用的,它会把链表的头节点删除掉,删除的方式是通过调用HashMap的removeNode方法。通过afterNodeInsertion方法和afterNodeAccess方法,是不是就可以简单的实现一个基于最近最少使用(LRU)的淘汰策略了?当然,我们还要重写removeEldestEntry方法,因为它默认返回的是false。void afterNodeInsertion(boolean evict) { }//3.这个方法是当HashMap删除一个键值对时调用的,它会把在HashMap中删除的那个键值对一并从链表中删除,保证了哈希表和链表的一致性。void afterNodeRemoval(Node<K,V> p) { }

LinkedHashMap继承于HashMap,因此也重新实现了这3个函数,顾名思义这三个函数的作用分别是:节点访问后、节点插入后、节点移除后做一些事情。

43.线程同步与阻塞的关系?同步一定阻塞吗?阻塞一定同步吗?,同步和异步有什么区别?

同步与非同步:主要是保证互斥的访问临界资源的情况
阻塞与非阻塞:主要是从 CPU 的消耗上来说的

44.int与Integer的区别,分别什么场合使用

1234
1、Integer是int提供的封装类,而int是Java的基本数据类型2、Integer默认值是null,而int默认值是0;3、声明为Integer的变量需要实例化,而声明为int的变量不需要实例化;4、Integer是对象,用一个引用指向这个对象,而int是基本类型,直接存储数值。

int是基本数据类型,Integer是包装类,类似HashMap这样的结构必须使用包装类,因为包装类继承自Object,都需要实现HashCode,所以可以使用在HashMap这类数据结构中。

45.RPC的详细过程

RPC主要的重点有:
动态代理,主要是invoke反射原理
序列化,使用Thrift的效率高
通信方式,使用Netty的NIO能提高效率
服务发现,使用zookeeper可以实现

1、服务消费方(client)调用以本地调用方式调用服务;
2、client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
3、client stub找到服务地址,并将消息发送到服务端;
4、server stub收到消息后进行解码;
5、server stub根据解码结果调用本地的服务;
6、本地服务执行并将结果返回给server stub;
7、server stub将返回结果打包成消息并发送至消费方;
8)client stub接收到消息,并进行解码;
9、服务消费方得到最终结果。

本站所有文章均由网友分享,仅用于参考学习用,请勿直接转载,如有侵权,请联系网站客服删除相关文章。若由于商用引起版权纠纷,一切责任均由使用者承担
极客文库 » 面试总结:Java高级篇(下),收藏慢慢看!

欢迎加入「极客文库」,成为原创作者从这里开始!

立即加入 了解更多