你强任你强,我干我本行——Java基础(中)

五、内部类

内部类:定义在一个类的中的类,虽然知道Java有这个特性,但是在实际工作中却很少用到,只有在看源码时看到多处应用到内部类,以下参考了《Thinking in Java》和《java core》

5.1 为什么要用内部类:

①因为java只能单继承,运用内部类可以实现多重继承,所以每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
②内部类可以访问外部类对象的所有成员。
③若类只需要实例化一次,可以使用匿名内部类。

5.2 为什么内部类可以访问外部类对象的所有成员

因为.
eg:
声明一个拥有内部类的类:
因为编译器修改了所有的内部类的构造器,添加了一个外部类引用的参数


    public class OuterClass{
        class InnerClass{}
    }
复制代码

javac编译后会有2个文件,因为每个类都会产生一个.class文件,内部类的命名有严格的规则,外部类美元符号加上内部类,如下


class OuterClass$InnerClass {
    OuterClass$InnerClass(OuterClass var1) {
        this.this$0 = var1;
    }
    private void study() {
    }
}
复制代码

3.在方法和作用域内的内部类
①一个定义在方法中的类
②一个定义在作用域内的类,此作用域在方法的内部
③一个实现了接口的匿名类
④一个匿名类,他扩展了有非默认构造器的类
⑤一个匿名类,它执行字段初始化
⑥一个匿名类,它通过实例初始化实现构造(匿名类没有构造函数)
注:
内部类访问局部变量,局部变量必须是常量(final修饰)
静态嵌套类与内部类区别:
静态嵌套类可以完全独立于外围类存在用来隐藏自己,而内部类是外围类的一部分,内部类对象是以外部类对象存在为前提.

六、泛型

6.1 为什么用泛型?

因为集合在添加时可以放object类型元素,也就是说任何object子类都能进入此集合无论在编译器还是运行时都不会有问题,当我们获取集合元素时取出来的是object引用,但遍历时无法强转多个特定类型,除非多个分支instance of判断类型。所以决定使用泛型,用尖括号括起来类型参数,它指定了这个集合可以保存的类型,可以在编译期防止将错误类型的对象放入集合中.

6.2 泛型定义

①定义类

②定义方法

6.3 泛型擦除

虚拟机没有泛型类型对象,所有对象都属于普通类,无论何时定义一个泛型类型,都自动提供了一个相应的原始类型,原始类型的名字就是删去类型参数后的泛型类型名,擦除类型变量将擦除到它的第一个边界,并替换为限定类型(无限定类型用Object),<>不能用基本数据类型,要用引用类型因为泛型擦除。只能有Object类型(引用类型).
T → Object
T extends Comparable& Serializable → Comparable
4.既然泛型擦除,为什么还会返回特定类型?
因为编译器会把返回的Object类型自动强转为特定类型。也因为泛型擦除,会出现以下问题:

由于运行时泛型擦除,这时子类有2个方法一个是继承自父类的形参为Object类型的study方法,另一个自己重写的参数为String类型study方法,那么当我们向上转型形成多态调用study方法,这显然是不同的方法它是如调用到后者的?
javac编译,javap -c反汇编一哈,我们可以看到下图 父类引用genic,只有父类一个Object类型参数方法,由于Genic是GenicChild类型的会调用其Object类型参数方法,此方法为桥方法,它再调用String类型方法坐做了一个转换


    public void study(Object obj){
        study((String)obj);
    }
复制代码

当我们定义一个返回类型是泛型的方法,子类重写其父类方法,那么子类有2个方法一个泛型擦除的Object返回类型方法,一个是特定类型方法。这两个方法的方法签名一样,我们知道一个类不能拥有2个方法签名相同的方法,这样是不合法的,但是在虚拟机中返回类型可以用来区分方法,虚拟机能够正确处理这一情况
注:
①重载没有桥方法,重写父类方法泛型定义成擦除后的类型也不会有桥方法
②数组不能用泛型,可以用数据结构是数组的集合arraylist
③泛型不能实例化.eg new T(),new T[]因为泛型擦除不知道具体哪个类型

6.4 通配符

T 自定义泛型类型
? 默认是Object及其子类,也就是java的所有对象
? extends T 接受T类型或者T的子类型对象
? super T 接受T类型或者T的父类型对象

七、异常

7.1 异常体系:

Throwable是java异常的超类,他有两个子类,Error和Exception,Error指系统错误例如OOM由虚拟机管理,而另一个Exception在Java类库、用户方法以及运行时故障中都可能抛出的异常。Exception又分为checked Exception和unchecked Exception这2种,前者是受检查异常例如读文件时的FileNotFoundException,后者非受检查异常也叫运行时异常都继承RuntimeExcetion自动被虚拟机抛出例如大名鼎鼎的NullPointerException.

7.2 抛出异常

throw 异常生成阶段:手动抛出异常对象
throws 声明方法可能要抛出的各种异常类
抛出的异常可以catch捕获,也可以继续抛到上层,注意重写限定,若父类方法没有抛出异常,子类重写的方法只能捕获异常无法向上抛,并且catch异常最详细的最先写越泛的后写。在项目里一般都会有自定义异常,并且针对不同的错误场景会有不同的错误码,在整个项目中不同部门负责的系统定义的错误码都会有所不同这样我们在排查时直接根据错误码就能较快地发现哪个环节出了问题。
注:

7.3.finally

因为finally里的代码总会执行,所以一般用来关闭资源对象(在JDK7及以上若实现了java.lang.AutoCloseable接口的对象,和实现了java.io.Closeable接口的对象可以用try—with—resources),最好不要在finally里用return。

你可能感兴趣的:(你强任你强,我干我本行——Java基础(中))