多态
概述
可以理解为事物存在的多种体现形态。同样的引用调用同样的方法却做了不同的事情
多态的本质是:一个程序中同名的不同方法。多态的体现
父类的引用指向子类的对象,父类的引用接收子类的对象。
多态可以表现在很多方面,例如可以通过子类对父类方法的覆盖实现多态,也可以通过一个类中方法的重载实现多态,还可以将子类的对象作为父类的对象实现多态。
多态的前提
类与类之间必须是继承或者实现的关系。通常还有一个前提 就是覆盖
多态的利与弊
大大的提高了程序的扩展性,但是只能使用父类的引用访问父类中的成员。多态中成员的特点
非静态成员函数:在编译时期,参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。在运行时期,参阅对象所属的类中是否有调用的方法。
总结,成员函数在多态调用的时候,编译看左边父类,运行看右边子类。
成员变量:无论编译和运行,都参考左边父类。
静态成员函数:无论编译和运行都参考左边父类。如何使用子类特有方法:多态转型
Animal a=new Cat(); //类型提升,向上转型
a.eat(); //父类的共有方法多态事例与扩展事例
学生例
/* * 基础班学生: * 学习 、睡觉 * 高级班学生: * 学习、睡觉 */ abstract class Student { public abstract void study(); public static void sleeps() { System.out.print("睡觉"); } } class jichu extends Student { public void study() { System.out.print("学习基础"); } public static void sleeps() { System.out.print("站着"); } } class gaoji extends Student { public void study() { System.out.print("学习高级"); } public static void sleeps() { System.out.print("趴着"); } } class DoStudent { public void dosome(Student stu) { stu.study(); stu.sleeps(); } } public class duotai { public static void main(String[] args) { DoStudent ds=new DoStudent(); ds.dosome(new jichu());//传的是子类对象 ds.dosome(new gaoji()); } }
电脑运行实例
/* * 需求;主板事例 * 电脑运行实例,电脑运行基于主板 */ interface PCI { public void open(); public void close(); } class MainBoard { public void run() { System.out.println("主板运行"); } public void usePCI(PCI p) { if(p!=null) { p.open(); p.close(); } } } class netcard implements PCI { public void open() { System.out.println("网卡运行"); } public void close() { System.out.print("网卡关闭"); } } public class duotai { public static void main(String[] args) { MainBoard mb=new MainBoard(); mb.run(); mb.usePCI(new netcard()); } }
实现
方法重写:不同的子类对父类的同一方法给出不同的实现版本对象造型:用父类型的引用引用子类型的对象
方法的重载
方法的重载就是在同一个类中允许同时存在一个以上的同名方法,只要它们的参数个数或类型不同即可,在这种情况下,该方法就叫被重载了,这个过程称为方法的重载。与方法的覆盖不同,重载不是子类对父类同名方法的重新定义,而是类对自身已有的同名方法的重新定义。Object类
在Object类中定义了toString()方法,在该方法中输出了对象的基本信息匿名内部类
new 外部类名或者接口名() {覆盖类或者接口中的代码(也可以自定义内容)
};
是内部类的简化格式
首先它是内部类,它最大的特点就是没有名字,而且我们不能显示的通过代码为它添加构造方法。
前提:内部类必须继承或者实现一个外部类或者接口
就是建立一个带有内容的外部类或者接口的子类匿名对象
匿名内部类中定义的方法最好不要超过3个
异常
什么是异常
异常属于程序在运行时出现的状况,编译器无法检查异常是低耦合的处理运行时状况的方式,不打乱原有的业务逻辑
异常也称为例外,是在程序运行中发生的、会打断程序正常执行的非正常事件
Error类称为错误类,它表示Java运行时产生的系统内部错误或资源耗尽的错误,是比较严重的,仅靠修改程序本身是不能恢复执行的。
Exception类称为异常类,它表示程序本身可以处理的错误,在开发Java程序中进行的异常处理,都是针对Excption类及其子类。在Exception类的众多子类中有一个特殊的RuntimeException类,该类及其子类用于表示运行时异常,除了此类,Exception类下所有其它的子类都用于表示编译时异常。
异常的分类
ThrowableError
IOError
AssertionError
VirtualMachineError
OutOfMemoryError
StackOverflowError
AWTError
Exception
受检异常(编译器会检查该类异常并且强制性的要求处理)
ClassNotFoundException
IOException
CloneNotSupportedException
InterruptedException
IllegalAccessException
NoSuchFieldException
NoSuchMethodException
SQLException
RuntimeException
NullPointerException空指针异常
IndexOutOfBoundsException
ArrayIndexOutOfBoundsException数组下标越界
ArithmeticException算数异常
ClassCastException
NegativeArraySizeException
SecurityException
IllegalArgumentException
NumberFormatException字符串转换为数字异常
ConcurrentModificationException
运行时异常
运行时异常大多数是由于程序设计不当而引发的错误,但是这种错误要在运行时才会发生和被发现,如零作除数、数组下标越界、访问空对象等。这类错误可以通过改进程序加以克服,不需对其进行捕获。如果发生了这类异常,系统可以自行处理。检查型异常
也是在运行时发生的,但是编译器会在编译时进行检查,一旦发现某些语句使得此类异常有产生的“可能”,就会强制要求用户进行处理,否则不能通过编译。try...catch和finally
try调用声明受检异常的方法必须使用try块进行保护,否则调用者也要进行异常声明自行编写程序代码来捕捉异常的最大好处是:可以灵活操控程序的流程,且可以做出最适当的处理。
一个try后面可以跟0个或多个catch
并列的catch最多只有一个有机会执行
异常的捕获遵循里氏替换原则
并列的catch应当先捕获子类型异常再捕获父类异常
没有父子关系的异常类型对catch的顺序没有要求
需要注意的是,finally中的代码块有一种情况下是不会执行的,那就是在try...catch中执行了System.exit(0)语句。System.exit(0)表示退出当前的Java虚拟机,Java虚拟机停止了,任何代码都不能再执行了。
throw
在程序出现状况的地方可以创建异常对象并用throw抛出catch捕获到异常之后也可以用throw将异常对象再次抛出
再次抛出时可以将受检异常包装成运行时异常
注意:抛出异常时,throw关键字所抛出的是异常类的实例对象,因此我们要先用new关键字来产生一个对象。
throws关键字
子类重写的方法不能比父类被重写方法声明更多的异常可以用throws为方法声明一个或多个异常,多个异常用逗号隔开
方法声明异常时需要遵循重写三原则
运行时异常和编译时异常
经常会在程序编译时期产生一些异常,而这些异常必须要进行处理,这种异常被称为编译时期异常,也称为checked异常。编译时异常的特点是Java编译器会对其进行检查,如果出现异常就必须对异常进行处理,否则程序无法通过编译。
处理编译时期的异常有两种方式,具体如下:
使用try…catch语句对异常进行捕获
使用throws关键字声明抛出异常,调用者对其处理。
另外还有一种异常是在程序运行时期产生的,这种异常即使不编写异常处理代码,依然可以通过编译,因此我们称之为运行时异常,也称为unchecked异常。
运行时异常的特点是Java编译器不会对其进行检查
运行时异常一般是由于程序中的逻辑错误引起的,在程序运行时无法恢复。比如通过数组的角标访问数组的元素时,如果超过了数组的最大角标,就会发生运行时异常
自定义异常
在实际开发中,如果没有特殊的要求,自定义的异常类只需继承Exception类,在构造方法中使用super()语句调用Exception的构造方法即可。class 异常名称 extend Exception { 类主体}
异常设计原则
不要将异常处理用于正常的控制流对可以恢复的情况使用受检异常,对编程错误使用运行时异常
避免不必要的对受检异常的使用
优先使用标准异常
每个声明(抛出)异常的方法都要有文档
不要在catch中忽略掉捕获到的异常
保持异常的原子性
异常发生后对象能够恢复到异常发生之前的状态
避免过于庞大的try块
不要写一个catch(Exception e) {}捕获所有的异常,异常的捕获要有针对性