aoot examination
1. 接口和抽象类的区别
- 接口是对动作的抽象(这个对象能做什么),抽象类是对根源的抽象(这个对象是什么)。
- 两者都不能直接实例化,对接口实例化时,接口变量必须指向一个类对象(此类对象必须实现了所有的接口方法);对抽象类实例化时,抽象类变量必须指向一个子类对象(此子类对象必须实现了所有的抽象方法)。注:如果方法不能全部被类 A 实现,那么类 A 必然是抽象类。
- 接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
- 抽象方法要被实现,所以不能是静态的,也不能是私有的。
2. 嵌套类,内部类的概念
- 嵌套类:一个类的内部定义另一个类,就是嵌套类。分为静态(使用较少)和非静态两种。
- 内部类:指非静态嵌套类。分为成员内部类、静态嵌套类、方法内部类、匿名内部类。
注:对于静态嵌套类,因为其中的所有成员和方法都默认是静态的,所以无法访问外部类中的非静态成员,由此静态嵌套类使用受限。
3. javadoc 标签哪些是类前面的,哪些是方法前面了?
- 类注释的标签有:author、version、
- 方法注释的标签有:param、return、throws、exception
- 通用:see 引用、since 描述文本(支持哪个 jdk 版本)、deprecated、link(链接文档用)
4. 防御性编程:
- 目的:打造高质量的模块。
- 设计系统的每个组件,让其尽可能的保护自己。
- 预见在什么地方可能出现问题,然后创建一个环境来测试错误,当预见的问题出现的时候通知你,并执行一个你指定的损害控制动作。
5. overload 和 override 深刻理解
- override,重写。子类对父类的允许访问的方法的实现过程进行重新编写,外壳完全不变,核心重写。
- 不能抛出比原方法更宽泛的异常。原来抛 IOException,重写后只能抛 IOException 或其子类。
- final 方法不能被重写。
- static 方法不能被重写,但可以被重新声明。
- 构造方法不能被重写。
- overload,重载。一个类中,方法名字相同,而参数不同,返回类型可同可不同。
- 必须改变参数列表;
- 访问修饰符可以改变;
- 可以声明更广的检查异常;
- 无法以返回值类型作为重载函数的区分标准。
6. Java 中哪些类型有兼容性,哪些类型没有兼容性?
“小”的数据类型可以直接赋给“大”的数据类型。
“大”的不能赋值给“小”的数据类型(会出现编译错误)
- 整数类:long > int > short > byte
- 浮点型:double > float
- 整型数据类型可以赋给浮点数据类型
- char 可以赋给 long 和 int ,但是不能赋给 short 和 byte (编译错误) 。
- char 可以赋给float和double
- 当整数型常量在 0~65535 之间时,可以被赋值给 char 型变量
- char 型常量可以被赋值给整数类变量,只要整数变量的类型可以容纳 char 型文字常量所表示的数值。
- 浮点型常量默认为 double 型,而 double 型常量不能赋值给 float 型变量。
- boolean 与其他数据类型没有兼容性。
7. float 和 double 为什么不能用等号等号来比较。怎么比较?
计算机表示浮点数( float 或 double 类型)都有一个精度限制,对于超出了精度限制的浮点数,计算机会把它们的精度之外的小数部分截断。因此,本来不相等的两个浮点数在计算机中可能就变成相等的了
- 设置误差精度
- 转换成字符串后使用 equals 方法比较,需要精度很高
- 转换成 Long 后使用
==
比较(即使用Double.doubleToLongBits()
) - 使用 BigDecimal 类型的 equals 方法或 compareTo 方法
8. volatile 和 synchronize 的区别?
分别是什么:
- volatile是一个变量修饰符,而synchronized是一个方法或块的修饰符。
- 一个声明为 volatile 类型的变量将在所有的线程中同步的获得数据,不论你在任何线程中更改了变量,其他的线程将立即得到同样的结果。所以 volatile 类型变量在性能上有所消耗。
- 是在告诉 jvm 当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取(事实上并不确切)。
- 很多Java程序员认为volatile是让CPU直接访问主存来避免visibility问题, 这是错误的观点。其实Java里面volatile就是放了一个full memory fence(理解:强制将L1、L2刷入线程间的缓存,即多线程可见)等待 write buffer flush 到缓存系统处理结束。参考分布式系统一致性的发展历史(一)中的解释。
- synchronized 获取和释放由监听器控制的锁,如果两个线程都使用一个监听器(即相同对象锁),那么监听器可以强制在一个时刻只有一个线程能处理代码块,这是最一般的同步。另外,synchronized 还能使内存同步。在实际当中,synchronized 使得所有的线程内存与主内存相同步。
- 本质是:锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住
- volatile 只能在线程内存和主内存之间同步一个(或多个,限于写 volatile 变量之前所有对共享变量的值的改变)变量的值,而 synchronized 则同步在线程内存和主内存之间的所有变量的值,并且通过锁住和释放监听器来实现。
区别:
- volatile 是线程同步的轻量级实现,所以 volatile 的性能要比 synchronize 好;但 synchronize 的执行效率也不差;
- 多线程访问 volatile 不会发生阻塞;而 synchronize 会发生阻塞;
- volatile 能保证变量在私有内存和主内存间的同步,但不能保证变量的原子性;synchronize 可以保证变量原子性;
- volatile 是变量在多线程之间的可见性;synchronize 是多线程之间访问资源的同步性;
- volatile 标记的变量不会被编译器优化;synchronized 标记的变量可以被编译器优化。
对于 volatile 修饰的变量,可以解决变量读时可见性问题,无法保证原子性。对于多线程访问同一个实例变量还是需要加锁同步。
9. mvn/git/Junit 的命令。
1 | mvn compile |
10. maven 的目录结构
1 | src - main - java |
11. Java 的 IO 体系
推荐阅读:Java IO 体系
字节流
InputStream、OutputStream:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27读取文本
psvm(){
FileInputStream fis = new FileInputStream("likehui.txt"); // try-catch Exception
int n = fis.read();
sysout((char)n); // print 文本中第一个字符,比如“H”
fis.close();
}
// 复制图片
psvm(){
try {
FileInputStream fis = new FileInputStream("src/main/resources/happy.png");
FileOutputStream fos = new FileOutputStream("src/main/resources/happy3.png");
int n = 0;
byte[] b = new byte[1024];
while((n = fis.read(b))!= -1){
fos.write(b,0,n);
}
fis.close();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}字符流
1
略略略
序列化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27// 其中 Goods 类实现了 Serializable接口
psvm(){
Goods gd001 = new Goods("gd001",0.2);
try {
FileOutputStream fos = new FileOutputStream("src/main/resources/imooc.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
FileInputStream fis = new FileInputStream("src/main/resources/imooc.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
oos.writeObject(gd001);
oos.writeBoolean(true);
oos.flush();
Goods goods = (Goods) ois.readObject();
System.out.println(goods);
System.out.println(ois.readBoolean());
fos.close();
oos.close();
fis.close();
ois.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
12. decorate pattern
装饰模式动态的将责任附加到对象上,若要扩展功能,装饰模式提供了比继承更有弹性的替代方案
13. runtimeException 受检异常
必须捕获或抛出:checkedException
允许忽略:不可查的 RuntimeException(含子类)和 Error(含子类)
- 非检查异常,就是指编译器不要求强制处理的异常。一般指 RuntimeException 及其子类。
- 检查异常,就是编译器要求强制处理的异常。一般有:IO 异常、SQL 异常
- RuntimeException 的子类:
- NullPointerException;
- ArrayIndexOutOfBoundsException;
- ArithmeticException;
- ClassCastException。
14. equals hashcode 怎么实现的
实现 equals 的方法:
- Use == to see if argument is a reference to this (optimization)
- Use instanceof to check if argument is of the correct type (properly handles null)
- Cast the argument to the correct type
- Check each “significant” field
- Check reflexivity, symmetry, transitivity
1 |
|
实现 hashCode 的方法:
- 取一个非 0 的 int 作为初始值,比如 42,保存在 result 中。
- 计算你所关心的域(在 equals 起作用的)的 hashCode。如何生成属性的 hashCode 我们等一下再说,先假设生成的 hashCode 为 c。
- 组合所有的域,result = 31 * result + c。
1 | public class TestClass { |