1、实例方法和静态方法有什么不一样?
答:实例方法只能在其类下调用,而静态方法可以直接调用。
答:1、在外部调用静态方法时可以用“类名.方法名”和“对象名.方法名”调用方法;而实例方法只能用“对象名.方法名”调用方法。(调用静态方法可以无需创建对象)2、静态方法在访问本类时不能直接调用实例成员(实例成员变量和实例方法),只能调用静态成员;而实例方法则都可以。
2、Java中的异常有哪几类?分别怎么使用?
答:常见的异常有:
1、java.lang.nullpointerexception “程序遇上了空指针”,即调用了未经初始化的对象或者是不存在。
2、java.lang.classnotfoundexception “指定类不存在”,这里主要注意类的名称或路径是否正确。
3、java.lang.arrayindexoutofboundsexception “数组下标越界”,即调用的数组下标超过了数组的范围。
4、FileNotFoundException “文件未找到异常”,检查文件名是否正确或是否存在。
5、IOException “输入输出流异常” ,进行输入输出操作时出问题或找不到文件。
6、NoSuchMehodException “方法异常”,调用的放法未定义。
三、常用的集合类有哪些?
答:List,Set,Map。
1、List:实现类ArrayList和LinkedList
①、ArrayList:索引从零开始,线性存储,有索引,有顺序、可重复
②、LinkedList:线性存储,有索引、有顺序、链表结构、可重复
2、Set:不需要编号与名,存放速度快但不好取,不允许重复,具体的 Set 实现类依赖添加的对象的 equals() 方法来检查等同性,实现类HashSet和TreeSet
①、HashSet:无序,调用对象的hashCode()方法,获取哈希码,从在集合中计算存放对象的位置;底层通过比较哈希码与equals()方法来判别是否重复。
②、TreeSet:树型排序,只能对实现了Comparable借口的对象排序。
3、Map:以键值对的形式存储对象,键不能重复,实现类HashMap和TreeMap
①、HashMap:无序、按照哈希算法来存取键对象,可重载hashCode()和equals()方法来比较键,但两者必须一致。
②、TreeMap:可树型排序,通过传递Comparator的实现类构造TreeMap。
4、ArrayList和LinkedList的内部实现?
答:ArrayList是基于数组的数据结构,其在增加时若数组不满足增加量时会进行数组扩容,同时还需要数据搬迁,同理在删除时也需要数据搬迁。
LinkedList是基于链表的数据结构,通过内部的一个元素类内存放元素,增加和删除只需要在上下指针增减新元素。
所以,ArrayList的读取性较好,基于数组索引的index索引,但写入率不太好,需要数据搬迁,适合于随机读取;而LinkedList的读取率不太好,需要遍历链表,但写入率可以,更适用于顺序读取。
5、内存溢出?
答:即运行所需内存超过JVM所提供的内存承受范围,JVM所管理的内存大致分为三部分区域:①永久保存区域 ②堆区域 ③JAVA栈区域
①永久保存区域:主要保存class 和 mete的信息,class需要保存的内容主要包括方法和静态属性;
②堆区域:主要存放的是对象,每次用new创建一个对象实例时,对象实例存储于堆区域,这部分空间会被JVM的垃圾回收机制管理,堆区域只有一个;
③JAVA栈区域:主要存放基本类型变量和方法的输入输出参数以及对象的引用,JAVA程序的每个线程就有一个独立的Java栈。
6、ClassLoader?
答:类加载器。Java程序(class文件)并不是本地的可执行文件。当运行Java文件时,首先运行JVM,然后再把Java class加载到JVM中运行,负责加载Java class的部分就叫ClassLoader。
7、==和equals的区别?
答:对于基本数据类型,==比较的是值是否相同,对于引用对象,==比较的是一个对象在内存中的地址。
而equals 不用于比较基本类型但可以用于比较基本数据类型包装类的值是否相等,对于引用对象,equals在Java.lang.object中定义的是同样用==对内存地址进行比较,而在许多类中都重写类该方法,比如String会对内存地址引用不相等时,还会进行值比较,所以如果没有重写父类object的equals时,它用法与==一样。
8、hashCode()方法的作用?
答:hashCode()在Object中定义,根据对象的特定字段运用哈希算法得出特定的哈希码,一般hashCode()方法运用于集合中根据哈希码加快查询的速率,迅速地查找出相匹配的桶取出值,同时hashCode()常用于equals()方法中根据哈希码比对对象的内存地址是否相同。
9、Object类常用的方法?
答:boolean equals(Object object)判断某对象是否与此对象“相等”。
int hashCode()返回对象的哈希码值。
String toString()返回对象的字符串表达。
10、NIO是什么?
答:即non-blocking IO,为所有的原始类型提供缓存支持,定义为数据容器的缓冲区。其Channel不同于IO的单向Stream,Channel是双向的可读可写;Buffer(缓冲区)相当于一个容器,NIO写数据和读数据放进Buffer中;Selector是NIO的核心类,Selector能够检测多个注册通道上是否有事件发生,若有,便获取事件然后对事件进行相应的响应。这样便可以单个线程管理多个连接,同时大大减少了系统开销,不必创建多个线程。
11、GC(垃圾回收)算法?
答:①、引用计数(reference counting)原理:此对象有一个引用,则+1;此对象删除一个引用,则-1。GC收集为0的对象。
②、复制(copying)原理:把内存空间分为两个相等的区域,每次只使用一个区域。垃圾回收时,便利当前区域把正在使用的对象复制到另一份区域。
③、标记-清扫(Mark and sweep)原理:对于“活”的对象,一定可以追溯到其存活在堆栈和静态存储区的引用。这个引用链条可能穿过数个对象层次,算法基于有向图,采用深度游戏搜索。先从GC roots开始遍历所有引用,对活的对象进行标记,然后对堆进行遍历把未标记的对象清除。
④、标记-压缩(Mark-Compact)原理:同标记-清除,标记活的对象,然后将所有标记了的对象整理到堆的底部。
⑤、分代(generationl collecting)原理:基于对象生命周期分析得出的垃圾回收算法。把对象分为年轻代、年老代、持久代,对不同的生命周期进行不同的算法进行回收。
新生代的GC(Minor GC)Minor GC非常频繁,一般回收速度也比较快。新生代存活时间较短,因此基于Copying算法来进行回收,对于新生代就是就是在Eden和FromSpace或ToSpace之间copy,新生代采用空闲指针的方式来控制GC触发,指针保持最后一个分配的对象在新生代区间的位置,当有新的对象要分配内存时,用于检查空间是否足够,不够就触发GC。当连续分配对象时,对象会逐渐从eden到survivor。
旧生代的GC(MajorGC/FullGC)对象存活比较久,比较稳定,因此采用Mark算法进行回收,扫描标记处活的对象,然后未标记的对象进行回收,回收后对空出来的空间进行合并,要么标记出来便于下次分配,总之减少内存碎片带来的损耗。
MajorGC 的速度一般会比 Minor GC 慢 10倍以上。
java GC即是“自适应、分代的、停止-复制、标记-扫描”式的垃圾回收器。
12、CMS(Concurrent Mark Sweep)?
答:并行垃圾处理机制,GC和程序并发执行。
Young GC,Stop the world冻结所有内存,程序执行,但并发的程序需要一些Stop the world的时间和Copying collector,多线程操作扫描和Copy,减少Stop the world的时间。
Old GC,程序和GC并发执行:
Initial Phase:短暂停,标记GC根集合,单线程执行。
Concurrent making phase:GC多线程标记从根集合可达的所有活对象。由于程序和GC并发运行,可能有活对象未被标记。
Concurrent pre-clean:单线程,并发执行。
Remark phase: 短暂停,多线程标记在Concurrent marking phase中有变化的相关对象。
Concurrent sweep phase:和程序并发执行。单线程执行。不做compacting。
concurrent reset:单线程,并发执行。
CMS需要更多的内存空间,因为mark phase时程序还是在运行,程序可以申请更多的old空间。在mark phase中,CMS保证标识活对象,但是该过程中,活对象可能转变为垃圾,只能等待下一次GC才能回收。
和其他Collector不同,CMS不是等到old满时才GC,基于以前的统计数据(GC时间,Old空间消耗速度)来决定何时GC。CMS GC也可以基于old空间的占用率。
13、创建类的实例的方法?
①、用new语句创建对象,这是最常见的创建对象的方法。
②、通过工厂方法返回对象,如:String str = String.valueOf(23);
③、运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。如:Object obj = Class.forName("java.lang.Object").newInstance();
④、调用对象的clone()方法。
⑤、通过I/O流(包括反序列化),如运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法。
14、final/finally/finalize的区别?
答:①:final为用于标示常量的关键字,若定义的是基本类型,表示基本类型被赋予的值不可变;若定义方法,表示方法不能被覆盖;若定义类,表示类不能被继承。
②:finally是异常处理try/catch语句的一部分,表示无论是try或catch,finally里的语句都会在最后被执行。
③:finalize()是Object类的一个子方法,由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。
15、Session/Cookie的区别?
答:①,session 在服务器端,cookie 在客户端(浏览器)
②,session 默认被存在在服务器的一个文件里(不是内存)
③,session 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是说,如果浏览器禁用了 cookie ,同时 session 也会失效(但是可以通过其它方式实现,比如在 url 中传递 session_id)
④,session 可以放在 文件、数据库、或内存中都可以。
⑤,用户验证这种场合一般会用 session
16、StringBuffer/StringBuilder的区别,扩展再问他们的实现?
①. 在执行速度方面的比较:StringBuilder > StringBuffer
②. StringBuffer与StringBuilder,他们是字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,不像String一样创建一些对象进行操作,所以速度就快了。
③. StringBuilder:线程非安全的
StringBuffer:线程安全的
StringBuffer与StringBuilder都继承自AbstractStringBuilder
AbstractStringBuilder的实现原理:我们知道使用StringBuffer等无非就是为了提高java中字符串连接的效率,因为直接使用+进行字符串连接的话,jvm会创建多个String对象,因此造成一定的开销。AbstractStringBuilder中采用一个char数组来保存需要append的字符串,char数组有一个初始大小,当append的字符串长度超过当前char数组容量时,则对char数组进行动态扩展,也即重新申请一段更大的内存空间,然后将当前char数组拷贝到新的位置,因为重新分配内存并拷贝的开销比较大,所以每次重新申请内存空间都是采用申请大于当前需要的内存空间的方式,这里是2倍。
17、Servlet的生命周期?
①、初始化阶段,调用Init()方法。(Servlet初始化的时刻:①、Servlet容器启动时自动装载某些Servlet,实现它要在Web.xml文件中的
Servlet被装载后,Servlet容器创建Servlet实例并调用Init()方法进行初始化,整个Servlet周期内,Init()方法只被调用一次。
②、响应客户请求,调用Service()方法。
③、终止阶段,调用Destory()方法。
Servlet工作原理:
首先简单解释一下Servlet接收和响应客户请求的过程,首先客户发送一个请求,Servlet是调用service()方法对请求进行响应的,service()方法中对请求的方式进行了匹配,选择调用doGet,doPost等这些方法,然后再进入对应的方法中调用逻辑层的方法,实现对客户的响应。在Servlet接口和GenericServlet中是没有doGet,doPost等等这些方法的,HttpServlet中定义了这些方法,但是都是返回error信息,所以,我们每次定义一个Servlet的时候,都必须实现doGet或doPost等这些方法。
每一个自定义的Servlet都必须实现Servlet的接口,Servlet接口中定义了五个方法,其中比较重要的三个方法涉及到Servlet的生命周期,分别是上文提到的init(),service(),destroy()方法。GenericServlet是一个通用的,不特定于任何协议的Servlet,它实现了Servlet接口。而HttpServlet继承于GenericServlet,因此HttpServlet也实现了Servlet接口。所以我们定义Servlet的时候只需要继承HttpServlet即可。
Servlet接口和GenericServlet是不特定于任何协议的,而HttpServlet是特定于HTTP协议的类,所以HttpServlet中实现了service()方法,并将请求ServletRequest,ServletResponse强转为HttpRequest和HttpResponse。