汇总:Android小白成长之路_知识体系汇总【持续更新中…】
异常
-
在
java
中,异常对象都是派生于Throwable
类的一个实例,下一层分为两个分支:Error
和Exception
- Error:Java运行时系统的内部错误和资源耗尽错误,应用程序不应该抛出这种类型的对象
- Exception:又分为两个分支,一个分支派生于
RuntimeException
,另一个分支包含其他异常,由程序错误导致的异常属于RuntimeException
,而程序本身没问题,但由于下像I/O
错误这类问题导致的异常属于其他异常- RuntimeException:错误的类型转换,数组访问越界,访问null指针,应该修改避免,而不是捕获处理
- 其他异常:试图在文件尾部后面读取数据,试图打开一个不存在的文件,试图根据给定的字符串查找Class对象,但这个类并不存在。这类异常必须捕获或者抛出异常,不处理的话编译器将报错
-
使用
try/catch
语句块捕获异常,如果在try
语句中的任何代码抛出了一个在catch
子句中说明的异常类,那么程序将跳过try
语句块其余代码,并开始执行catch
子句中的处理代码,如果catch
子句中没有声明这个异常类型,则会立刻退出这个方法 -
finally子句:不管是否有异常被捕获,这个子句的代码都会被执行,如果代码抛出了异常,但异常没被
catch
子句捕获,那么try
的代码执行中断,直接开始执行finally
里的代码,可以只有try
和finally
语句,而没有catch
子句 -
有一种不错的捕获异常的写法:
try{ try{ ... }finally{ //释放资源 } }catch(Excepyion e){ ... }
内层的
try
语句块只有一个职责,就是确保资源被释放,而外层的try
语句块也只有一个职责,就是确保捕获出现的错误,这样写可以连finally
里出现的异常都一起捕获了 -
当利用
return
语句从try
语句块中退出,在方法返回前,finally
子句的内容将被执行。如果finally
子句中也有一个return
语句,这个返回值将会覆盖原始的返回值
泛型
-
泛型程序设计意味着编写的代码可以被很多不同类型的对象所重用
-
泛型类:
public class Pair<T> { private T first; private T second; public Pair(){ first = null; second = null} public Pair(T first,T second){ this.first = first;this.second = second;} public T getFirst(){ return first;} public T getSecond(){ return second;} }
Pair类引入一个类型变量T,用尖括号<>括起来,并放在类名后,泛型类可以有多个类型变量,例如:
public class Pair<T, U>{ }
-
泛型方法:
public static <T> T getMiddle(T... a){ return a[a.length / 2]; }
类型变量放在修饰符的后面,返回类型的前面,当调用泛型方法时,在方法名前的尖括号里放入具体的类型:
String middle = <String>getMiddle("a","b","c");
-
类型变量的限定:
public static <T extends Comparable> T min(T[] a)...
上面的形式将泛型T限制为实现了
Comparable
接口的类,如果传入的类型不满足这个规则,将编译报错。一个类型变量或通配符可以有多个限定,如:T extends Comparable & Serializable
限定类型用&隔开
-
类型擦除:无论何时定义一个泛型类型,都自动提供了一个相应的原始类型,原始类型的名字就是删去类型类型参数后的泛型类型名,擦除类型变量,并替换为限定类型(没有限定的变量默认为
Object
),例如Pair<T>
的原始类型如下:public class Pair { private Object first; private Object second; public Pair(){ first = null; second = null} public Pair(Object first,Object second){ this.first = first;this.second = second;} public Object getFirst(){ return first;} public Object getSecond(){ return second;} }
如果有多个限定的类型,则原始类型用第一个限定的类型变量来替换,如果要切换限定,编译器在必要时要向要切换的限定插入强制类型转换,因此为了提高效率,应该将没有方法的接口放在边界列表的末尾
-
泛型的约束和局限性:
-
不能使用基本类型实例化类型参数,例如没有
Pair<double>
,只有Pair<Double>
,其原因是类型擦除,擦除后原始类型是Object
,而Object
不能存储double
值(基本类型的值) -
运行时类型查询只适用于原始类型,不适用于泛型,也就是下面的查询是错误的:
if(a instanceof Pair<T>) ...
-
不能创建参数化类型的数组,例如以下的写法是错误的:
Pair<String>[] table = new Pair<String>[10];
因为类型擦除后,table的类型是Pair[]。可以将其转换为Object[],数组会记住它的元素类型,如果存储其他类型的元素,就会抛出一个
ArrayStoreException
异常,因此不允许创建参数化类型的数组。不过可以声明类型为Pair<String>[]
的变量,但不能用new Pair<String>[10];
初始化 -
不能实例化类型变量,例如下面的写法是错误的:
public Pair(){ first = new T(); second = new T();}
-
不能构造泛型数组,例如下面的写法是错误的:
public static <T extends Comparable> T[] minmax(T[] a){ T[] mm = new T[2];}
类型擦除会使这个方法永远构造Comparable[2]数组
-
泛型类的静态上下文中类型变量无效,不能在静态域或方法中引用类型变量,例如:
public class Singleton<T> { private static T singleInstance; //error public static T getSingleInstance() //error { if(singleInstance == null) return new SingleInstance(); return singleInstance; } }
类型擦除后,只剩下Singleton类,将只包含一个singleInstance域,通俗来说,也就是静态域或方法优先于类等的实例化,因此并不知道真正传递的参数类型是什么,所以无法使用
-
不能抛出或捕获泛型类的实例
-
可以消除对受查异常的检测,java异常处理有一个基本原则是必须为所有受查异常提供一个处理器,不过可以利用泛型擦除消除这个限制
-
通配符类型
-
通配符类型中,允许类型参数变化,例如:
Pair<? extends Employee>
表示任何泛型Pair类型,它的类型参数是Employee的子类
-
通配符限定与类型变量限定类似,但有一个附加的能力,即可以指定一个超类型限定,例如:
? super Manager
这个通配符限制为Manager的所有超类型
-
带有超类型限定的通配符可以向泛型对象写入,带有子类限定的通配符可以从泛型对象读取
-
无限定通配符,例如
Pair<?>
,Pair<?>
和Pair的本质不同在于:可以用任意Object对象调用原始Pair类的setObject方法