Java中的异常处理
异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性的处理异常,让程序进最大可能恢复正常
并继续执行,且保持代码的清晰。
Throwable类是Java异常类型的顶层父类,一个对象只有是Throwable类的实例,他才是一个异常对象,才能被异常处理机制识别。
Throwable派生出Error类和Exception类。
Error类以及他的子类的实例,代表了JVM本身的错误。错误不能被程序员通过代码处理,Error很少出现。
异常的类型
- 非检查异常:Error和RuntimeException以及他们的子类;
- 检查异常:除了Error和RuntimeException的其他异常。
异常的处理 - 程序员对有可能出现的异常使用try catch处理;
- 函数里并不处理异常,使用throw or throws关键字把可能出现的异常抛给调用该函数的上级函数处理;
- 交给JVM虚拟机处理。
Object类常见方法
- Object()
- clone()
- equals(Object)
- finalize()
- getClass()
- hashCode()
- notify()
- notifyAll()
- toString()
- wait()
- wait(long)
- wait(long,int)
final关键字
final用于修饰类,成员变量和成员方法;
final修饰的类,不能被继承(String,StringBuilder,StringBuffer,Math,不可变类),其中所有的方法都不能被重写,所以不能同时用abstract和final修饰类;
final修饰的方法不能被重写,但是子类可以用父类中的final修饰的方法;
final修饰的成员变量是不可变的,如果成员变量是基本数据类型,初始化之后成员变量的值不能被改变,如果成员变量是引用类型,那么它只能指向初始化时指向的那个对象,不能再指向别的对象,但是对象当中的内容是允许改变的。
优点
- final方法比非final方法快一些,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定;
- final关键字提高了性能,JVM和Java应用都会缓存final变量;
- final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销;
- 使用final关键字,JVM会对方法,变量及类进行优化。
四种引用类型
只有强引用FinalReference类是包内可见,其他三种引用类型均有public,可以在应用程序中直接使用。
- 强引用(StrongReference)
强引用时使用最普遍的引用,如果一个对象具有强引用,那么垃圾回收器绝对不会回收它,当内存空间不足时, Java虚拟机宁愿抛出OutOfMemoryError也不愿意回收具有强引用的对象来解决内存不足的问题; - 软引用(SoftReference)
如果一个对象只具有软引用,则内存空间足够,垃圾回收器便不会回收它,如果内存空间不足,那么垃圾回收器 就会回收这些对象的内存,只要垃圾回收器没有回收它,该对象就可以被对象使用。软引用可以用于实现内存 敏感的高速缓存; - 弱引用(WeakReference)
只具有弱引用的对象的生命周期更短,垃圾回收器一旦发现就只有弱引用的对象,不管当前内存是否足够, 都会将其回收,但是垃圾回收器是一个优先级很低的线程,不一定很快的发现那些只有弱引用的对象,弱引用 可用于解决内存泄漏的问题; - 虚引用
虚引用与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收,虚引用主要用来跟踪对象被垃圾回收器回收的活动。 虚引用必须和引用队列联合使用。垃圾回收器回收对象时,该对象还有虚引用,就会在回收对象的内存之前,把这个 虚引用加入到与之关联的引用队列中。
接口和抽象类的区别
接口的设计目的,是对类的行为进行约束(更准确的说是一种“有”约束,因为接口不能规定类不可以有什么行为),也就是提供一种机制,可以强制要求不同的类具有相同的行为。它只约束了行为的有无,但不对如何实现行为进行限制。对“接口为何是约束”的理解,我觉得配合泛型使用更好理解。
抽象类的设计目的,是代码复用。当不同的类具有某些相同的行为(记为行为集合A),且其中一部分行为的实现方式一致时(A的非真子集,记为B),可以让这些类都派生于一个抽象类。在这个抽象类中实现了B,避免让所有的子类来实现B,这就达到了代码复用的目的。而A减B的部分,留给各个子类自己实现。正是因为A-B在这里没有实现,所以抽象类不允许实例化出来(否则当调用到A-B时,无法执行)。
泛型擦除
Java泛型(Generic)的引入加强了参数类型的安全性,减少了类型的转换;Java的泛型在编译器有效,在运行期被删除,所有
泛型参数类型在编译后都会被清楚掉。
泛型擦除基本过程:
首先找到用来替换类型参数的具体类。这个具体类一般是Object。如果指定了类型参数的上界,则使用这个上界类。
把代码中的类型参数替换成具体的类。同时去掉出现的类型声明,即去掉<>的内容。比如T get()方法声明就变成
Object get();List就变成List。接下来就可能需要生成一些桥接方法,这是由于类型擦除后的类可能缺少某些必须的方法。
自动装箱和拆箱
装箱就是自动将基本数据类型转换为包装器类型,拆箱就是自动将包装类型转换为基本数据类型。
int 4字节 Integer
byte 1字节 Byte
short 2字节 Short
long 8字节 Long
float 4字节 Float
double 8字节 Double
char 2字节 Character
Boolean 未定 Boolean
Integer total = Integer.valueOf(99);
int totalprim = total.intValue;
- 有拆箱操作时要特别注意封装类对象是否为null;
- 装箱操作会创建对象,频繁的装箱操作会消耗许多内存,影响性能,所以可以避免装箱的时候应该尽量避免;
- equals(Object o)因为原equals方法中的参数类型是封装类型,所传入的参数类型是基本数据类型,所以会 自动对其装箱,反之,会自动进行拆箱;
- 当两种不同类型用==比较时,包装器类的需要拆箱,当同种类型用==比较时,会自动拆箱或者装箱。
获取键盘输入常用的两种方法
- 通过java.util.Scanner获取输入
Scanner scanner = newScanner(System.in);
int num = scanner.nextInt();
String str = scanner.next();
- 通过java.io.BufferedReader获取输入
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String str=reader.readLine();
两种方法都是通过包装System.in获取的,System.in得到的是InputStream,也就是键盘输入流的InputStream。
静态多态和动态多态
- 静态多态:即为重载,方法的重载;静态绑定/编译时绑定/早期绑定/方法重载。(在同一类中)
- 即为重写/覆盖,方法的重写;动态绑定/运行时绑定/后期绑定/方法覆盖。(在不同的类中)