------- android培训、java培训、期待与您交流! ----------
面向对象二
对多态,继承,接口,抽象类,异常类进行总结;
1. 通过创建相应子类的对象来获取对应接口引用;
用接口的引用来调用子类的方法;
2. 多态的体现
1) 父类的引用指向了自己的子类对象。
父类的引用也可以接收自己的子类对象。
2),多态的前提
必须是类与类之间有关系。要么继承,要么实现。
通常还有一个前提:存在覆盖。
3),多态的好处
多态的出现大大的提高程序的扩展性。
4),多态的弊端:
提高了扩展性,但是只能使用父类的引用访问父类中的成员。
5),多态的应用
3. 多态的特点;
多态只能访问父类中的方法,并且访问的方法通常被覆盖了,这样运行的就是子类中的方法;
覆盖只运行子类中的方法;
4. 如果想要调用子类中的特有方法时,如何操作?
强制将父类的引用,转成子类类型,向下转型。
///Cat c = (Cat)a;
//c.catchMouse();
5. if(a instanceof Cat)这个方法用于判断对象的类型;
6. 多态调用方法的规则;
在多态中成员函数的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法。
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。
在多态中,成员变量的特点:
无论编译和运行,都参考左边(引用型变量所属的类)。
在多态中,静态成员函数的特点:
无论编译和运行,都参考做左边。
Fu1 f = new Zi1();
调用的父类的变量;变量不存在覆盖;只看左面
System.out.println(f.num);
调用的子类的方法,因为覆盖;看右面;
f.method1();
虽然这个是覆盖,但是它是静态覆盖;它只看左面,跟变量一样。
f.method4();
Zi1 z1 = new Zi1();
想调用子类的静态方法,只有通过创建自己的对象去调用;
z1.method4();
7. Object:是所有对象的直接或者间接的父类,传说中的上帝。
该类中定义的肯定是所有对象都具备的功能。
Object类中已经提供了,对对象是否相同的比较方法。
如果自定义类中也有比较相同的功能,没有必要重新定义。
只要沿袭父类中的功能,建立自己特有比较内容即可,这就是覆盖。
8. 对继承的总结
一、特点:
提高了代码的复用性。
让类与类之间产生关系,是多态性的前提。
二、Java中的继承。
1,java只支持单继承,不支持多继承。为啥呢?答案:因为继承了多个父类如果有相同方法时,子类对象不确定运行哪一个。
2,Java还支持多层继承。A-->B--->C 原来可以形成继承体系。
要使用体系功能,"查阅父类功能,建立子类对象调用功能。"
注解:父类的由来其实是由事物中的共性内容不断向上抽取而来的。
所以父类中定义的是该体系中的最基本,最共性功能。
三、继承出现后,代码上也有一些特点:
1,变量。
当子父类中定义了相同的名称的成员变量,
子类要使用父类中的同名变量时,需要使用关键字super来区分。
一般不会出现这种情况,因为父类中有了,子类不需要定义。
而且父类定义时,一般变量都私有化。
2,函数。
子类可以直接访问父类中非私有的成员函数。
特殊情况:当子类中定义了与父类一模一样的方法时,会发生覆盖操作,大多指的是非静态方法。
最终会运行子类的方法,父类相当于被覆盖了。
函数的另一个特性:覆盖(重写,复写)。
什么时候用啊?
当父类的功能要被修改时,不建议修改源码,因为是灾难。
只要通过一个类继承原有类,定义一个新的升级后的功能即可。
但是功能是相同的,只是实现方法改变,这是子类可以沿袭父类中的功能定义,
并重写功能内容。这就是覆盖。
覆盖很爽,但是有注意事项:
1)子类覆盖父类时,必须权限要大于等于父类权限。
2)静态不能覆盖非静态。
3,构造函数。
构造函数可以本类进行对象初始化,也可以给子类对象进行初始化。
子类对象初始化过程:
子类中的所有构造方法都会访问父类中空参数的构造函数,
因为每一个构造函数的第一行,都有一句隐式的super语句。
为什么要有这条语句?
因为子类会获取到父类中的数据,必须要先明确父类对数据的初始化过程。
当父类中没有空参数构造函数时,子类构造函数必须通过super句来明确要访问的父类中指定的构造函数。
当然子类构造函数也可以通过this语句访问本类中的构造函数。
但是子类中肯定,至少有一个构造函数会访问父类。
9. 抽象类:其实就是在分析事物时,事物中的功能有些是不明确的内容的,这些不明确内容就是抽象的,可以通过抽象函数来描述。
抽象函数一定要定义在抽象类中,因为,抽象函数所在类也必须被抽象标识。
写法特点:
1,抽象函数只对函数进行声明,没有函数主体。
2,抽象类和抽象函数都需要用abstract修饰。
3,抽象类不可以进行实例化。
4,想要使用抽象功能,必须通过子类覆盖了父类中所有的抽象方法后,才可以对子类实例化。如果只覆盖了部分抽象方法,那么子类还是一个抽象类。
也可以理解为:抽象类是一个父类,是不断向上抽取而来的,
在抽取过程中,只抽取了方法声明,但没有抽取方法实现。
抽象类和一半类差不多。
区别:
抽象类可以定义抽象方法。
抽象类不可以建立对象。
其实抽象类一样用于描述事物,既可以定义抽象方法,也可以定义非抽象方法。
10. 接口
初期理解:接口看上去是一个特殊的抽象类,里面存的都是抽象方法。
特点:
格式:
一、1,通过interface来定义。
2,接口中常见成员:常量,抽象方法。
而且这些成员都有固定的修饰符。
常量:public static final
方法:public abstract
3,接口中的成员都是共有的。
4,一个类可以对接口进行多实现,也弥补了多继承带来的安全隐患,所以java对多继承进行了改良,用多实现方法来体现多继承的特性。
5,一个类可以继承一个类的同时,实现多个接口。
二、接口与接口之间是继承关系,而且可以多继承。
应用特点:
1,接口是对外暴露的规则。
2,接口是功能的扩展。
3,接口的出现降低了耦合性。
三、抽象类和接口异同:
相同:
1,都可以在内部定义抽象方法。
2,通常都在顶层。
3,都不可以实例化,都需要子类来实现。
四、不同点:
1,抽象类中可以定义抽象方法和非抽象方法,
而接口中只能定义抽象方法。
2,接口的出现可以多实现。
抽象类只能单继承。
也就是说:接口的出现,避免了单继承的局限性。
3,继承和实现的关系不一致。继承:is a,实现:like a
11. 异常类
异常:就是程序在运行时出现不正常情况。
异常由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述,并封装成对象。
其实就是java对不正常情况进行描述后的对象体现。
对于问题的划分:两种:一种是严重的问题,一种非严重的问题。
对于严重的,java通过Error类进行描述。
对于Error一般不编写针对性的代码对其进行处理。
对与非严重的,java通过Exception类进行描述。
对于Exception可以使用针对性的处理方式进行处理。
无论Error或者Exception都具有一些共性内容。
比如:不正常情况的信息,引发原因等。
Throwable
|--Error
|--Exception
12. 打印异常的一些方法;
/ by zero;
System.out.println(e.getMessage());//
异常名称:异常信息。
System.out.println(e.toString());//
异常名称,异常信息,异常出现的位置。
e.printStackTrace();//
其实jvm默认的异常处理机制,就是在调用printStackTrace方法。
打印异常的堆栈的跟踪信息。
13. 我定义的这个功能可能有问题,所以我就要抛出异常信息,让调用者来处理这个信息;
//在功能上通过throws的关键字声明了该功能有可能会出现问题。
int div(int a,int b)throws Exception{
return a/b;
}
14. 对多异常的处理。
1,声明异常时,建议声明更为具体的异常,这样处理的可以更具体。
2,对方声明几个异常,就对应有几个catch块。不要定义多余的catch块。
如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。
建立在进行catch处理时,catch中一定要定义具体处理方式。
不要简单定义一句 e.printStackTrace(),
也不要简单的就书写一条输出语句
15. 自定义异常。
需求:在本程序中,对于除数是-1,也视为是错误的是无法进行运算的。
那么就需要对这个问题进行自定义的描述。
当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。
要么在内部try catch处理。
要么在函数上声明让调用者处理。
一般情况在,函数内出现异常,函数上需要声明。
发现打印的结果中只有异常的名称,却没有异常的信息。
因为自定义的异常并未定义信息。
如何定义异常信息呢?
因为父类中已经把异常信息的操作都完成了。
所以子类只要在构造时,将异常信息传递给父类通过super语句。
那么就可以直接通过getMessage方法获取自定义的异常信息。
自定义异常:
必须是自定义类继承Exception。
继承Exception原因:
异常体系有一个特点:因为异常类和异常对象都被抛出。
他们都具备可抛性。这个可抛性是Throwable这个体系中独有特点。
只有这个体系中的类和对象才可以被throws和throw操作。
throws和throw的区别
throws使用在函数上。
throw使用在函数内。
throws后面跟的异常类,可以跟多个,用逗号隔开。
throw后跟的是异常对象
代码如下;
class FuShuException extends Exception
{
private int value;
FuShuException()
{super();
}
msg父类已经实现了;我们直接调用就行了;value是我们传递的值,负数的值;
FuShuException(String msg,int value)
{
super(msg);
this.value = value;
}
public int getValue()
{
return value;
}
class Demo02
{
// 当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。
// 要么在内部try catch处理。
// 要么在函数上声明让调用者处理。
int div(int a,int b)throws FuShuException
{
if(b<0)
//手动通过throw关键字抛出一个自定义异常对象。
//因为java不认识这个异常,所以我们要手动抛出,java认识的会自动抛出;如算数异常;会自动抛给主函数;
throw new FuShuException("出现了除数是负数的情况------ / by fushu",b);
return a/b;
}
}