极*Java速成教程

Java语言基础

多态

多态是面向对象的一大重要特性,如果说封装是隐藏一个类怎么做,继承是确定一系列的类做什么,那多态就是通过手段去分离做什么和怎么做。

向上转型与收窄

在开发者将一类事物封装成类以后,他们的具体操作都被隐藏,而通过继承获得的“特化”的子类,满足了父类全部的性质,也就是说子类也是一种扩大的父类,子类比父类多了点东西。
那么以对父类的要求去要求子类,子类自然也全部符合要求,也就是说,可以用子类变量填充父类参数列表,用子类对象调用父类public方法,重写方法返回父类方法返回类的子类,这时候把子类的带有特性的东西丢出去一些就好,“给”的时候宜多不宜少。
我们不用关心操作的是子类还是父类,只要这个对象可以调用继承树根中的某一个类定义的方法就好。

向下转型与报错

如果把子类给了父类,就是多给了东西,Java编译器回把多余的丢掉,但是如果少给了东西,把父类给了子类,就会出现父类缺少子类特性的问题,就会不够用,就可能会报错。

绑定

将一个方法的调用和方法的主题关联起来叫做“绑定”,程序设计中,绑定分为两种,一种是当代码编译时就将方法调用和主体关联起来,叫做前期绑定,一种是运行起来以后才将方法调用和主体关联起来,叫做动态绑定。
动态绑定就像是有一个乐器演奏列表,列表中的每个乐器都要被演奏,对于程序来说,不知道下一个进来的是小提琴还是手风琴,但是只要是乐器(父类),乐器有演奏的方法,程序就能进行各种具体乐器(子类)和演奏的关联,然后对子类对象调用父类方法,就能正常运行(但是实际上运行的是子类从父类继承来的,可能进行了重写的方法)。
因此,我们应更关心类的设计,抽象出更合适的父类和继承关系结构,才能减少代码量,方便开发。

虽然Java绝大多数情况都是动态绑定,但final和static修饰的成员是静态绑定的,这是他们“最终”和“面向类的静态”的性质所决定的

接口

抽象类

就像小提琴和小号都是乐器,是乐器父类的子类,乐器父类具有演奏方法,子类自然也有。但是这时候就会出现一种问题,小提琴的演奏是拉的,小号的演奏是吹的,他们的演奏完全是不同的方法,那么父类定义的演奏方法有什么意义呢,是没有意义,是一种纯粹的抽象,基于这种思想,我们可以将父类中的演奏方法定义为抽象方法,用abstract关键词修饰,只有方法的声明而没有方法体,没有具体实现。有抽象方法的类就成了抽象类,抽象类不可以生成对象,继承抽象类的类如果没有实现方法体,那么也是一个抽象类,这个抽象的概念会传递继承。

接口类

接口类是一种特殊的类,用interface关键词替代了类的class关键词。接口类中的所有方法都是抽象的,是只有方法声明没有方法实现的,其他类可以使用implements继承接口类,继承了接口类的子类必须实现接口类声明的各个方法。
接口类中的属性是默认final和static的。
通过继承多个接口类,子类可以实现多重继承,也就是子类满足所有父类的基本要求,同时是多个父类的特例,满足多个父类的要求,实现多种向上转型。
接口类也是类,符合类继承的一切规律。
接口的强大之处在于,对于任意的一个类,只要继承了接口并实现了方法,那就满足接口的一切要求。接口就像翅膀,插在任何能提供动力的物体上,通过实现具体的飞的方法,那么这个东西就可以飞。
还可以进行工厂模式的设计,用接口构建好类和工厂类,用工厂类接口方法返回类接口;然后使用具体的类对类和工厂进行实现,就可以实现工厂的效果,对工厂的不同“产品”执行相同的操作。

内部类

将一个类置于另一个类中,那这就是内部类。内部类从逻辑思想上来说,就像你需要设计一个汽车齿轮箱,你有所有基本的材料,但仍然需要自己敲打出来一些趁手的小部件才能完成组装,这些定义在某个结构内部的类就叫内部类,内部包括类内部和方法内部等,受作用域限制。
内部类在类的内部完成定义,如果要创建一个内部类的对象,那么可以使用外部类对象.new语法在外部创建内部类对象,除静态方法外,其实例化产生对象需要使用外部类.内部类的方法进行类型指明。。
定义在内部的类,拥有其外围类所有成员的访问权,可以使用外围类.this获取一个外围类的引用。多层嵌套的内部类可以访问其所有层次的外围类的所有成员
通过使用访问控制的内部类继承接口,可以将接口实现并达到隐藏具体实现的效果,达到接口不可扩展的目的。

匿名内部类

匿名内部类就是一个没有自己名称的、继承自另一个(抽象/接口)类的类,一般直接定义在return等地方并直接创建对象,可以简化代码。
匿名类没有构造器(名字都没有,怎么定义同名的构造器XD),匿名类的初始化,可以使用代码段的方式进行{code},就仿佛是一个没有名字没有返回值的方法。当父类有有参构造器时,可以在匿名类参数列表括号里添加参数,将自动传递至父类。
匿名内部类中如果要使用外部定义的对象,那么需要是final的,但是匿名类的父类使用的对象不必是final的。

嵌套类

嵌套类就是static的内部类。嵌套类是类层次,而不是像其他内部类是对象层次的,创建嵌套类不需要外围类的对象。
嵌套类具有和其他static成员类似的性质,且只能访问static的外围类对象,没有外围类的this指针。
嵌套类可以放在接口内部,甚至可以在内部类中实现外围接口。可以方便地创造被所有接口实现类所共用的代码。

内部类的应用

内部类可以独立地承载接口,实现接口的功能,还不会让这个接口的实现“污染”到外围类的结构。内部类还可以针对同一个接口,实现不同的实现,可以丰富类的功能,比如一个类实现了一个迭代器接口,如果采取外围类直接继承接口的方式实现,那只能实现一种迭代,如果采取多个内部类实现同一个接口,那么就能实现多种迭代效果,比如反向迭代等。还可以使用内部类继承一个完整的类,这就绕开了Java单根继承的问题,可以构造更加复杂的多重继承。
通过内部类,可以实现闭包的功能。通过将具体实现隐藏到内部类中,然后提供回调的接口将内部类暴露出来,就可以实现回调的功能。
通过内部类,可以实现控制框架等框架功能,就像是一个表示事物的类中通过内部类继承事件类,实现了多种不同的行为,然后将实现了行为的内部类注册到控制器中,通过控制器调用内部类运行功能。

内部类的继承

如果只继承内部类而不继承外围类,那么内部类的继承需要在内部类的构造器中显式地指明其依附的外部类对象,并调用外围类.super()方法,在创建对象时提供相应的变量参数。
内部类不存在覆盖的思想,父类和子类的内部类是完全隔离的。

方法内部的类

不能使用访问控制关键词,有作用域限制,与匿名内部类相比,局部内部类可以有多个对象,并且可以有命名的可重载的构造器可以使用。

异常处理

Java中的异常,就是“意料之中的错误”,当问题出现时,程序应该停下来,如果可以做就做一些处理,做不了处理就交给别人处理,而不是让程序崩溃,因此异常可以增强程序的健壮性,对于一些可能发生的错误,有了更好的处理方式。System.err是标准错误流,可以打印出一些错误信息。

如何处理异常

首先,尝试运行程序

try{
    A
}

对于Java来说,try关键词修饰的代码块是尝试运行的,因为开发者知道,这里可能会出现问题。

然后,发现异常

对于Java来说,当发现可能出错的问题的时候,比如尝试访问一个空的引用,那么就可以通过throw关键词抛出异常,或者是在函数上通过throws关键词声明这个方法中可能向调用者抛出的异常。通过这种方法提出这个异常,交由外界进行处理避免程序的崩溃。
Exception类是所有异常类的父类,所有的异常都是Exception。

try{
    throw new NullPointerException("a==null");
}
public void f() throws Exception{
    throw new Exception();
}

标准Exception类都有两个构造器,一个默认构造器和一个参数构造器,可以随异常信息返回一个字符串供处理。可以自定义异常类型,继承并实现Exception类。
如果throw句没有包括在try中或者是没有catch语句可以处理或者是catch语句处理不了,依旧可以用throw语句将错误对象抛出,抛给上一级的方法和对象,逐级上抛直至有对象能处理或者是程序崩溃,甩锅嘛。
Java中异常的传递是一条甩锅的链,从前甩到后,从里甩到外,从栈顶对象甩到栈底最后甩给jvm然后程序崩溃

解决异常

针对try中提出的问题,在catch代码块中进行匹配,与Type id2类型相同的异常会被代码段B处理。

try{
    throw new NullPointerException("a==null");
}catch(Type id1){
    A
}catch(Type id2){
    B
}

catch子句将匹配Type为基类的所有类(依旧是向上转型原则),可以将捕获Exception类的catch代码放到最后,就可以捕获所有的异常还不至于所有的异常都被其一网打尽。
可以使用Exception类中的initCause()方法,将前面发生的异常现场保存下来并加入自己的一些信息,最后形成一条异常链。

结束战斗

当异常没有catch代码段能够捕获或者是异常处理结束时,可能还需要做一些收尾工作,那就交由finally代码段处理。

try{
    throw new NullPointerException("a==null");
}catch(Type id1){
    A
}catch(Type id2){
    B
}finally{
    C
}

只要执行到了try代码段,无论是否发生异常,异常是否被处理,只要虚拟机没崩,finally代码段将始终被执行。
因此,异常处理应遵循一个原则“在创建需要清理的对象后,立即进入一个try-finally语句块”。

异常日志

可以使用java.util.logging工具将输出记录到日志中。常见的用法是通过Logger.getLogger(String)获取静态logger对象,然后使用静态方法调用logger.severe(String)记录错误日志。

异常的限制

在覆盖方法时,只能抛出基类方法的异常列表中列出的异常,因为要保证向上转型的正确性(兼容性?),否则如果出现了新的异常,基类将难以处理。

原文地址:https://www.cnblogs.com/CoveredWithDust/p/Fast_JAVA_4.html