JAVA面试总结

1.sleep()和wait():

  Java中的多线程是一种抢占式的机制,而不是分时机制。抢占式的机制是有多个线程处于可运行状态,但是只有一个线程在运行。 
  ● 共同点: 
   (1) 他们都是在多线程的环境下,都可以在程序的调用处阻塞指定的毫秒数,并返回。 
   (2) wait()和sleep()都可以通过interrupt()方法 打断线程的暂停状态 ,从而使线程立刻抛出InterruptedException。 
       如果线程A希望立即结束线程B,则可以对线程B对应的Thread实例调用interrupt方法。如果此刻线程B正在wait/sleep/join,则线程B会立刻抛出InterruptedException,在catch() {} 中直接return即可安全地结束线程。 
      需要注意的是,InterruptedException是线程自己从内部抛出的,并不是interrupt()方法抛出的。对某一线程调用 interrupt()时,如果该线程正在执行普通的代码,那么该线程根本就不会抛出InterruptedException。但是,一旦该线程进入到 wait()/sleep()/join()后,就会立刻抛出InterruptedException 。 
   ● 不同点: 
   (1) 每个对象都有一个锁来控制同步访问。Synchronized关键字可以和对象的锁交互,来实现线程的同步。 
      sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。 
   (2) wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用 
   (3) sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常 
   (4) sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
   (5) wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。

2.截止JDK1.8版本,java并发框架支持锁包括:

  1) 自旋锁, 自旋,jvm默认是10次吧,有jvm自己控制。for去争取锁.
  2) 阻塞锁 被阻塞的线程,不会争夺锁.
  3) 可重入锁 多次进入改锁的域.
  4) 读写锁.
  5) 互斥锁 锁本身就是互斥的.
  6) 悲观锁 不相信,这里会是安全的,必须全部上锁.
  7) 乐观锁 相信,这里是安全的.
  8) 公平锁 有优先级的锁.
  9) 非公平锁 无优先级的锁.
  10) 偏向锁 无竞争不锁,有竞争挂起,转为轻量锁.
  11) 对象锁 锁住对象.
  12) 线程锁.
  13) 锁粗化 多锁变成一个,自己处理.
  14) 轻量级锁 CAS实现.
  15) 锁消除 偏向锁就是锁消除的一种.
  16) 锁膨胀 jvm实现,锁粗化.
  17) 信号量 使用阻塞锁 实现的一种策略.
  18) 排它锁:X锁,若事务T对数据对象A加上X锁,则只允许T读取和修改A,其他任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。这就保证了其他事务在T释放A上的锁之前不能再读取和修改A。

3.结构型模式:

   结构型模式是描述如何将类对象结合在一起,形成一个更大的结构,结构模式描述两种不同的东西:类与类的实例。故可以分为类结构模式和对象结构模式。
   在GoF设计模式中,结构型模式有:
  1) 适配器模式 Adapter
  适配器模式是将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
  两个成熟的类需要通信,但是接口不同,由于开闭原则,我们不能去修改这两个类的接口,所以就需要一个适配器来完成衔接过程。
  2) 桥接模式 Bridge
  桥接模式将抽象部分与它的实现部分分离,是它们都可以独立地变化。它很好的支持了开闭原则和组合锯和复用原则。实现系统可能有多角度分类,每一种分类都有可能变化,那么就把这些多角度分离出来让他们独立变化,减少他们之间的耦合。
  3) 组合模式 Composite
  组合模式将对象组合成树形结构以表示部分-整体的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。
  4) 装饰模式 Decorator
   装饰模式动态地给一个对象添加一些额外的职责,就增加功能来说,它比生成子类更灵活。也可以这样说,装饰模式把复杂类中的核心职责和装饰功能区分开了,这样既简化了复杂类,有去除了相关类中重复的装饰逻辑。 装饰模式没有通过继承原有类来扩展功能,但却达到了一样的目的,而且比继承更加灵活,所以可以说装饰模式是继承关系的一种替代方案
  5) 外观模式 Facade
  外观模式为子系统中的一组接口提供了同意的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
  外观模式中,客户对各个具体的子系统是不了解的,所以对这些子系统进行了封装,对外只提供了用户所明白的单一而简单的接口,用户直接使用这个接口就可以完成操作,而不用去理睬具体的过程,而且子系统的变化不会影响到用户,这样就做到了信息隐蔽。
  6) 享元模式 Flyweight
  享元模式为运用共享技术有效的支持大量细粒度的对象。因为它可以通过共享大幅度地减少单个实例的数目,避免了大量非常相似类的开销。
  享元模式是一个类别的多个对象共享这个类别的一个对象,而不是各自再实例化各自的对象。这样就达到了节省内存的目的。
  7) 代理模式 Proxy 
  为其他对象提供一种代理,并由代理对象控制对原对象的引用,以间接控制对原对象的访问。

4.Statement、PreparedStatement和CallableStatement的异同:  

    1) Statement继承自Wrapper、PreparedStatement继承自Statement、CallableStatement继承自PreparedStatement

    2) Statement接口提供了执行语句和获取结果的基本方法; 
        PreparedStatement接口添加了处理 IN 参数的方法; 
        CallableStatement接口添加了处理 OUT 参数的方法。 
    3) a.Statement: 普通的不带参的查询SQL; 支持批量更新, 批量删除; 
        b.PreparedStatement: 可变参数的SQL, 编译一次, 执行多次, 效率高
           安全性好,有效防止Sql注入等问题; 
           支持批量更新, 批量删除; 
        c.CallableStatement: 继承自PreparedStatement, 支持带参数的SQL操作
           支持调用存储过程, 提供了对输出和输入/输出参数(INOUT)的支持; 
         Statement每次执行sql语句,数据库都要执行sql语句的编译, 最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement。
    4) PreparedStatement预编译的,使用PreparedStatement有几个好处:: 

      (1) 在执行可变参数的一条SQL时,PreparedStatement比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率要高。 
      (2) 安全性好,有效防止Sql注入等问题。 
      (3) 对于多次重复执行的语句,使用PreparedStament效率会更高一点,并且在这种情况下也比较适合使用batch; 
      (4) 代码的可读性和可维护性。

5.对于JVM内存配置参数:

-Xmx10240m -Xms10240m -Xmn5120m -XXSurvivorRatio=3

   其最小内存值和Survivor区总大小分别是(10240m,2048m).

   -Xmx:最大堆大小.
   -Xms:初始堆大小.
   -Xmn : 年轻代大小.
   -XXSurvivorRatio:年轻代中Eden区与Survivor区的大小比值.
   -Xms初始堆大小即最小内存值, 为10240m.
    XXSurvivorRatio=3,即Eden:FromSurvivor:ToSurvivor=3:1:1;所以Survivor一共是2048m.

 6.类加载过程:

     类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)7个阶段。其中准备、验证、解析3个部分统称为连接(Linking)。如图所示:

     

    这里写图片描述:

    加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班地开始,而解析阶段则不一定:它在某些情况下可以在初始化阶段之后再开始,这是为了支持Java语言的运行时绑定(也称为动态绑定或晚期绑定)。以下陈述的内容都已HotSpot为基准。

    ● 加载

    在加载阶段(可以参考java.lang.ClassLoader的loadClass()方法),虚拟机需要完成以下3件事情:

   1) 通过一个类的全限定名来获取定义此类的二进制字节流(并没有指明要从一个Class文件中获取,可以从其他渠道,譬如:网络、动态生成、数据库等);
   2) 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;
   3) 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口;
   加载阶段和连接阶段(Linking)的部分内容(如一部分字节码文件格式验证动作)是交叉进行的,加载阶段尚未完成,连接阶段可能已经开始,但这些夹在加载阶段之中进行的动作,仍然属于连接阶段的内容,这两个阶段的开始时间仍然保持着固定的先后顺序。

    ● 验证

    验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
    验证阶段大致会完成4个阶段的检验动作:

     1) 文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以魔术0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。
     2) 元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object之外。
     3) 字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。
     4) 符号引用验证:确保解析动作能正确执行。
    验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采用-Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

    ● 准备

    准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。这时候进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在堆中。其次,这里所说的初始值“通常情况”下是数据类型的零值,假设一个类变量的定义为:

public static int value=123;

    那变量value在准备阶段过后的初始值为0而不是123. 因为这时候尚未开始执行任何java方法,而把value赋值为123的putstatic指令是程序被编译后,存放于类构造器()方法之中,所以把value赋值为123的动作将在初始化阶段才会执行。
    至于“特殊情况”是指:public static final int value=123,即当类字段的字段属性是ConstantValue时,会在准备阶段初始化为指定的值,所以标注为final之后,value的值在准备阶段初始化为123而非0.

    ● 解析

    解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。

    ● 初始化

     类初始化阶段是类加载过程的最后一步,到了初始化阶段,才真正开始执行类中定义的java程序代码。在准备极端,变量已经付过一次系统要求的初始值,而在初始化阶段,则根据程序猿通过程序制定的主管计划去初始化类变量和其他资源,或者说:初始化阶段是执行类构造器<clinit>()方法的过程.
   <clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块static{}中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问。如下:

复制代码

public class Test
{
    static
    {
        i=0;
        System.out.println(i);//这句编译器会报错:Cannot reference a field before it is defined(非法向前应用)
    }
    static int i=1;
}

复制代码

    更多介绍,请移步:http://blog.csdn.net/u013256816/article/details/50829596

7.JVM内存:

     大多数 JVM 将内存区域划分为: Method Area(Non-Heap)(方法区),  Heap(堆) Program Counter Register(程序计数器),  VM Stack(虚拟机栈,也有翻译成JAVA 方法栈的), Native Method Stack ( 本地方法栈 ),其中Method Area 和Heap 是线程共享的 ,VM StackNative Method Stack 和Program Counter Register 是非线程共享的。

     为什么分为线程共享和非线程共享的呢?

    首先我们熟悉一下一个一般性的 Java 程序的工作过程。一个 Java 源程序文件,会被编译为字节码文件(以 class 为扩展名),每个java程序都需要运行在自己的JVM上,然后告知 JVM 程序的运行入口,再被 JVM 通过字节码解释器加载运行。

     那么程序开始运行后,都是如何涉及到各内存区域的呢?
     概括地说来,JVM初始运行的时候都会分配好 Method Area(方法区) 和Heap(堆) ,而JVM 每遇到一个线程,就为其分配一个 Program Counter Register(程序计数器) , VM Stack(虚拟机栈)和Native Method Stack (本地方法栈), 当线程终止时,三者(虚拟机栈,本地方法栈和程序计数器)所占用的内存空间也会被释放掉。这也是为什么我把内存区域分为线程共享和非线程共享的原因,非线程共享的那三个区域的生命周期与所属线程相同,而线程共享的区域与JAVA程序运行的生命周期相同,所以这也是系统垃圾回收的场所只发生在线程共享的区域(实际上对大部分虚拟机来说知发生在Heap上)的原因。

    方法区在JVM中也是一个非常重要的区域,它与一样,是被线程共享的区域。 在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。

    程序计数器是Java虚拟机中唯一一个没有规定任何内存溢出OutOfMemoryError的内存区域,Java虚拟机中的程序计数器指向正在执行的字节码地址,而不是下一条。

8.Java垃圾回收算法:

   两个最基本的Java垃圾回收算法:复制算法和标记清理算法。

   复制算法:两个区域A和B,初始对象在A,继续存活的对象被转移到B。此为新生代最常用的算法。
   标记清理:一块区域,标记要回收的对象,然后回收,一定会出现碎片,那么引出:标记-整理算法:多了碎片整理,整理出更大的内存放更大的对象。
   两个概念:新生代和年老代。
      新生代:初始对象,生命周期短的。
      永久代:长时间存在的对象。
   整个java的垃圾回收是新生代和年老代的协作,这种叫做分代回收。
   P.S:Serial New收集器是针对新生代的收集器,采用的是复制算法。
           Parallel New(并行)收集器,新生代采用复制算法,老年代采用标记整理。
           Parallel Scavenge(并行)收集器,针对新生代,采用复制收集算法。
           Serial Old(串行)收集器,新生代采用复制,老年代采用标记清理。
           Parallel Old(并行)收集器,针对老年代,标记整理。
           CMS收集器,基于标记清理。
           G1收集器:整体上是基于标记清理,局部采用复制。
   综上:新生代基本采用复制算法,老年代采用标记整理算法。cms采用标记清理

9.重写(Overriding)和重载(Overloading):

    重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。

    如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。

    如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。

    Overloaded的方法是可以改变返回值的类型。

10.优化Hibernate所鼓励的7大措施:

   1) 尽量使用many-to-one,避免使用单项one-to-many;
   2) 灵活使用单向one-to-many;
   3) 不用一对一,使用多对一代替一对一;
   4) 配置对象缓存,不使用集合缓存;
   5) 一对多使用Bag 多对一使用Set;
   6) 继承使用显示多态 HQL:from object polymorphism="exlicit" 避免查出所有对象;
   7) 消除大表,使用二级缓存。

11.构造方法(构造器):

   构造方法是一种特殊的方法,具有以下特点。
    (1) 构造方法的方法名必须与类名相同
    (2) 构造方法没有返回类型,也不能定义为void,在方法名前面不声明方法类型。
    (3) 构造方法的主要作用是完成对象的初始化工作,它能够把定义对象时的参数传给对象的域。
    (4) 一个类可以定义多个构造方法,如果在定义类时没有定义构造方法,则编译系统会自动插入一个无参数的默认构造器,这个构造器不执行任何代码。
    (5) 构造方法可以重载,以参数的个数,类型,顺序

12.J2EE中常用的名词解释:

   (1) Web容器:给处于其中的应用程序组件(JSP,SERVLET)提供一个环境,使JSP, SERVLET直接和容器中的环境变量接接口互,不必关注其它系统问题。主要有WEB服务器来实现。例如:TOMCAT,WEBLOGIC,WEBSPHERE等。该容器提供的接口严格遵守J2EE规范中的WEB APPLICATION 标准。我们把遵守以上标准的WEB服务器就叫做J2EE中的WEB容器。
   (2) EJB容器:Enterprise java bean 容器。更具有行业领域特色。他提供给运行在其中的组件EJB各种管理功能。只要满足J2EE规范的EJB放入该容器,马上就会被容器进行高效率的管理。并且可以通过现成的接口来获得系统级别的服务。例如邮件服务、事务管理。一个实现了J2EE体系结构中EJB组件规范的容器。 这个规范指定了一个Enterprise bean的运行时环境,包括安全,一致性,生命周期,事务, 配置,和其他的服务。
   (3) JNDI:(Java Naming & Directory Interface)JAVA命名目录服务。主要提供的功能是:提供一个目录系统,让其它各地的应用程序在其上面留下自己的索引,从而满足快速查找和定位分布式应用程序的功能。
   (4) JMS:(Java Message Service)JAVA消息服务。主要实现各个应用程序之间的通讯。包括点对点和广播。
   (5) JTA:(Java Transaction API)JAVA事务服务。提供各种分布式事务服务。应用程序只需调用其提供的接口即可。
   (6) JAF:(Java Action FrameWork)JAVA安全认证框架。提供一些安全控制方面的框架。让开发者通过各种部署和自定义实现自己的个性安全控制策略。
   (7) RMI/IIOP:(Remote Method Invocation /internet对象请求中介协议)他们主要用于通过远程调用服务。例如,远程有一台计算机上运行一个程序,它提供股票分析服务,我们可以在本地计算机上实现对其直接调用。当然这是要通过一定的规范才能在异构的系统之间进行通信。RMI是JAVA特有的。RMI-IIOP出现以前,只有RMI和CORBA两种选择来进行分布式程序设计。RMI-IIOP综合了RMI和CORBA的优点,克服了他们的缺点,使得程序员能更方便的编写分布式程序设计,实现分布式计算。首先,RMI-IIOP综合了RMI的简单性和CORBA的多语言性(兼容性),其次RMI-IIOP克服了RMI只能用于Java的缺点和CORBA的复杂性(可以不用掌握IDL)。

13.Linux链接:

    Linux链接分两种,一种被称为硬链接(Hard Link),另一种被称为符号链接(Symbolic Link)。默认情况下,ln命令产生硬链接。
    ● 硬连接
    硬连接指通过索引节点来进行连接。在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号(Inode Index)。在Linux中,多个文件名指向同一索引节点是存在的。一般这种连接就是硬连接。硬连接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬连接到重要文件,以防止“误删”的功能。其原因如上所述,因为对应该目录的索引节点有一个以上的连接。只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬连接文件均被删除。
    ● 软连接
    另外一种连接称之为符号连接(Symbolic Link),也叫软连接。软链接文件有类似于Windows的快捷方式。它实际上是一个特殊的文件。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息

14.会话跟踪技术:   

    有四种方法可以实现会话跟踪技术:URL重写、隐藏表单域、Cookie、Session。
    (1) 隐藏表单域: <input type="hidden">,非常适合步需要大量数据存储的会话应用。
    (2) URL 重写: URL 可以在后面附加参数,和服务器的请求一起发送,这些参数为名字/值对。
    (3) Cookie: 一个 Cookie 是一个小的, 已命名数据元素。服务器使用 SET-Cookie 头标将它作为 HTTP响应的一部分传送到客户端,客户端被请求保存 Cookie 值,在对同一服务器的后续请求使用一个Cookie 头标将之返回到服务器。与其它技术比较,Cookie 的一个优点是在浏览器会话结束后,甚至在客户端计算机重启后它仍可以保留其值。
    (4) Session: 使用 setAttribute(String str,Object obj)方法将对象捆绑到一个会话。

15.HashTable和HashMap区别:

    (1) 继承不同Hashtable继承自Dictionary, HashMap继承自AbstractMap

public class Hashtable extends Dictionary implements Map
public class HashMap extends AbstractMap implements Map

    (2) Hashtable 中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。
    (3) Hashtable中,key和value都不允许出现null值
    在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。
    (4) 两个遍历方式的内部实现上不同
     Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。
    (5) 哈希值的使用不同HashTable直接使用对象的hashCode。而HashMap重新计算hash值
    (6) Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数

16.reflection是如何工作的:

   (1) public Method[] getDeclaredMethods()返回类或接口声明的所有方法,包括public, protected, default (package) 访问和private方法的Method对象,但不包括继承的方法。当然也包括它所实现接口的方法。

   (2) public Method[] getMethods()返回某个类的所有public方法,包括其继承类的公用方法,当然也包括它所实现接口的方法。

17.SpringMVC的原理:

     SpringMVC是Spring中的模块,它实现了mvc设计模式的web框架,首先用户发出请求,请求到达SpringMVC的前端控制器DispatcherServlet), 前端控制器根据用户的url请求处理器映射器查找匹配该url的handler,并返回一个执行链,前端控制器再请求处理器适配器调用相应的handler进行处理并返回给前端控制器一个modelAndView,前端控制器再请求视图解析器对返回的逻辑视图进行解析,最后前端控制器将返回的视图进行渲染并把数据装入到request域,返回给用户。
     DispatcherServlet是前端控制器设计模式的实现,提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得Spring的所有好处。
    DispatcherServlet主要用作职责调度工作,本身主要用于控制流程,主要职责如下:
     (1) 文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;
     (2) 通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);
     (3) 通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);
     (4) 通过ViewResolver解析逻辑视图名到具体视图实现
     (5) 本地化解析
     (6) 渲染具体的视图等;
     (7) 如果执行过程中遇到异常将交给HandlerExceptionResolver来解析

18.抽象类与接口的区别:

     接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final。另外,接口和抽象类在方法上有区别: 

     (1) 抽象类可以有构造方法,接口中不能有构造方法。 
     (2) 抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。Java 8里的接口可以有default方法。
     (3) 抽象类中可以普通成员变量,接口中没有普通成员变量
     (4) 抽象类中的抽象方法的访问类型可以是public,protected和默认类型
     (5) 抽象类中可以包含静态方法,接口中不能包含静态方法。
     (6) 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能public static final类型,并且默认即为public static final类型。
     (7) 一个类可以实现多个接口,但只能继承一个抽象类。二者在应用方面也有一定的区别:接口更多的是在系统架构设计方法发挥作用,主要用于定义模块之间的通信契约。而抽象类在代码实现方面发挥作用,可以实现代码的重用,例如,模板方法设计模式是抽象类的一个典型应用,假设某个项目的所有Servlet类都要用相同的方式进行权限判断、记录访问日志和处理异常,那么就可以定义一个抽象的基类,让所有的Servlet都继承这个抽象基类,在抽象基类的service方法中完成权限判断、记录访问日志和处理异常的代码,在各个子类中只是完成各自的业务逻辑代码。

19.JDK中的包和他们的基本功能:

    (1) java.awt: 包含构成抽象窗口工具集的多个类,用来构建和管理应用程序的图形用户界面,主要用于编写GUI程序,包括按钮、标签等常用组件以及相应的事件类。
    (2) java.lang: 提供java编成语言的程序设计的基础类,是一个核心包,系统自动将这个包引入到用户程序,该包中主要的类:object类,它是所有类的父类,其中定义的方法其它类都可以使用。数据类型包装类,数学类,字符串类,系统和运行时类,操作类,线程类,错误和异常处理类,过程类。System提供一个独立于具体计算机资源的编程界面,Runtime类可用于直接访问运行时资源。
    (3) java.io:包含提供多种输出输入功能的类。
    (4) java.net:包含执行与网络有关的类,如URL,SCOKET,SEVERSOCKET。
    (5) java.applet: 包含java小应用程序的类。
    (6) java.util:包含一些实用性的类,实用包提供了各种实用功能的类,主要包括日期类、数据结构类和随机数类等。

20.Java常用关键字功能:

    (1) final关键字可用于修饰类、变量和方法。final修饰的类不能被继承,final修饰的方法不能被重写,final修饰的变量不可被修改,一旦获得初始值,该变量就不能被重新赋值。
    (2) public:访问控制修饰符,用于修饰类、类的方法、属性或者构造器。
    (3) abstract:用于修饰抽象类或者抽象方法
    (4) static:用于修饰类、方法或者成员变量,表明该类是静态类或者方法、成员变量属于当前类

21.volatile关键字:

   一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
   (1) 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
   (2) 禁止进行指令重排序。
       volatile只提供了保证访问该变量时,每次都是从内存中读取最新值,并不会使用寄存器缓存该值—每次都会从内存中读取。
       而对该变量的修改,volatile并不提供原子性的保证
       由于及时更新,很可能导致另一线程访问最新变量值,无法跳出循环的情况, 多线程下计数器必须使用锁保护

22.super和this关键字:

    (1) 调用super()必须写在子类构造方法的第一行,否则编译不通过。每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。
    (2) super()和this()类似, 区别是: super从子类中调用父类的构造方法,this()在同一类内调用其它方法。
    (3) super()和this()均需放在构造方法内第一行
    (4) 尽管可以用this调用一个构造器,但却不能调用两个
    (5) this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
    (6) this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量, static方法,static语句块。
    (7) 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字

23.OuterClass类:

    1) 为什么使用内部类?
    使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
    使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,使用内部类还能够为我们带来如下特性:
      (1) 内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独。
      (2) 在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
      (3) 创建内部类对象的时刻并不依赖于外围类对象的创建。
      (4) 内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
      (5) 内部类提供了更好的封装,除了该外围类,其他类都不能访问。
    2) 内部类分类:
    (一) 成员内部类:
     (1) Inner 类定义在 Outer 类的内部,相当于 Outer 类的一个成员变量的位置,Inner 类可以使用任意访问控制符,如 public 、 protected 、 private 等。
     (2) Inner 类中定义的 show() 方法可以直接访问 Outer 类中的数据,而不受访问控制符的影响,如直接访问 Outer 类中的私有属性age。
     (3) 定义了成员内部类后,必须使用外部类对象来创建内部类对象,而不能直接去 new 一个内部类对象,即:内部类 对象名 = 外部类对象.new 内部类( );
     (4) 编译上面的程序后,会发现产生了两个.class 文件: Outer.class,Outer$Inner.class{}。
     (5) 成员内部类中不能存在任何static 的变量和方法, 可以定义常量:
        ● 因为非静态内部类是要依赖于外部类的实例,而静态变量和方法是不依赖于对象的,仅与类相关, 简而言之:在加载静态域时,根本没有外部类,所在在非静态内部类中不能定义静态域或方法,编译不通过; 非静态内部类的作用域是实例级别。
        ● 常量是在编译器就确定的, 放到所谓的常量池了。
    ★ 外部类是不能直接使用内部类的成员和方法的,可先创建内部类的对象,然后通过内部类的对象来访问其成员变量和方法;
    ★ 如果外部类和内部类具有相同的成员变量或方法,内部类默认访问自己的成员变量或方法,如果要访问外部类的成员变量,可以使用 this 关键字,如:Outer.this.name。
   (二) 静态内部类: 是 static 修饰的内部类
    (1) 静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问 
    (2) 如果外部类的静态成员与内部类的成员名称相同,可通过“类名.静态成员”访问外部类的静态成员;如果外部类的静态成员与内部类的成员名称不相同,则可通过“成员名”直接调用外部类的静态成员。
    (3) 创建静态内部类的对象时,不需要外部类的对象,可以直接创建 内部类 对象名 = new 内部类()。
   (三) 方法内部类:访问仅限于方法内或者该作用域内
    (1) 局部内部类就像是方法里面的一个局部变量一样,是不能有 public、protected、private 以及 static 修饰符的。
    (2) 只能访问方法中定义的 final 类型的局部变量, 因为: 当方法被调用运行完毕之后,局部变量就已消亡了。但内部类对象可能还存在, 直到没有被引用时才会消亡。此时就会出现一种情况,就是内部类要访问一个不存在的局部变量; 使用final修饰符不仅会保持对象的引用不会改变,而且编译器还会持续维护这个对象在回调方法中的生命周期. 局部内部类并不是直接调用方法传进来的参数,而是内部类将传进来的参数通过自己的构造器备份到了自己的内部,自己内部的方法调用的实际是自己的属性而不是外部类方法的参数; 防止被篡改数据,而导致内部类得到的值不一致。在内部类中的属性和外部方法的参数两者从外表上看是同一个东西,但实际上却不是,所以他们两者是可以任意变化的,也就是说在内部类中我对属性的改变并不会影响到外部的形参,而然这从程序员的角度来看这是不可行的,毕竟站在程序的角度来看这两个根本就是同一个,如果内部类该变了,而外部方法的形参却没有改变,这是难以理解和不可接受的,所以为了保持参数的一致性,就规定使用 final来避免形参的不改变。
   (四) 匿名内部类:
    (1) 匿名内部类是直接使用 new 来生成一个对象的引用;
    (2) 对于匿名内部类的使用它是存在一个缺陷的,就是它仅能被使用一次,创建匿名内部类时它会立即创建一个该类的实例,该类的定义会立即消失,所以匿名内部类是不能够被重复使用;
    (3) 使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口;
    (4) 匿名内部类中是不能定义构造函数的,匿名内部类中不能存在任何的静态成员变量和静态方法;
    (5) 匿名内部类中不能存在任何的静态成员变量和静态方法,匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法;
    (6) 匿名内部类初始化:使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果。

24.Spring的事务传播特性:

    PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 
    PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。 
    PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。 
    PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。 
    PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 
    PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常

25.Servlet的生命周期:

    Servlet的生命周期分为5个阶段:加载创建初始化处理客户请求卸载
    (1) 加载:容器通过类加载器使用servlet类对应的文件加载servlet。
    (2) 创建:通过调用servlet构造函数创建一个servlet对象。
    (3) 初始化:调用init方法初始化。
    (4) 处理客户请求:每当有一个客户请求,容器会创建一个线程来处理客户请求。
    (5) 卸载:调用destroy方法让servlet自己释放其占用的资源。

26.Java反射机制:

    Java反射机制概念:Java反射机制是在运行状态中,对于任意一个,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
    Java反射机制主要提供了以下功能: 
     (1) 在运行时判断任意一个对象所属的类
     (2) 在运行时构造任意一个类的对象
     (3) 在运行时判断任意一个类所具有的成员变量和方法
     (4) 在运行时调用任意一个对象的方法
     (5) 生成动态代理

27.Struts:

    Struts的工作流程: 在web应用启动时就会加载初始化ActionServlet, ActionServlet从struts-config.xml文件中读取配置信息, 把它们存放到各种配置对象, 当ActionServlet接收到一个客户请求时, 将执行如下流程. 
    (1) 检索和用户请求匹配的ActionMapping实例, 如果不存在, 就返回请求路径无效信息; 
    (2) 如果ActionForm实例不存在, 就创建一个ActionForm对象, 把客户提交的表单数据保存到ActionForm对象中; 
    (3) 根据配置信息决定是否需要表单验证. 如果需要验证, 就调用ActionForm的validate()方法; 
    (4) 如果ActionForm的validate()方法返回或返回一个不包含ActionMessage的ActuibErrors对象, 就表示表单验证成功; 
    (5) ActionServlet根据ActionMapping所包含的映射信息决定将请求转发给哪个Action, 如果相应的Action实例不存在, 就先创建这个实例, 然后调用Action的execute()方法; 
    (6) Action的execute()方法返回一个ActionForward对象, ActionServlet在把客户请求转发给ActionForward对象指向的JSP组件; 
    (7) ActionForward对象指向JSP组件生成动态网页, 返回给客户; 
   为什么要用Struts? 
    JSP、Servlet、JavaBean技术的出现给我们构建强大的企业应用系统提供了可能。但用这些技术构建的系统非常的繁乱,所以在此之上,我们需要一个规则、一个把这些技术组织起来的规则,这就是框架,Struts便应运而生。 基于Struts开发的应用由3类组件构成:控制器组件、模型组件、视图组件(MVC)。

28.堆(heap)栈(stack)的区别?

   1) JAVA的JVM的内存:

    堆区: 
    (1) 存储的全部是对象, 每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令) .
    (2) jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身.
   栈区: 
    (1) 每个线程包含一个栈区,栈中只保存基础数据类型的对象自定义对象的引用(不是对象),对象都存放在堆区中.
    (2) 每个栈中的数据(原始类型和对象引用)都是私有的, 其他栈不能访问. 
    (3) 栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令).

   2) 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆, 程序员不能直接地设置栈或堆。 
   3) 栈的优势是, 存取速度比堆要快, 仅次于直接位于CPU中的寄存器。但缺点是, 存在栈中的数据大小与生存期必须是确定的, 缺乏灵活性。另外, 栈数据可以共享。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢

   4) 在C语言里堆(heap)和栈(stack)里的区别:

     heap:是由malloc之类函数分配的空间所在地。地址是由低向高增长的。 
     stack:是自动分配变量,以及函数调用的时候所使用的一些空间。地址是由高向低减少。 

    (1) 管理方式不同:栈(stack)由编译器管理;堆(heap)由程序员管理。 
    (2) 空间大小不同:win32中,堆(heap)可达4G;VC中栈默认1M(可以修改)。 
    (3) 碎片问题:堆(heap)易产生;栈(stack)不会。 
    (4) 生长方向不同:堆(heap)生长方向是向上的,也就是向着内存增加的方向;栈(stack)相反。 
    (5) 分配方式不同:堆(heap)是动态的,没有静态的堆;栈(stack)有两种:动态和静态。 
    (6) 分配效率不同:栈(stack),系统提供底层支持,有专门的寄存器存放栈地址,效率高;堆(heap),由库函数提供支持,效率底。

展开阅读全文

没有更多推荐了,返回首页