Day08–面向对象3(多态)
一、static关键字
1.特点
- 可以修饰成员变量,成员方法
- 随着类的加载而加载,优先于对象加载
- 只加载一次,就会一直存在,不再开辟新空间
- 全局唯一,全局共享
- 可以直接被类名调用
- 静态只能调用静态,非静态可以随意调用
- static不能和this或者super共用,因为有static时可能还没有对象
2.测试
package cn.tedu.opp;
//测试 static关键字
/*
* 总结
* 1.静态资源进内存的时间早,出内存的时间晚--谨慎使用
* 2.静态资源随着类的加载二加载--也叫类的资源
* 3.多了一种调用方式--除了能用对象方式调用,还能用类名直接调用
* 4.是全局共享的,而且只加载一次(省时间省内存)
* */
public class Test06_Static {
public static void main(String[] args) {
//2.静态资源进内存的时间要早,当类被加载时,静态资源同时也就加载了
Demo.game();
System.out.println(Demo.age);
Demo d=new Demo();
d.eat();
System.out.println(d.name);
//1.静态资源---通过对象d访问 或 直接被类名调用
d.game();
System.out.println(d.age);
//3.全局唯一,全局共享
Demo d2=new Demo();
d2.age=20;
System.out.println(d.age);//20
}
}
class Demo{
//普通资源
String name;
public void eat() {
//5.非静态资源调用静态资源??--可以
game();
System.out.println(age);
System.out.println(name);
System.out.println("eat...");
}
//静态资源--要被static修饰
static int age =10;
public static void game() {
//4.静态资源调用非静态资源??--不行
//eat();
//System.out.println(name);
System.out.println(age);
System.out.println("game");
}
}
二、静态代码块
1.概述
- 通常用来完成项目的初始化,拥有static的所有特点
2.特点
- 位置是在成员位置
static{
.....
}
3.测试
package cn.tedu.opp;
//测试 静态代码块
/*
* 总结
* 1.执行顺序
* 当类加载时:执行静态代码块 只执行一次
* 当创建对象时:执行构造代码块并且构造代码块优先于构造方法执行
* 当方法被调用时:执行局部代码块
* */
public class Test07_Block {
public static void main(String[] args) {
Person2 p = new Person2();
p.show();
}
}
class Person2{
static{
System.out.println("静态代码块:用来完成项目的初始化(加载的早并且只加载一次)");
}
{
System.out.println("构造代码块:提取构造方法的共性");
}
public Person2() {
System.out.println("构造方法:用来创建对象");
}
public void show() {
System.out.println("局部代码块:控制变量的作用范围");
}
}
三、final关键字
1.概述
- 最终的,final的本意是用来, 控制子类重写的现象.
- 如果父类的某些方法,不许子类修改. 只需要把父类的方法修饰成最终的
2.特点
- 可以修饰类,不能被继承
- 可以修饰方法,不能被重写
- 可以修饰变量,值不能被修改,是一个常量
3.测试
package cn.tedu.opp;
/*
* 可以修饰类,不能被继承
* 可以修饰方法,不能被重写
* 可以修饰变量,值不能被修改,是一个常量
* */
public class Test01_Final {
public static void main(String[] args) {
new Zi2().drink();
}
}
final class Fu{//1.可以修饰类,不能被继承--The type Zi2 cannot subclass the final class Fu
}
class Fu2{
//final String NAME="Jack";//3.可以修饰变量,值不能修改--The final field Fu2.Name cannot be assigned
public static final String NAME="Jack";//常量的标准写法
final public void eat() {//2.可以修饰方法,不能被重写--Cannot override the final method from Fu2
System.out.println("eating...");
}
public void drink() {
System.out.println("drink");
}
}
class Zi2 extends Fu2{
@Override
public void drink() {
System.out.println(super.NAME);
System.out.println("喝汤");
}
}
四、多态
1.概述
- 多态是指一个对象有多种形态
- 好处:提高了程序的灵活性.体现程序的通用性.做出统一调用标准
- 通用性:多态中,不关心具体子类的类型,屏蔽了子类间的不同,会把子类当父类来看
- 好处:提高了程序的灵活性.体现程序的通用性.做出统一调用标准
2.特点
-
前提: 发生继承关系 + 发生方法重写现象
- 口诀1: 父类引用 指向 子类对象
Animal a = new Dog();
- 口诀2: 编译看左边,运行看右边
- 想要保存成功,只能使用 左边 父类的
- 结果以右边 子类 为准
3.入门案例
package cn.tedu.opp;
//测试 多态
public class Test02_Mulity {
public static void main(String[] args) {
//2.创建多态对象 -- 口诀1:父类引用 指向 子类对象
Animal a = new Dog();
//3.使用多态对象 -- 口诀2:编译看左,运行看右
//- 多态的目的是统一调用标准,标准就是父类!! -
a.eat();//- a.eat()是父类提供的方法,但运行结果是子类提供的
//- (方法声明是用了父类的,方法体是用了子类的)
//a.drink();//4.父类中没有的,是子类特有的方法,如果非得用?--多态对象不支持,只能创建子类对象使用
}
}
//1.前提:发生继承关系 + 发生方法重写现象
class Animal{
public void eat() {
System.out.println("eating...");
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("non-eating...");
}
public void drink() {
System.out.println("drinking...");
}
}
五、多态的使用
- 测试
package cn.tedu.opp;
//测试 多态的使用
/*
* 总结:
* 在使用多态对象时:
* 1.调用普通方法:普通方法被重写,所以用了子类的方法体和父类的方法声明
* 2.调用成员变量:成员变量用父类的
* 3.调用静态资源时:静态资源用父类的
* 原因:因为静态资源不能重写
* 4.多态中,方法声明一定用父类的!!(父类没声明不能使用)
* 方法体由于存在Override,所以可能使用的是子类的方法体!
* */
public class Test03_Mulity {
public static void main(String[] args) {
//创建多态对象
Animal2 a = new Dog2();
a.eat();//1.成员方法被重写了,所以用了子类的方法体和父类的方法声明
System.out.println(a.name);//2.成员变量用父类的
a.drink();//3.静态资源用父类的
Animal2.drink();//eat()是父类的
new Dog2().drink();
}
}
class Animal2{
String name = "小动物";
public void eat() {
System.out.println("eat");
}
static public void drink() {
System.out.println("drink");
}
}
class Dog2 extends Animal2{
String name = "大黄";
@Override
public void eat() {
System.out.println("non-eat");
}
//静态资源可以被重写吗?? -- 不能
static public void drink() {
System.out.println("non-drink");
}
}
六、异常
1.概述
- 是指程序中出现的bug
2.继承结构
--Throwable
--Exception:软件的bug
--ArrayIndexOutOfBoundException
--XxxException
--Error:不是软件问题,不关注
3.异常的处理
- 捕获:在程序中加代码,自己的问题自己处理
- 语法:
try{
有问题的代码
}catch(异常类型1 异常名){
给出合理的解决方案1
}catch(异常类型2 异常名){
给出合理的解决方案2
}catch(异常类型3 异常名){
给出合理的解决方案3
}...
- 抛出:自己的问题不处理,交给调用者处理
- 语法:在方法声明上,添加代码 throws 异常类型
4.测试
1)捕获异常
package cn.tedu.opp;
import java.util.InputMismatchException;
import java.util.Scanner;
//测试 异常处理
public class Test04_Exception {
public static void main(String[] args) {
// method();//暴露 异常
// method2();//捕获 异常
method3();//利用多态捕获异常
}
//暴露 异常
public static void method() {
//需求:接收用户输入的两个整数,并做除法运算
System.out.print("请输入两个整数:");
int a = new Scanner(System.in).nextInt();
int b = new Scanner(System.in).nextInt();
System.out.println(a/b);
}
//捕获 异常
public static void method2() {
/*
* try{
* 有问题的代码
* }catch(异常类型 异常名){
* 给出合理的解决方案
* }
* */
System.out.print("请输入两个整数:");
try {
int a = new Scanner(System.in).nextInt();
int b = new Scanner(System.in).nextInt();
System.out.println(a/b);
}catch(ArithmeticException e) {
System.out.println("分母不能为零");
}catch(InputMismatchException e) {
System.out.println("请输入两个整数");
}
}
//利用多态捕获异常
public static void method3() {
System.out.print("请输入两个整数:");
try {
int a = new Scanner(System.in).nextInt();
int b = new Scanner(System.in).nextInt();
System.out.println(a/b);
}catch(Exception e) {
//还有很多异常要处理,但是不知道还有几个也不知道叫啥,根本没法写了??? -- 多态
//多态来解决,多态根本不关心子类叫啥,有几个,把所有子类都当父类来看 Exception
//反正所有的异常都是Exception的子类,所以只要捕获Exception那么所有异常就能处理了
System.out.println("程序出错,请重新输入!");
}
}
}
2)抛出异常
package cn.tedu.opp;
import java.util.InputMismatchException;
//测试 抛出异常
import java.util.Scanner;
public class Test05_Throws {
public static void main(String[] args){//抛出Exception时,main方法也要跟着抛出throws Exception,或者捕获
// method();//抛出异常
try {
method2();
} catch (Exception e) {//method2抛出啥,这里就捕获啥
System.out.println("程序错误");
}
}
public static void method() throws ArithmeticException,InputMismatchException {
//语法:在方法声明上,添加代码throws异常类型
System.out.print("请输入两个整数:");
int a = new Scanner(System.in).nextInt();
int b = new Scanner(System.in).nextInt();
System.out.println(a/b);
}
//直接抛出Exception体现了多态,会把所有子类的异常都抛出
public static void method2() throws Exception{
System.out.print("请输入两个整数:");
int a = new Scanner(System.in).nextInt();
int b = new Scanner(System.in).nextInt();
System.out.println(a/b);
}
}
拓展
1.程序设计题目
事物: 培优班老师 / 高手班老师
共性: 讲课 / 备课
测试: 创建对象测试功能是否正确
2.OCP原则
OCP原则核心含意是:一个好的设计应该能够容纳新的功能需求的增加,但是增加的 方式不是通过修改又有的模块(类) ,而是通过增加新的模块(类)来完成的, 也就是在设计的时候,所有软件组成实体包括接口,函数等必须是可扩展 但不可修改的。
3.向下转型
Animal a = new Dog();
//TODO 多态对象只支持调用父类的功能,如果非要使用子类扩展的功能
//方法1:创建子类对象
//方法2:向下造型 -- 把父类类型的a转型子类类型
Dog d = (Dog)a;//强转
d.sleep();//子类特有的方法
注:Animal是父类,Dog是子类*
4.静态代码块,构造代码块,局部代码块
!!!执行顺序:静态代码块—构造代码块—构造函数
-
静态代码块:在类加载时就加载,并且只被加载一次,一般用于项目的初始化
-
构造代码块:在创建对象时会自动调用,每次创建对象都会被调用
-
局部代码块:方法里的代码块