学习内容:编译时类型检查的重要性,使用泛型实现编译时进行类型检查,定义泛型接口、泛型类,派生泛型接口、泛型类的子类、实现类,使用类型通配符,设定通配符上限和通配符下限,设定类型形参的上限,在方法签名中定义类型形参,泛型方法和类型通配符之间的区别和联系,泛型方法与方法重载,java8改进的类型推断,擦除与转换,泛型与数组
学习笔记:
1、当把对象放进集合里,元素会失去原来的类型,都变成Object类型,之所以设计成这样,是因为想具有很好的通用性,但这样带来了两个问题。①集合对元素类型没有任何限制,这样可能引发一些问题。②由于把对象丢进集合时,集合丢失了对象的状态信息,因此取出元素时通常还需要进行强制类型转换,这种强制类型转换既增加了编程的复杂度,也可能引发异常。
2、包含泛型声明的类型可以在定义变量、创建对象时传入一个类型实参,从而可以动态的生成无数多个逻辑上的子类,但这种子类在物理上并不存在。
3、当创建带泛型的自定义类,为该类定义构造器时,构造器名还是原来的类名,不要增加泛型声明。
4、定义方法时可以声明数据形参,调用方法时必须为这些数据形参传入实际的数据,与此类似的是,定义类、接口、方法时可以声明类型形参,使用类、接口、方法时应该为这些类型形参传入实际的类型。
5、不管为泛型的类型形参传入哪一种类型实参,对于java来说,它们依然被当成同一个类处理,在内存中也只占用一块内存空间,因此在静态方法、静态初始化块或者静态变量的声明和初始化中不允许使用类型形参。
6、类型通配符与泛型方法还有一个显著的区别:类型通配符既可以在方法签名中定义形参类型,也可以用于定义变量的类型,但泛型方法中的类型形参必须在对应方法中显示声明。
7、java8改进了泛型方法的类型推断能力,类型推断主要有如下两方面。①可通过调用方法的上下文来推断类型参数的目标类型。②可在方法调用链中,将推断得到的类型参数传递到最后一个方法。
8、当把一个具有泛型信息的对象赋给另一个没有泛型信息的变量时,所有在尖括号之间的类型信息都将被扔掉。
学习内容:异常的定义和概念,java的异常机制和捕获异常的方法,多异常捕获,java异常类的继承体系,异常对象的常用方法,finally块的作用,自动关闭资源的try语句,异常语句的合理嵌套,Chected异常和Runtime异常,使用throws声明异常,使用throw抛出异常,定义异常,异常链和异常转义,异常的跟踪栈信息,异常的处理规则
学习笔记:
1、当java运行时环境收到异常对象时,会寻找能处理该异常对象的catch块,如果找到合适的catch块,则把该异常对象交给该catch块处理,这个过程被称为捕获异常,如果java运行时环境找不到捕获异常的catch块,则运行时环境终止,java程序也将退出。
2、在通常情况下,如果try块被执行一次,则try块后只有一个catch块会被执行,绝不可能有多个catch块被执行,除非在循环中使用了continue开始下一次循环,下一次循环又重新运行了try块,这才可能导致多个catch块被执行。
3、try块与if语句不一样,try块后的花括号不可以省略,即使try块里只有一行代码,也不可以省略这个花括号。与之类似的是,catch块后的花括号也不可以省略。还有一点需要指出:try块里声明的变量时代码块内局部变量,只在try块内有效,在catch块中不能访问该变量。
4、异常捕获时,一定要记住先捕获小异常,再捕获大异常。
5、使用一个catch块捕获多种类型的异常时需要注意如下两个地方:①捕获多种类型的异常,多种异常类型之间用|隔开。②捕获多种类型的异常时,异常变量有隐式的final修饰,因此程序不能对异常变量重新赋值。
6、所有的异常对象都包含了如下几个常用方法:①getMessage():返回异常的详细描述字符串。②printStackTrace():将该异常的跟踪栈信息输出到标准输出流。③printStackTrace(PrintStream S):将该异常的跟踪栈信息输出到标准输出流。④getStackTrace()返回该异常的跟踪栈信息。
7、java的垃圾回收机制不会回收任何物理资源,垃圾回收机制只能回收堆内存中对象所占用的内存。
8、异常处理语法结构中只有try块是必须的,也就是说,如果没有try块,则不能有后面的catch块和finally块,catch块和finally块都是可选的,但两者必须出现其一,也可以同时出现,可以由多个catch块,捕获父类异常的catch块必须位于捕获子类异常的后面,但不能只有try块,既没有catch块,也没有finally块,多个catch块必须位于try块之后,finally块必须位于所有的catch块之后。
9、除非在try块、catch块中调用了退出虚拟机的方法,否则不管在try块、catch块中执行怎样的代码,出现怎样的情况,异常处理的finally块总会被执行。
10、如果finally块里也使用了return或者throw等导致方法终止的语句,finally块已经终止了方法,系统将不会跳回去执行try块、catch块里的任何代码。
11、这种在try块或finally块中包含完整的异常处理流程的情形被称为异常处理的嵌套。
12、自动关闭资源的try语句相当于包含了隐式的finally块,因此这个try语句既可以没有catch块,也没有finally块。
13、对于Checked异常的处理方式有如下两种。①当方法明确知道该如何处理该异常,程序应该使用try。。catch块来捕获异常,然后在对应的catch块中修复该异常。②当前方法不知道如何处理这种异常,应该在定义该方法时声明抛出该异常。
14、使用Checked异常至少存在两大不便之处:①对于程序中的Checked异常,java要求必须显示捕获并处理异常,或者显示声明抛出该异常。这样就增加了编码复杂度。②如果在方法中显示声明抛出Checked异常,将会导致方法签名与异常耦合,如果该方法是重写父类的方法,则该方法抛出的异常还会受到被重写方法所抛出的异常的限制。
15、虽然PrintStackTrace()方法可以很方便地用于追踪异常的发生情况,可以用它来调试程序,但在最后发布的程序中,应该避免使用它,而应该对捕获的异常进行适当的处理,而不是简单地将异常的跟踪栈信息打印出来。
16、过度使用异常主要有两个方面。①把异常和普通错误混淆在一起,不再编写任何错误代理代码,而是以简单地抛出异常来替代所有的错误处理。②使用异常处理来代替流程控制。
17、对于完全已知的错误,应该编写处理这种错误的代码,增加程序的健壮性,对于普通错误,应该编写处理这种错误的代码,增加程序的健壮性,只有对外部的、不能确定的和预知的运行时错误才使用异常。
18、异常处理机制的初衷是将不可预期异常的处理代码和正常的业务逻辑处理代码分离,因此绝不要使用异常处理来替代正常的业务逻辑判断。
19、异常只应该用于处理非正常的情况,不要使用异常处理来代替正常的流程控制。对于一些完全可预知,而且处理方式清楚的错误,程序应该提供相应的错误处理代码,而不是将其笼统地称为异常。
20、①所有的异常都采用相同的处理方式,这将导致无法对不同的异常分情况处理,如果要分情况处理,则需要在catch块中使用分支语句进行控制,这是得不偿失的做法。②这种捕获方式可能将程序中的错误、Runtime异常等可能导致程序终止的情况全部捕获到,从而压制了异常。如果出现了一些关键异常,那么此异常也会被忽略。
21、通常建议对异常采取适当措施,比如:①处理异常。对异常进行核实的修复,然后绕过异常发生的地方继续执行,或者用别的数据进行计算,以代替期望的方法返回值,或者提示用户重新操作,总之,对于Checked异常,程序应该尽量修复。②重新抛出新异常。把当前运行环境下能做的事情尽量做完,然后进行异常转义,把异常包装成当前层的异常,重新抛出给上层调用者。③在合适的层处理异常。如果当前层不清楚如何处理异常,就不要再当前层捕获异常,直接使用throws声明抛出该异常,让上层调用者来负责处理该异常。