![[计算机软件及应用]java面试宝典精心整理国内顶级IT公司面试题.pdf_第1页](http://file.renrendoc.com/FileRoot1/2019-12/23/b94261b2-8e26-470a-8a48-cd894e67c716/b94261b2-8e26-470a-8a48-cd894e67c7161.gif)
![[计算机软件及应用]java面试宝典精心整理国内顶级IT公司面试题.pdf_第2页](http://file.renrendoc.com/FileRoot1/2019-12/23/b94261b2-8e26-470a-8a48-cd894e67c716/b94261b2-8e26-470a-8a48-cd894e67c7162.gif)
![[计算机软件及应用]java面试宝典精心整理国内顶级IT公司面试题.pdf_第3页](http://file.renrendoc.com/FileRoot1/2019-12/23/b94261b2-8e26-470a-8a48-cd894e67c716/b94261b2-8e26-470a-8a48-cd894e67c7163.gif)
![[计算机软件及应用]java面试宝典精心整理国内顶级IT公司面试题.pdf_第4页](http://file.renrendoc.com/FileRoot1/2019-12/23/b94261b2-8e26-470a-8a48-cd894e67c716/b94261b2-8e26-470a-8a48-cd894e67c7164.gif)
![[计算机软件及应用]java面试宝典精心整理国内顶级IT公司面试题.pdf_第5页](http://file.renrendoc.com/FileRoot1/2019-12/23/b94261b2-8e26-470a-8a48-cd894e67c716/b94261b2-8e26-470a-8a48-cd894e67c7165.gif)
已阅读5页,还剩93页未读, 继续免费阅读
[计算机软件及应用]java面试宝典精心整理国内顶级IT公司面试题.pdf.pdf 免费下载
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
目录目录 jdk1 5 新增的功能 3 字符流和字节流的区别 使用场景 相关类 5 线程安全的概念 实现线程安全的几种方法 10 抽象类和接口的区别 使用场景 16 hash 算法的实现原理 hashcode 的实现原理 21 error 和 exception 的区别 runtimeexception 和非 runtimeexception 的区别 24 继承与组合的区别 使用场景 27 组合关系的分解过程对应继承关系的抽象过程 28 使用静态工厂方法的好处和坏处 31 排序算法 他们是时间复杂度是多少 33 数据库设计原则 范式 36 数据库常用的编码方式有哪几种 41 如果有 10 万条学生成绩信息 怎么获取成绩最高的那一条数据 怎么获取成绩第三的 那一条数据 列举你认为性能最好的方式 41 序列化的作用 应用场景 除了网路传输 41 spring 的 ioc aop 的使用场景 49 spring 简单而强大 49 相关厂商内容 49 相关赞助商 49 简化企业应用程序 50 底层的技术 aspectj和spring aop简介 50 spring 2 0中新的aop支持 52 采用路线图 55 使用开箱即用的spring方面 57 简化web 服务和数据访问层 59 用开发时间方面提升生产力 64 简化 基础结构 需求的实现 69 简化领域模型 71 小结 72 ajax 是否能跨域请求 解决的办法 73 解析 xml 的几种方法 他们的原理 76 怎么样实现高性能的代码 77 如果有和其他系统有接口调用 但其他系统还没开发完成 怎么进行单元测试 77 防止重复提交有哪几种方式 网上很多 可以 google 下 82 怎么样运用样式设计一个 div 浮出层 82 数据库连接池的实现原理 请求怎么样去获取连接 关闭连接时 连接池是销毁连接 还是回收连接 82 tomcat weblogic jboss 的区别 容器的作用 86 apache 是容器么 它的作用是什么 92 内部跳转和外部跳转的区别 底层实现原理 93 http 和 https 的区别 96 宕机的原因有哪几种 怎么样分析宕机的原因 如 数据库的长连接 97 在 velocity 页面 为什么不推荐不推荐使用宏定义 97 webx 的核心原理 webx 框架和 velocity 的优缺点 97 页面上如果有一个 screen 和两个 control 那么他们有几个 context 98 一个含有 layout screen 和 control 的页面 他们的加载顺序是什么 是等所有的加载 完一起显示 还是其他 98 if a true 会出问题么 为什么 98 支付宝怎么样保证他的安全 他的调用异常分哪几种 98 项目中你觉得做得最好的是什么 98 jdk1 5 新增的功能新增的功能 jdk1 5 的一个重要主题就是通过新增一些特性来简化开发 这些特性包括泛型 for each 循环 自动装包 拆包 枚举 可变参数 静态导入 使用这些特性有助于我们编写更加清晰 精悍 安全的代码 下面我们简单介绍一下这些新特性 1 泛型 generic c 通过模板技术可以指定集合的元素类型 而 java 在 1 5 之前一直没有相对应的功能 一个 集合可以放任何类型的对象 相应地从集合里面拿对象的时候我们也不得不对他们进行强制得类 型转换 猛虎引入了泛型 它允许指定集合里元素的类型 这样你可以得到强类型在编译时刻进 行类型检查的好处 collection c new arraylist c add new date 编译器会给出一个错误 add java lang string in java util collection cannot be applied to java util date 2 for each 循环 for each循环得加入简化了集合的遍历 假设我们要遍历一个集合对其中的元素进行一些处理 典型的代码为 void processall collection c for iterator i c iterator i hasnext myclass myobject myclass i next myobject process 使用 for each 循环 我们可以把代码改写成 void processall collection c for myclass myobject c myobject process 这段代码要比上面清晰许多 并且避免了强制类型转换 3 自动装包 拆包 autoboxing unboxing 自动装包 拆包大大方便了基本类型数据和它们包装类地使用 自动装包 基本类型自动转为包装类 int integer 自动拆包 包装类自动转为基本类型 integer int 在 jdk1 5 之前 我们总是对集合不能存放基本类型而耿耿于怀 现在自动转换机制解决了我们 的问题 int a 3 collection c new arraylist c add a 自动转换成 integer integer b new integer 2 c add b 2 这里 integer 先自动转换为 int 进行加法运算 然后 int 再次转换为 integer 4 枚举 enums jdk1 5 加入了一个全新类型的 类 枚举类型 为此 jdk1 5 引入了一个新关键字 enmu 我们 可以这样来定义一个枚举类型 public enum color red white blue 然后可以这样来使用 color mycolor color red 枚举类型还提供了两个有用的静态方法values 和valueof 我们可以很方便地使用它们 例如 for color c color values system out println c 5 可变参数 varargs 可变参数使程序员可以声明一个接受可变数目参数的方法 注意 可变参数必须是函数声明中的 最后一个参数 假设我们要写一个简单的方法打印一些对象 util write obj1 util write obj1 obj2 util write obj1 obj2 obj3 在 jdk1 5 之前 我们可以用重载来实现 但是这样就需要写很多的重载函数 显得不是很有效 如果使用可变参数的话我们只需要一个函数就行了 public void write object objs for object obj objs system out println obj 在引入可变参数以后 java 的反射包也更加方便使用了 对于 c getmethod test new object 0 invoke c newinstance new object 0 现在我们可以这样写了 c getmethod test invoke c newinstance 这样的代码比原来清楚了 很多 6 静态导入 static imports 要使用用静态成员 方法和变量 我们必须给出提供这个方法的类 使用静态导入可以使被导入 类的所有静态变量和静态方法在当前类直接可见 使用这些静态成员无需再给出他们的类名 import static java lang math r sin pi 2 无需再写 r math sin math pi 不过 过度使用这个特性也会一定程度上降低代码地可读性 字符流和字节流的区别 使用场景 相关类字符流和字节流的区别 使用场景 相关类 java 流在处理上分为字符流和字节流 字符流处理的单元为 2 个字节的 unicode 字符 分别 操作字符 字符数组或字符串 而字节流处理单元为 1 个字节 操作字节和字节数组 java 内用 unicode 编码存储字符 字符流处理类负责将外部的其他编码的字符流和 java 内 unicode 字符流之间的转换 而类 inputstreamreader 和 outputstreamwriter 处理字符流和 字节流的转换 字符流 一次可以处理一个缓冲区 一次操作比字节流 一次一个字节 效率高 一一 以字节为导向的以字节为导向的 stream inputstream outputstream inputstream 和 outputstream 是两个 abstact 类 对于字节为导向的 stream 都扩展这两 个鸡肋 基类 1 inputstream 1 1 bytearrayinputstream 把内存中的一个缓冲区作为 inputstream 使用 construct a bytearrayinputstream byte 创建一个新字节数组输入流 bytearrayinputstream 它 从指定字节数组中读取数据 使用 byte 作为其缓冲区数组 b bytearrayinputstream byte int int 创建一个新字节数组输入流 它从指定字节数组中 读取数据 mark 该字节数组未被复制 1 2 stringbufferinputstream 把一个 string 对象作为 inputstream construct stringbufferinputstream string 据指定串创建一个读取数据的输入流串 注释 不推荐使用 stringbufferinputstream 方法 此类不能将字符正确的转换为字节 同 jdk 1 1 版中的类似 从一个串创建一个流的最佳方法是采用 stringreader 类 1 3 fileinputstream 把一个文件作为 inputstream 实现对文件的读取操作 construct a fileinputstream file name 创建一个输入文件流 从指定的 file 对象读取数据 b fileinputstream filedescriptor 创建一个输入文件流 从指定的文件描述器读取数据 c fileinputstream string name 创建一个输入文件流 从指定名称的文件读取数据 method read 从当前输入流中读取一字节数据 read byte 将当前输入流中 b length 个字节数据读到一个字节数组中 read byte int int 将输入流中 len 个字节数据读入一个字节数组中 1 4 pipedinputstream 实现了 pipe 的概念 主要在线程中使用 管道输入流是指一个通讯管 道的接收端 一个线程通过管道输出流发送数据 而另一个线程通过管道输入流读取数据 这样可实现两 个线程间的通讯 construct pipedinputstream 创建一个管道输入流 它还未与一个管道输出流连接 pipedinputstream pipedoutputstream 创建一个管道输入流 它已连接到一个管道输出流 1 5 sequenceinputstream 把多个 inputstream 合并为一个 inputstream 序列输入流 类允许 应用程序把几个输入流连续地合并起来 并且使它们像单个输入流一样出现 每个输入流依次被读取 直到到达该流的末尾 然后 序列输入流 类关闭这个流并自动地切换到下一个输入流 construct sequenceinputstream enumeration 创建一个新的序列输入流 并用指定的输入流的枚举值 初始化它 sequenceinputstream inputstream inputstream 创建一个新的序列输入流 初始化为首先 读输入流 s1 然后读输入流 s2 2 outputsteam 2 1 bytearrayoutputstream 把信息存入内存中的一个缓冲区中 该类实现一个以字节数组形 式写入数据的输出流 当数据写入缓冲区时 它自动扩大 用 tobytearray 和 tostring 能检索数据 constructor a bytearrayoutputstream 创建一个新的字节数组输出流 b bytearrayoutputstream 创建一个新的字节数组输出流 c bytearrayoutputstream int 创建一个新的字节数组输出流 并带有指定大小字节的缓 冲区容量 tostring string 根据指定字符编码将缓冲区内容转换为字符串 并将字节转换为字符 write byte int int 将指定字节数组中从偏移量 off 开始的 len 个字节写入该字节数组输 出流 write int 将指定字节写入该字节数组输出流 writeto outputstream 用 out write buf 0 count 调用输出流的写方法将该字节数组输出流 的全部内容写入指定的输出流参数 2 2 fileoutputstream 文件输出流是向 file 或 filedescriptor 输出数据的一个输出流 constructor a fileoutputstream file name 创建一个文件输出流 向指定的 file 对象输出数据 b fileoutputstream filedescriptor 创建一个文件输出流 向指定的文件描述器输出数据 c fileoutputstream string name 创建一个文件输出流 向指定名称的文件输出数据 d fileoutputstream string boolean 用指定系统的文件名 创建一个输出文件 2 3 pipedoutputstream 管道输出流是指一个通讯管道的发送端 一个线程通过管道输出流发 送数据 而另一个线程通过管道输入流读取数据 这样可实现两个线程间的通讯 constructor a pipedoutputstream 创建一个管道输出流 它还未与一个管道输入流连接 b pipedoutputstream pipedinputstream 创建一个管道输出流 它已连接到一个管道输入流 二二 以字符为导向的以字符为导向的 stream reader writer 以 unicode 字符为导向的 stream 表示以 unicode 字符为单位从 stream 中读取或往 stream 中写入信息 reader writer 为 abstact 类 以 unicode 字符为导向的 stream 包括下面几种类型 1 reader 1 1 chararrayreader 与 bytearrayinputstream 对应此类实现一个可用作字符输入流的字符 缓冲区 constructor chararrayreader char 用指定字符数组创建一个 chararrayreader chararrayreader char int int 用指定字符数组创建一个 chararrayreader 1 2 stringreader 与 stringbufferinputstream 对应其源为一个字符串的字符流 stringreader string 创建一新的串读取者 1 3 filereader 与 fileinputstream 对应 1 4 pipedreader 与 pipedinputstream 对应 2 writer 2 1 chararraywrite 与 bytearrayoutputstream 对应 2 2 stringwrite 无与之对应的以字节为导向的 stream 2 3 filewrite 与 fileoutputstream 对应 2 4 pipedwrite 与 pipedoutputstream 对应 3 两种不同导向的 stream 之间的转换 3 1 inputstreamreader 和 outputstreamreader 把一个以字节为导向的 stream 转换成一个以字符为导向的 stream inputstreamreader 类是从字节流到字符流的桥梁 它读入字节 并根据指定的编码方式 将之转换为字符流 使用的编码方式可能由名称指定 或平台可接受的缺省编码方式 inputstreamreader 的 read 方法之一的每次调用 可能促使从基本字节输入流中读取一个 或多个字节 为了达到更高效率 考虑用 bufferedreader 封装 inputstreamreader bufferedreader in new bufferedreader new inputstreamreader system in 例如 实现从键盘输入一个整数 java view plaincopy string s null inputstreamreader re new inputstreamreader system in bufferedreader br new bufferedreader re try s br readline system out println s integer parseint s br close catch ioexception e e printstacktrace catch numberformatexception e 当应用程序试图将字符串转换成一种数值类型 但该字符串不能转换为适当 格式时 抛出该异常 system out println 输入的不是数字 inputstreamreader inputstream 用缺省的字符编码方式 创建一个 inputstreamreader inputstreamreader inputstream string 用 已 命 名 的 字 符 编 码 方 式 创 建 一 个 inputstreamreader outputstreamwriter 将多个字符写入到一个输出流 根据指定的字符编码将多个字符转换为 字节 每个 outputstreamwriter 合并它自己的 chartobyteconverter 因而是从字符流到字节流的 桥梁 三 三 java io 的一般使用原则的一般使用原则 一 按数据来源 去向 分类 1 是文件 fileinputstream fileoutputstream 字节流 filereader filewriter 字符 2 是 byte bytearrayinputstream bytearrayoutputstream 字节流 3 是 char chararrayreader chararraywriter 字符流 4 是 string stringbufferinputstream stringbufferouputstream 字节流 stringreader stringwriter 字符流 5 网络数据流 inputstream outputstream 字节流 reader writer 字符流 二 按是否格式化输出分 1 要格式化输出 printstream printwriter 三 按是否要缓冲分 1 要缓冲 bufferedinputstream bufferedoutputstream 字节流 bufferedreader bufferedwriter 字符流 四 按数据格式分 1 二进制格式 只要不能确定是纯文本的 inputstream outputstream 及其所有带 stream 结束的子类 2 纯文本格式 含纯英文与汉字或其他编码方式 reader writer 及其所有带 reader writer 的子类 五 按输入输出分 1 输入 reader inputstream 类型的子类 2 输出 writer outputstream 类型的子类 六 特殊需要 1 从 stream 到 reader writer 的转换类 inputstreamreader outputstreamwriter 2 对象输入输出 objectinputstream objectoutputstream 3 进程间通信 pipeinputstream pipeoutputstream pipereader pipewriter 4 合并输入 sequenceinputstream 5 更 特 殊 的 需 要 pushbackinputstream pushbackreader linenumberinputstream linenumberreader 决定使用哪个类以及它的构造进程的一般准则如下 不考虑特殊需要 首先 考虑最原始的数据格式是什么 原则四 第二 是输入还是输出 原则五 第三 是否需要转换流 原则六第 1 点 第四 数据来源 去向 是什么 原则一 第五 是否要缓冲 原则三 特别注明 一定要注意的是 readline 是否有定义 有什么 比 read write 更特殊的输入或输出方法 第六 是否要格式化输出 原则二 线程安全的概念 实现线程安全的几种方法线程安全的概念 实现线程安全的几种方法 java 编程语言为编写多线程应用程序提供强大的语言支持 但是 编写有用的 没有错误 的多线程程序仍然比较困难 本文试图概述几种方法 程序员可用这几种方法来创建高效的 线程安全类 并发性并发性 只有当要解决的问题需要一定程度的并发性时 程序员才会从多线程应用程序中受益 例如 如果打印队 列应用程序仅支持一台打印机和一台客户机 则不应该将它编写为多线程的 一般说来 包含并发性的编 码问题通常都包含一些可以并发执行的操作 同时也包含一些不可并发执行的操作 例如 为多个客户机 和一个打印机提供服务的打印队列可以支持对打印的并发请求 但向打印机的输出必须是串行形式的 多 线程实现还可以改善交互式应用程序的响应时间 回页首回页首 synchronized 关键字关键字 虽然多线程应用程序中的大多数操作都可以并行进行 但也有某些操作 如更新全局标志或处理共享文件 不能并行进行 在这些情况下 必须获得一个锁来防止其他线程在执行此操作的线程完成之前访问同一个 方法 在 java 程序中 这个锁是通过 synchronized关键字提供的 清单 1 说明了它的用法 清单清单 1 使用使用 synchronized 关键字来获取锁关键字来获取锁 public class maxscore int max public maxscore max 0 public synchronized void currentscore int s if s max max s public int max return max 这里 两个线程不能同时调用 currentscore 方法 当一个线程工作时 另一个线程必须阻塞 但是 可 以有任意数量的线程同时通过 max 方法访问最大值 因为 max 不是同步方法 因此它与锁定无关 试考虑在 maxscore 类中添加另一个方法的影响 该方法的实现如清单 2 所示 清单清单 2 添加另一个方法添加另一个方法 public synchronized void reset max 0 这个方法 当被访问时 不仅将阻塞 reset 方法的其他调用 而且也将阻塞 maxscore 类的同一个实例 中的 currentscore 方法 因为这两个方法都访问同一个锁 如果两个方法必须不彼此阻塞 则程序员必 须在更低的级别使用同步 清单 3 是另一种情况 其中两个同步的方法可能需要彼此独立 清单清单 3 两个独立的同步方法两个独立的同步方法 import java util public class jury vector members vector alternates public jury members new vector 12 1 alternates new vector 12 1 public synchronized void addmember string name members add name public synchronized void addalt string name alternates add name public synchronized vector all vector retval new vector members retval addall alternates return retval 此处 两个不同的线程可以将 members 和 alternates 添加到 jury 对象中 请记 住 synchronized 关键字既可用于方法 更一般地 也可用于任何代码块 清单 4 中的两段代 码是等效的 清单清单 4 等效的代码等效的代码 synchronized void f void f 执行某些操作 synchronized this 执行某些操作 所以 为了确保 addmember 和 addalt 方法不彼此阻塞 可按清单 5 所示重写 jury 类 清单清单 5 重写后的重写后的 jury 类类 import java util public class jury vector members vector alternates public jury members new vector 12 1 alternates new vector 12 1 public void addmember string name synchronized members members add name public void addalt string name synchronized alternates alternates add name public vector all vector retval synchronized members retval new vector members synchronized alternates retval addall alternates return retval 请注意 我们还必须修改 all 方法 因为对 jury 对象同步已没有意义 在改写后的版本中 addmember addalt 和 all 方法只访问与 members 和 alternates 对象相关的锁 因此锁定 jury 对象毫无用处 另请注意 all 方法本来可以写为清单 6 所示的形式 清单清单 6 将将 members 和和 alternates 用作同步的对象用作同步的对象 public vector all synchronized members synchronized alternates vector retval retval new vector members retval addall alternates return retval 但是 因为我们早在需要之前就获得 members 和 alternates 的锁 所以这效率不高 清单 5 中的改写 形式是一个较好的示例 因为它只在最短的时间内持有锁 并且每次只获得一个锁 这样就完全避免了当 以后增加代码时可能产生的潜在死锁问题 回页首回页首 同步方法的分解同步方法的分解 正如在前面看到的那样 同步方法获取对象的一个锁 如果该方法由不同的线程频繁调用 则此方法将成 为瓶颈 因为它会对并行性造成限制 从而会对效率造成限制 这样 作为一个一般的原则 应该尽可能 地少用同步方法 尽管有这个原则 但有时一个方法可能需要完成需要锁定一个对象几项任务 同时还要 完成相当耗时的其他任务 在这些情况下 可使用一个动态的 锁定 释放 锁定 释放 方法 例如 清单 7 和 清单 8 显示了可按这种方式变换的代码 清单清单 7 最初的低效率代码最初的低效率代码 public synchonized void dowork unsafe1 write file unsafe2 清单清单 8 重写后效率较高的代码重写后效率较高的代码 public void dowork synchonized this unsafe1 write file synchonized this unsafe2 清单 7 和清单 8 假定第一个和第三个方法需要对象被锁定 而更耗时的 write file 方法不需要对象被 锁定 如您所见 重写此方法以后 对此对象的锁在第一个方法完成以后被释放 然后在第三个方法需要 时重新获得 这样 当 write file 方法执行时 等待此对象的锁的任何其他方法仍然可以运行 将同步方 法分解为这种混合代码可以明显改善性能 但是 您需要注意不要在这种代码中引入逻辑错误 回页首回页首 嵌套类嵌套类 内部类在 java 程序中实现了一个令人关注的概念 它允许将整个类嵌套在另一个类中 嵌套类作为包含 它的类的一个成员变量 如果定期被调用的的一个特定方法需要一个类 就可以构造一个嵌套类 此嵌套 类的唯一任务就是定期调用所需的方法 这消除了对程序的其他部分的相依性 并使代码进一步模块化 清单 9 一个图形时钟的基础 使用了内部类 清单清单 9 图形时钟图形时钟示例示例 public class clock protected class refresher extends thread int refreshtime public refresher int x super refresher refreshtime x public void run while true try sleep refreshtime catch exception e repaint public clock refresher r new refresher 1000 r start private void repaint 获取时间的系统调用 重绘时钟指针 清单 9 中的代码示例不靠任何其他代码来调用 repaint 方法 这样 将一个时钟并入一个较大的用户界 面就相当简单 回页首回页首 事件驱动处理事件驱动处理 当应用程序需要对事件或条件 内部的和外部的 作出反映时 有两种方法或用来设计系统 在第一种方 法 称为轮询 中 系统定期确定这一状态并据此作出反映 这种方法 虽然简单 也效率不高 因为您 始终无法预知何时需要调用它 第二种方法 称为事件驱动处理 效率较高 但实现起来也较为复杂 在事件驱动处理的情况下 需要一 种发信机制来控制某一特定线程何时应该运行 在 java 程序中 您可以使用 wait notify 和 notifyall 方法向线程发送信号 这些方法允许线程在一个对象上阻塞 直到所需的条件得到满足为止 然后再次开 始运行 这种设计减少了 cpu 占用 因为线程在阻塞时不消耗执行时间 并且可在 notify 方法被调用 时立即唤醒 与轮询相比 事件驱动方法可以提供更短的响应时间 回页首回页首 创建高效的线程安全类的步骤创建高效的线程安全类的步骤 编写线程安全类的最简单的方法是用 synchronized 声明每个方法 虽然这种方案可以消除数据损坏 但 它同时也会消除您预期从多线程获得的任何收益 这样 您就需要分析并确保在 synchronized 块内部仅 占用最少的执行时间 您必须格外关注访问缓慢资源 文件 目录 网络套接字和数据库 的方法 这些方法可能降低您的程序的效率 尽量将对这类资源的访问放在一个单独的线程中 最好在任何 synchronized 代码之外 一个线程安全类的示例 被设计为要处理的文件的中心储存库 它与使用 getwork 和 finishwork 与 worktable 类对接的一组线程一起工作 本例旨在让您体验一下全功能的线程安全类 该类使用了 helper 线程和混合同步 请注意继续添加要处理的新文件的 refresher helper 线程的用法 本例没有调整 到最佳性能 很明显有许多地方可以改写以改善性能 比如将 refresher 线程改为使用 wait notify 方 法事件驱动的 改写 populatetable 方法以减少列出磁盘上的文件 这是高成本的操作 所产生的影响 回页首回页首 小结小结 通过使用可用的全部语言支持 java 程序中的多线程编程相当简单 但是 使线程安全类具有较高的效率 仍然比较困难 为了改善性能 您必须事先考虑并谨慎使用锁定功能 抽象类和接口的区别 使用场景抽象类和接口的区别 使用场景 在 java 语言中 abstract class 和 interface 是支持抽象类定义的两种机制 正是由于这两种 机制的存在 才赋予了 java 强大的 面向对象能力 abstract class 和 interface 之间在对于抽 象类定义的支持方面具有很大的相似性 甚至可以相互替换 因此很多开发者在进 行抽象 类定义时对于 abstract class 和 interface 的选择显得比较随意 其实 两者之间还是有很大的 区别的 对于它们的选择甚至反映出对 于问题领域本质的理解 对于设计意图的理解是否 正确 合理 本文将对它们之间的区别进行一番剖析 试图给开发者提供一个在二者之间进 行选择的依据 理解抽象类 abstract class 和 interface 在 java 语言中都是用来进行抽象类 本文 中的抽象类并非从 abstract class 翻译而来 它表示的是一个抽象体 而 abstract class 为 java 语言中用于定义抽 象类的一种方法 请读者注意区分 定义的 那么什么是抽象类 使用抽象类能为我们带 来什么好处呢 在 面向对象的概念中 我们知道所有的对象都是通过类来描绘的 但是反过来却不是 这样 并不是 所有的类都是用来描绘对象的 如果一个类中没有包含足够的信息来描绘一 个具体的对象 这样的类就是抽象类 抽象类往往用来表征我们在对问题领域进行分析 设 计中得出的抽象概念 是对一系列看上去不同 但是本质上相同的具体概念的抽象 比如 如果我们进行一个图形编辑软件的开发 就会发现问题领域存在着圆 三角形这样一些具 体概念 它们是不同的 但是它们又都属于形状这样一个概念 形状这个概念在问题领域是 不存在的 它就是一个抽象概念 正是因为抽象的概念 在问题领域没有对应的具体概念 所以用以表征抽象概念的抽象类是不能够实例化的 在面向对象领域 抽象类主要用来进行类型隐藏 我们可以构造出一个固定的一组行 为的抽象描 述 但是这组行为却能够有任意个可能的具体实现方式 这个抽象描述就是抽 象类 而这一组任意个可能的具体实现则表现为所有可能的派生类 模块可以操作一个 抽 象体 由于模块依赖于一个固定的抽象体 因此它可以是不允许修改的 同时 通过从这个 抽象体派生 也可扩展此模块的行为功能 熟悉 ocp 的读者一定知 道 为了能够实现面向 对象设计的一个最核心的原则 ocp open closed principle 抽象类是其中的关键所在 从语法定义层面看 abstract class 和 interface 在语法层面 java 语言对于 abstract class 和 interface 给出了不同的定义方式 下面以定 义一个名为 demo 的抽象类为例来说明这种不同 使用 abstract class 的方式定义 demo 抽象类的方式如下 abstract class demo abstract void method1 abstract void method2 使用 interface 的方式定义 demo 抽象类的方式如下 interface demo void method1 void method2 在 abstract class 方式中 demo 可以有自己的数据成员 也可以有非 abstract 的成员方 法 而在 interface 方式的实现中 demo 只能够有静态的不能被修改的数据成员 也就是必 须是 static final 的 不过在 interface 中一般不定义数据成员 所有的成员方法都是 abstract 的 从某种意义上说 interface 是一种特殊形式的 abstract class 从编程的角度来看 abstract class 和 interface 都可以用来实现 design by contract 的思 想 但是在具体的使用上面还是有一些区别的 首先 abstract class 在 java 语言中表示的是一种继承关系 一个类只能使用一次继承 关系 因为 java 不支持多继承 转注 但是 一个类却可以实现多个 interface 也许 这 是 java 语言的设计者在考虑 java 对于多重继承的支持方面的一种折中考虑吧 其次 在 abstract class 的定义中 我们可以赋予方法的默认行为 但是在 interface 的定 义中 方法却不能拥有默认行为 为了绕过这个限制 必须使用委托 但是这会增加一些复 杂性 有时会造成很大的麻烦 在 抽象类中不能定义默认行为还存在另一个比较严重的问题 那就是可能会造成维护 上的麻烦 因 为如果后来想修改类的界面 一般通过 abstract class 或者 interface 来表示 以适应新的情况 比如 添加新的方法或者给已用的方法中添 加新的参数 时 就会非常 的麻烦 可能要花费很多的时间 对于派生类很多的情况 尤为如此 但是如果界面是通 过 abstract class 来实现的 那 么可能就只需要修改定义在 abstract class 中的默认行为就可 以了 同样 如果不能在抽象类中定义默认行为 就会导致同样的方法实现出现在该抽象类的 每一个派生类中 违反了 one rule one place 原则 造成代码重复 同样不利于以后的 维护 因此 在 abstract class 和 interface 间进行选择时要非常的小心 从设计理念层面看 abstract class 和 interface 上面主要从语法定义和编程的角度论述了 abstract class 和 interface 的区 别 这些层面 的区别是比较低层次的 非本质的 本小节将从另一个层面 abstract class 和 interface 所反 映出的设计理念 来分析一下二者的区别 作者认为 从这个层面进行分析才能理解二者概 念的本质所在 前面已经提到过 abstract class 在 java 语言中体现了一种继承关系 要想使得 继承关 系合理 父类和派生类之间必须存在 is a 关系 即父类和派生类在概念本质上应该是相同 的 对于 interface 来说则不然 并不要求 interface 的实现者和 interface 定义在概念本质上 是一致的 仅仅是实现了 interface 定义的契约而已 为了使论述便于理解 下面将通过一 个简单的实例进行说明 考虑这样一个例子 假设在我们的问题领域中有一个关于 door 的抽象概念 该 door 具有执行两个动作 open 和 close 此时我们可以通过 abstract class 或者 interface 来定义一个 表示该抽象概念的类型 定义方式分别如下所示 使用 abstract class 方式定义 door abstract class door abstract void open abstract void close 使用 interface 方式定义 door interface door void open void close 其他具体的 door 类型可以 extends 使用 abstract class 方式定义的 door 或者 implements 使用 interface 方式定义的 door 看起来好像使用 abstract class 和 interface 没有大的区别 如果现在要求 door 还要具有报警的功能 我们该如何设计针对该例子的类结构呢 在 本例中 主要是为了展示 abstract class 和 interface 反映在设计理念上的区别 其他方面 无关的问题都做了简化或者忽略 下面将罗列出可能的解 决方案 并从设计理念层面对 这些不同的方案进行分析 解决方案一 简单的在 door 的定义中增加一个 alarm 方法 如下 abstract class door abstract void open abstract void close abstract void alarm 或者 interface door void open void close void alarm 那么具有报警功能的 alarmdoor 的定义方式如下 class alarmdoor extends door void open void close void alarm 或者 class alarmdoor implements door void open void close void alarm 这种方法违反了面向对象设计中的一个核心原则 isp interface segregation principle 在 door 的定义中把 door 概念本身固有的行为方法和另外一个概念 报警器 的行为方 法混在 了一起 这样引起的一个问题是那些仅仅依赖于 door 这个概念的模块会因为 报警器 这个 概念的改变 比如 修改 alarm 方法的参数 而改变 反 之依然 解决方案二 既然 open close 和 alarm 属于两个不同的概念 根据 isp 原则应该把它们分别定 义在 代表这两个概念的抽象类中 定义方式有 这两个概念都使用 abstract class 方式定义 两 个概念都使用 interface 方式定义 一个概念 使用 abstract class 方式定义 另一个概念使用 interface 方式定义 显然 由于 java 语言不支持多重继承 所以两个概念都使用 abstract class 方式定义是 不可行的 后面两种方式都是可行的 但是对于它们的选择却反映出对于问题领域中的概念 本质的理解 对于设计意图的反映是否正确 合理 我们一一来分析 说明 如果两个概念都使用 interface 方式来定义 那么就反映出两个问题 1 我们可能没有 理解清楚问题领域 alarmdoor 在概念本质上到底是 door 还是报警器 2 如果我们对于问 题领域的理解没有问题 比如 我们通过对于问题领域的分 析发现 alarmdoor 在概念本质 上和 door 是一致的 那么我们在实现时就没有能够正确的揭示我们的设计意图 因为在这 两个概念的定义上 均使用 interface 方式定义 反映不出上述含义 如果我们对于问题领域的理解是 alarmdoor 在概念本质上是 door 同时它有具有报 警 的功能 我们该如何来设计 实现来明确的反映出我们的意思呢 前面已经说过 abstract class 在 java 语言中表示一种继承关系 而继承关系 在本质上是 is a 关系 所以对于 door 这个概念 我们应该使用 abstarct class 方式来定义 另外 alarmdoor 又具有报警功能 说 明它又能够完成报警概念中定义的行为 所以报警概念可以通过 in
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 工业触电安全知识培训课件
- 子宫输卵管逆流课件
- 子宫肌瘤合并妊娠课件
- 工业燃气操作安全培训课件
- 年度供应链安全培训课件
- 工业机器人安全课件
- 威海网络安全培训课件
- 威海摩托安全培训课件
- 年前案场安全培训记录课件
- 年初安全大排查培训课件
- 高血压个案护理案例
- 四川省三级综合医院评审标准实施细则(2023年版)
- 心肺复苏术课件2024新版
- Unit 1 Lesson1 Hello!教学设计 2024-2025学年冀教版英语七年级上册
- 2024年省食品生产监管能力大比武理论备赛试题库(含答案)
- 黑布林阅读初一5《大卫和超级神探》中文版
- 2025届高三化学一轮复习策略讲座
- 50000t天污水厂课程设计
- GB/T 44251-2024腿式机器人性能及试验方法
- 人音版 (五线谱)一年级上册音乐-1 《玩具兵进行曲》教案
- 医药产业园区智慧园区系统建设方案
评论
0/150
提交评论