Java基础回顾——重难点易错点【1】

最近在学习一些框架时看到了很多思想结构比较好的源码,然后也遇见了很多自己以前忽略的一些基础“知识点”,于是就从一些笔试面试题中找了一下,记录一遍加深一下印象。

  1. HashMap 和 Hashtable个类都实现了Map接口,二者保存K-V对(key-value对);
    HashTable不允许null值(key和value都不可以),HashMap允许null值(key和value都可以);
    Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap
    就必须为之提供外同步; 由所有HashMap类的“collection
    视图方法”所返回的迭代器都是快速失败的:在迭代器创建之后,如果从结构上对映射进行修改,除非通过迭代器本身的 remove
    方法,其他任何时间任何方式的修改,迭代器都将抛出ConcurrentModificationException。迭代 HashMap
    采用快速失败机制,而 HashTable 不是,因为 HashTable 是线程安全的。
    java的快速失败机制,即fail-fast,它是Java集合的一种错误检测机制。当多个线程对集合进行结构上的改变的操作时,有可能会产生fail-fast机制。记住是有可能,而不是一定。
    例如:假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出
    ConcurrentModificationException 异常,从而产生fail-fast机制。

  2. HttpServletResponse 在Servlet中,当服务器响应客户端的一个请求时,就要用到HttpServletResponse接口。设置响应的类型可以使用setContentType()方法。发送字符数据,可以使用getWriter()返回一个对象。接口HttpServletResponse的常用方法:

    addCookie(Cookie cookie) 将指定的Cookie加入到当前的响应中;
    addHeader(String name,String value) 将指定的名字和值加入到响应的头信息中;
    containsHeader(String name) 返回一个布尔值,判断响应的头部是否被设置;
    encodeURL(String url) 编码指定的URL sendError(int sc) 使用指定状态码发送一个错误到客户端 ;
    sendRedirect(String location) 发送一个临时的响应到客户端 ;setDateHeader(String name,long date) 将给出的名字和日期设置响应的头部 ;
    setHeader(String name,String value) 将给出的名字和值设置响应的头部 。
    HttpServletRequest在Servlet中从request获取各种路径总结 request.getRealPath(“url”) 虚拟目录映射为实际目录 ;request.getRealPath(“./”) 网页所在的目录 ;
    request.getRealPath(“../”) 网页所在目录的上一层目录 ;request.getContextPath() 应用的web目录的名称;

  3. 值传递与**引用传递**Java中原始数据类型都是值传递,传递的是值得副本,形参的改变不会影响实际参数的值, 引用传递传递的是引用类型数据,包括String,数组,列表, map,类对象等类型,形参与实参指向的是同一内存地址,因此形参改变会影响实参的值。
    示例:Java基础回顾——重难点易错点【1】

  4. 桥接模式
    定义 :将抽象部分与它的实现部分分离,使它们都可以独立地变化。
    意图 :将抽象与实现解耦。
    桥接模式所涉及的角色 :
    Abstraction :定义抽象接口,拥有一个Implementor类型的对象引用 ;
    RefinedAbstraction :扩展Abstraction中的接口定义 ;
    Implementor :是具体实现的接口,Implementor和RefinedAbstraction接口并不一定完全一致,实际上这两个接口可以完全不一样Implementor提供具体操作方法,而Abstraction提供更高层次的调用 ;
    ConcreteImplementor :实现Implementor接口,给出具体实现
    Jdk中的桥接模式:JDBC
    JDBC连接 数据库 的时候,在各个数据库之间进行切换,基本不需要动太多的代码,甚至丝毫不动,原因就是JDBC提供了统一接口,每个数据库提供各自的实现,用一个叫做数据库驱动的程序来桥接就行了

  5. JDK中的来及回收器
    Java基础回顾——重难点易错点【1】

  6. 多线程中的几个方法区别:
    (1)suspend() 和 resume() 方法:两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的 resume() 被调用,才能使得线程重新进入可执行状态, suspend()函数让当前线程进入停滞状态,除非收到resume()信号,否则不唤醒。【总之:、 resume与suspended一起使用,但是现在jdk声明不再使用这两个方法。】
    (2)wait()与notify()、notifyAll()一起使用:
    wait():导致当前线程等待并使其进入到等待阻塞状态。直到其他线程调用该同步锁对象的notify()或notifyAll()方法来唤醒此线程。
    notify():唤醒在此同步锁对象上等待的单个线程,如果有多个线程都在此同步锁对象上等待,则会任意选择其中某个线程进行唤醒操作,只有当前线程放弃对同步锁对象的锁定,才可能执行被唤醒的线程。
    notifyAll():唤醒在此同步锁对象上等待的所有线程,只有当前线程放弃对同步锁对象的锁定,才可能执行被唤醒的线程。
    (3)sleep让当前的正在执行的线程暂停指定的时间,并进入阻塞状态。在其睡眠的时间段内,该线程由于不是处于就绪状态,因此不会得到执行的机会。即使此时系统中没有任何其他可执行的线程,出于sleep()中的线程也不会执行。因此sleep()方法常用来暂停线程执行。
    【注意:】我们需要注意如下几点:
    1.wait()方法执行后,当前线程立即进入到等待阻塞状态,其后面的代码不会执行;
    2.notify()/notifyAll()方法执行后,将唤醒此同步锁对象上的(任意一个-notify()/所有-notifyAll())线程对象,但是,此时还并没有释放同步锁对象,也就是说,如果notify()/notifyAll()后面还有代码,还会继续进行,知道当前线程执行完毕才会释放同步锁对象;
    3.notify()/notifyAll()执行后,如果右面有sleep()方法,则会使当前线程进入到阻塞状态,但是同步对象锁没有释放,依然自己保留,那么一定时候后还是会继续执行此线程,接下来同2;
    4.wait()/notify()/nitifyAll()完成线程间的通信或协作都是基于不同对象锁的,因此,如果是不同的同步对象锁将失去意义,同时,同步对象锁最好是与共享资源对象保持一一对应关系;
    5.当wait线程唤醒后并执行时,是接着上次执行到的wait()方法代码后面继续往下执行的。

  7. 继承派生题
    class Base {
    public void method()
    {
    System.out.println("Base");
    }
    }
    class Son extends Base {
    public void method()
    {
    System.out.println("Son");
    }
    public void methodB()
    {
    System.out.println("SonB");
    }
    }
    public class Test01 {
    public static void main(String[] args)
    {
    Base base = new Son();
    base.method();
    base.methodB();
    }
    }

    输出结果为:编译通不过!!!
    因为:
    Base base=new Son(); 是多态的表示形式。父类对象调用了子类创建了Son对象。
    base调用的method()方法就是调用了子类重写的method()方法。
    而此时base还是属于Base对象,base调用methodB()时Base对象里没有这个方法,所以编译不通过。
    要想调用的话需要先通过SON son=(SON)base;强制转换,然后用son.methodB()调用就可以了。

  8. Servlet中的Service
    Java基础回顾——重难点易错点【1】
    service()是在javax.servlet.Servlet接口中定义的, 在 javax.servlet.GenericServlet 中实现了这个接口。 而 doGet/doPost 则是在 javax.servlet.http.HttpServlet 中实现的, javax.servlet.http.HttpServlet 是 javax.servlet.GenericServlet 的子类。
    所以可以这样理解, 其实所有的请求均首先由 service() 进行处理, 而在 javax.servlet.http.HttpServlet 的 service() 方法中, 主要做的事情就是判断请求类型是 Get 还是 Post, 然后调用对应的 doGet/doPost 执行。

  9. Statement接口下的结构
    Java基础回顾——重难点易错点【1】

  10. final、finally和finalize 区别
    (1).final
    如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在new一个对象时初始化(即只能在声明变量或构造器或代码块内初始化),而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能覆盖(重写)。
    (2).finally
    在异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。
    (3).finalize
    方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。注意:finalize不一定被jvm调用,只有当垃圾回收器要清除垃圾时才被调用。