解释:父类类型的引用类型变量保存的是子类类型的对象的地址值
3. 口诀2:编译看左边,运行看右边解释:编译时要看父类是否定义了这个资源,运行时使用的是子类的功能
4. 资源使用情况- 成员变量使用的是父类的
- 成员方法使用的是父类的方法定义,子类的方法体
- 如果多态对象调用的是子类没有重写过的方法,方法定义与方法体使用的都是父类的,所以这个不符合多态的前提,直接使用纯纯的父类对象调用即可
- 静态资源属于类资源,随着类的加载而加载,只会加载一次,优先于对象进行加载,可以通过类名直接调用,被全局所有对象共享,所以静态不存在重写的现象,在哪个类定义,就属于哪个类的资源
- 我们现在学习的多态,把自己看作是父类类型,参考“花木兰替父从军”
异常层次结构中的根是Throwable
Error:目前我们编码解决不了的问题
Exception:异常
编译异常:未运行代码就报错了,强制要求处理
运行时异常:运行代码才报错,可以通过编译,不强制要求处理
异常捕获处理的格式:
try{
可能会抛出异常的代码
}catch(异常的类型 异常的名字){
万一捕获到了异常,进行处理的解决方案
}
- try-catch结构可以嵌套,如果有多种异常类型需要特殊处理的话
- 使用多态的思想,不论是什么子异常,统一看作父类型Exception
做出更加通用的解决方案,甚至可以只写这一个
异常抛出的格式:
在方法的小括号与大括号之间,写:throws 异常类型
如果有多个异常,使用逗号分隔即可
private static void method3() throws ArithmeticException,InputMismatchException,Exception{ }
private static void method3() throws Exception{ }
- 如果一个方法抛出了异常,那么谁来调用这个方法,谁就需要处理这个异常,这里的处理也有两种方案:捕获解决 或者 继续向上抛出
- 不能直接把异常抛给main(),因为调用main()是JVM,没人解决了,该报错还报错,所以我们一般会在main()调用之前将异常解决掉
- 被关键字abstract修饰的类是抽象类
- 一旦一个类中包含了抽象方法,那么这个类必须被声明成一个抽象类
- 抽象类中的方法不做限制,非常自由:全普 / 全抽 / 半普半抽
- 抽象类不可以实例化–创建对象
- 抽象类有构造方法,它自己不用,但是为了子类创建对象时调用
- 如果一个子类继承了抽象父类,那么有两种解决方案:
1)作为一个抽象子类:不实现/实现部分抽象父类的抽象方法,躺平
2)作为一个普通子类:需要实现抽象父类的全部抽象方法,还债
- 被关键字abstract 修饰的方法就是抽象方法
- 抽象方法没有方法体{ },直接以分号结束
package cn.tedu.exec;
public class TestAnimal {
public static void main(String[] args) {
//创建蚂蚁类的对象--子类对象
Ant a = new Ant();
//创建蜜蜂类的对象--子类对象
Bee b = new Bee();
a.fly();//调用子类的特有方法
a.layEggs();//调用子类继承的方法
b.makeHoney();//调用子类的特有方法
b.layEggs();//调用子类继承的方法
}
}
//1.抽象形成一个父类
abstract class Animal{
//2.创建属性
int legNumbers;//腿的数量
int eggNumbers;//下蛋的数量
//3.创建下蛋的功能
public abstract void layEggs();
}
//4.创建子类蚂蚁类
class Ant extends Animal{
//4.2添加子类的特有属性
int eggNumbers = 2;//蚂蚁一次产2个卵
//4.1创建子类的特有功能
public void fly(){
System.out.println("蚂蚁飞啦~");
}
//4.3添加子类重写的方法
@Override
public void layEggs(){
System.out.println("蚂蚁产卵的数量为:"+eggNumbers);
}
}
//5.创建子类蜜蜂类
class Bee extends Animal{
//5.2添加子类的特有属性
int eggNumbers = 10;//蜜蜂一次产10个卵
//5.1创建子类的特有功能
public void makeHoney(){
System.out.println("蜜蜂在产蜂蜜");
}
//5.3添加子类重写的方法
@Override
public void layEggs(){
System.out.println("蜜蜂产卵的数量为:"+eggNumbers);
}
}
3 练习2-1 士兵类
package cn.tedu.exec2;
import java.util.Random;
//1.定义士兵类
public class Soldier {
//2.定义士兵类的属性
int id;//士兵编号
int blood = 100;//默认血量值100
AK47 a;//引用类型AK47作为属性,相当于给士兵配枪,a的默认值是null
//3.1定义士兵类的方法1
public void go(){
System.out.println(this.id+"号士兵在前进~");
}
//3.2定义士兵类的方法2
public void attack(){
//4.在攻击之前先判断这个士兵是否还活着,如果阵亡,直接结束当前攻击方法
if(blood == 0){
System.out.println("这是"+id+"号士兵的尸体。");
return;
}
System.out.println(id+"号士兵在进攻!");
if(a != null){
a.fire();//调用AK47发射子弹的开火方法
}
//1.生成一个随机数d,模拟进攻掉血的掉血量,随机数的范围是[0,10)
int d = new Random().nextInt(10);//[0,10)
blood = blood - d;//减去血量
//2.血量最多减到0,如果出现负数,重置成0
if(blood < 0){
blood = 0;
}
//3.当血量为0时,说明士兵阵亡
if(blood == 0){
System.out.println(id+"号士兵已阵亡。");
}
}
}
3 练习2-2 武器AK47类
package cn.tedu.exec2;
import java.util.Random;
public class AK47 {
//1.定义属性
int bullets = 100;//定义子弹的初始值为100发
//2.1定义功能1--开火功能
public void fire(){
//2.1首先判断是否有子弹,如果没有子弹,直接结束当前方法
if(bullets == 0){
System.out.println("没有子弹了!!!");
return;
}
//2.2生成一个随机值作为本次发射子弹的数量,范围:[0,10)
int r = new Random().nextInt(10);
//2.3判断实际子弹数是否够用,有多少发多少
if(r>bullets){
r = bullets;//将当前的实际子弹数赋值给随机数r
}
bullets = bullets -r;//发射子弹
//2.4为了游戏效果,发射几发子弹就在控制台打印几个突
for (int i = 0; i < r; i++) {
System.out.print("突");//本轮打印的都在同一行
}
System.out.println("~");
//2.5如果子弹数为0,提示用户弹夹空了
if(bullets == 0){
System.out.println("弹夹空了~");
}
}
//2.2定义功能2--装载子弹的功能
public void load(){
bullets = 100;
System.out.println("弹夹已装满");
}
}
4 练习2-3 测试类1
package cn.tedu.exec2;
import java.util.Scanner;
public class TestDemo1 {
public static void main(String[] args) {
//1.新建AK47对象
AK47 a = new AK47();
System.out.println("按回车射击,输入load装载子弹");
while(true){
String s = new Scanner(System.in).nextLine();
if(s.equals("load")){
a.load();
continue;
}
a.fire();
}
}
}
4 练习2-4 测试类2
package cn.cxy.exec2;
public class TestDemo2 {
public static void main(String[] args) {
//新建 Soldier 士兵对象
//内存地址,保存到变量s1
Soldier s1 = new Soldier();
Soldier s2 = new Soldier();
//用s1引用第一个士兵对象
//为它的id赋值
s1.id = 9527;
s2.id = 9528;
//用s1找到第一个士兵对象
//让第一个士兵执行go()方法代码
s1.go();
s2.go();
//新建 AK47 对象,保存到s1.a
s1.a = new AK47();
s2.a = new AK47();
s2.attack();
s2.attack();
s2.attack();
s2.attack();
}
}



