------- android培训、java培训、期待与您交流! ----------
3 面向对象之继承
3.1 继承的定义
类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类,子类会自动拥有父类所有可继承的属性和方法。在程序中,如果声明一个类继承另一个类,需要用到extends关键字。
运行结果是: 哈士奇
需要注意的问题:
1 类只支持单继承,不支持多重继承。即一个类只能有一个直接的父类
class A{}
class B{}
class C extends A,B{} //错误!C类不可以同时继承A和B
2 多个类可以继承同一个父类
class A{}
class B extends A{}
class C extends A{}
3 在Java中,允许多层继承
class A{}
class B extends A{}
class C extends B{}
4 子类和父类是一种相对概念,也就是说一个类是某个类父类的同时也可以是另一个类的子类。
3.2 重写父类方法
当子类出现和父类一模一样的函数时,当子类对象调用该函数,会运行子类函数的内容。
如同父类的函数被覆盖一样。这种情况是函数的另一个特性:重写(覆盖),需要注意的是,在子类中重写的方法需要和父类被重写的方法具有相同的方法名、参数列表以及返回值类型
运行结果: 汪汪
注意:1 子类覆盖父类,必须保证子类权限大于等于父类权限。
2 静态只能覆盖静态
3 父类private,子类访问不到
3.3 super关键字
当子类重写父类的方法后,子类对象将无法访问父类被重写的方法,为了解决这个问题,Java专门提供了super关键字用于访问父类的成员。
运行结果: animal发出叫声
注意:父类的成员变量或方法如果是私有,那么super也是访问不到的。
加载子类class文件时会先加载父类class文件。
3.4 子父类的构造函数
在对子类对象进行初始化时,父类的构造函数也会运行,那是因为子类的构造函数默认有一条隐匿的语句super(),super():会访问父类中(注意)空参数的构造函数,而且子类中所有的构造函数默认第一行都是super(),因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。所以子类在对象初始化中要先访问一下父类的构造函数。如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式指定。
运行结果: bacd
注意:super函数一定写在子类函数的第一行。super函数和this函数不能共存(this和super都要写在第一行)。
3.5 final关键字
final关键字可用于修饰类、变量和方法,它有“这是无法改变的”或者“最终”的含义,因此被final修饰的类、变量和方法将具有以下特性:
* final修饰的类不能被继承
* final修饰的方法不能被子类重写
* final修饰的变量(成员变量和局部变量)是常量,且只能赋值一次
常量的书写规范:所有的字母都大写,单词间用_连接
class修饰符只能是public 或 final或abstract
3.6 抽象类
抽象 abstract:看不懂
抽象类的特点:
* 抽象方法一定在抽象类中
* 抽象方法和抽象类都必须被abstract关键字修饰
* 抽象类不可以用new 创建对象,因为调用抽象方法没意义
* 抽象类中的方法要被使用必须由子类复写其所有的方法后,建立子类对象调用
如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。
抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。
运行结果: 汪汪
3.6.1 模板设计模式
又叫模板方法模式,在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情冴下,重新定义算法中的某些步骤。
例子:编写程序获得一段程序的运行时间
3.7 接口
3.7.1 接口的定义
接口:初期理解,可以认为是一个特殊的抽象类,当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示。class用于定义类,interface用于定义接口。
接口定义时,格式特点:
1 接口中常见定义:常量,抽象方法。
2 接口中的成员都有固定修饰符。常量:public static final,方法:public abstract
记住:接口中的成员都是public的。
3.7.2 接口的性质
1 接口中的方法都是抽象的,不能实例化对象。
2 当一个类实现接口时,如果这个类是抽象类,则实现接口中的部分方法即可,否则需要实现接口中的所有方法。
3 一个类通过implements关键字实现接口时,可以实现多个接口,被实现的多个接口之间用逗号隔开。
4 一个类在继承另一个类的同时还可以实现接口,此时,extends关键字必须位于implements关键字之前。
5 接口间的关系是继承,接口可以实现多继承,但不能出现返回值不同方法名相同的情况。
3.7.3 接口的举例实现
主体的放在父类,扩展的放在接口。
4 多态
4.1 多态的概念和体现
多态:事物存在的多种体现形态。函数的重载和重写就是函数多态的体现,多态一般指对象的多态性。
多态的体现:父类的引用指向了自己的子类对象或者说父类的引用也可以接收自己的子类对象,前提是必须是类与类之间有关系,要么继承,要么实现,通常还有一个前提,存在覆盖。
运行结果: Dog eat
Cat eat
4.2 多态的好处和弊端
好处:多态的出现大大的提高了程序的扩展性。
弊端:提高了扩展性,但是只能使用父类的引用访问父类中的成员。
4.3 对象的类型转换
借用多态我们可以很方便的调用同名的方法,但是只能使用父类的引用访问父类中的成员,如果想访问子类特有的成员怎么办呢?这时需要把对象的类型进行转换。
4.4 多态的特点
4.4.1 在多态中非静态成员函数的特点
在编译时期:参阅引用型变量所属的类中(父类)是否有调用的方法,如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法(子类)。
简单总结就是:成员函数在多态调用时,编译看左边(父类),运行看右边(子类)。
4.4.2 在多态中静态成员函数的特点
无论编译和运行,都参考左边(父类)(引用型变量所属的类)。
静态函数无法重写,覆盖只发生在子类与父类之间,当全是静态成员的全局性质时,这种子父类的概念已经不存在了,所以就不会覆盖,造成编译的二义性两个同名而且不重载的函数(全局性质的),显而易见,会编译报出重复定义。
4.4.3 在多态中,成员变量的特点
无论编译和运行,都参考左边(父类)(引用型变量所属的类)
5 内部类
5.1 内部类的定义和访问规则
将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)
特点:内部类的访问规则:
1 内部类可以直接访问外部类中的成员,包括私有。
2 外部类要访问内部类,必须建立内部类对象。
3 其他外部类建立非私有内部类对象
Outer.Inner in = new Outer().new Inner();
4 当内部类在成员位置上,就可以被成员修饰符所修饰。如:
private:将内部类在外部类中进行封装。
static:内部类就具备静态特性。
在外部其他类中,如何直接访问静态内部类的非静态成员呢?
new Outer.Inner().function();
在外部其他类中,如何直接访问静态内部类的静态成员呢?
Outer.Inner.function();
注意:
1 当内部类中定义了静态成员,该内部类必须是静态的。(静态类中有静态)
2 当外部类中的静态方法访问内部类时,内部类也必须是静态的。(静态访问静态)
3 静态内部类只能访问静态成员(包括内部类的和外部类的)
5.1.1 内部类中变量的访问规则
5.2 什么时候使用内部类?
当描述事物时,事物的内部还有事物。该事物用内部类来描述。
因为内部事物在使用外部事物的内容。
5.3 局部内部类
局部内部类:
1 局部内部类的成员变量不可以被static修饰,因为局部内部类不能被static修饰,static只能修饰成员变量。
2 建立局部内部类对象要写在局部内部类之后。
3 局部内部类可以直接访问外部类中的成员,因为还持有外部类中的引用。但是不可以访问它所在的局部中的变量,只能访问被final修饰的局部变量。
运行结果 3
5
5.4 匿名内部类
1 匿名内部类其实就是内部类的简写格式
2 定义匿名内部类的前提:
内部类必须是继承一个类或者实现接口。
3 匿名内部类的格式:new 父类或者接口(){定义子类的内容};
4 匿名内部类中定义的方法最好不要超过3个。
5.5 包
5.5.1 包的定义
1 对类文件进行分类管理
2 给类提供多层命名空间
3 写在程序文件的第一行
4 类名的全称的是 包名.类名
5 包也是一种封装形式
注意包名:所有字母都小写
5.5.2 包与包之间的访问
protected:保护权限,只有继承才可以访问
总结:包与包之间进行访问,被访问的包中的类以及类中的成员,需要public修饰
不同包中的子类还可以直接访问父类中被protected权限修饰的成员
| public | protected | default | private |
同一个类中 | ok | ok | ok | ok |
同一个包中 | ok | ok | ok |
|
子类 | ok | ok |
|
|
不同包中 | ok |
|
|
|
包与包之间可以使用的权限只有两种,public和protected
5.5.3 导入import
建议不要写通配符*,需要用到包中的哪个类,就导入哪个类。包里如果有相同的类名,那么要调用则必须加上包名.类名。
6 异常
6.1 异常的概念
体系: Throwable
|--Error
|--Exception
|--RuntimeException
异常:就是程序在运行时出现不正常情况。
异常由来:问题也是现实生活中的一个具体的事物,也可以通过java的类的形式进行描述,
并封装成对象。其实就是java对不正常情况进行描述后的对象体现。
对于问题的划分:一种是严重的问题,一种是非严重的问题。对于严重的,java通过Error类进行描述,对于Error类一般不编写针对性的代码对其进行处理。对于非严重的,java通过Exception类进行描述,对于Exception类可以使用针对性的处理方式进行处理。
异常的好处:
1 将问题进行封装
2 将正常流程代码和问题代码相分离,方便于阅读。
6.2 异常的处理
java提供了特有的语句进行处理:
格式:
try
{
需要被检测的代码;
}
catch(异常类变量)
{
处理异常的代码;(处理方式)
}
finally
{
一定会执行的语句;
}
格式二:
try
{
需要被检测的代码;
}
finally
{
一定会执行的语句;
}
对捕获到的异常对象进行常见方法操作:
6.3 throws
在函数上声明异常。便于提高安全性,让调用出进行处理,不至于会编译失败,如:
int div(int a,int b) throws Exception //声明了该功能有可能会出现问题
{
return a/b ;
}
对多异常的处理:
1 声明异常时,建议声明更为具体的异常。这样处理的可以更具体。
2 对方声明几个异常,就对应有几个catch块。不要定义多余的catch块,如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。
建议在进行catch处理时,catch中一定要定义具体处理方式,不要简单定义一句e.printStackTrace(); 也不要简单的就书写一条输出语句。
6.4 自定义异常
因为项目中会出现特有的问题,而这些问题并未被java所描述并封装对象。所以对于这些特有的问题可以按照java对问题封装的思想。将特有的问题,进行自定义的异常封装。
如何定义异常信息?
因为父类已经把异常信息的操作都完成了,所以子类只要在构造时,将异常信息传给父类。
6.5 finally
finally中存放的是一定会被执行的代码,通常用于关闭资源。
finally只有一种情况不会执行。当执行到System.exit(0);finally不会执行
6.6 异常在子父类覆盖中的体现
1 子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。
2 如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
3 如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。
如果子类方法发生了异常,就必须要进行try处理,绝对不能抛。