Java学习笔记:接口、对象转型、重写及多态

接口、对象转型、重写及多态

  • 学习参考网址https://how2j.cn/p/6235

接口

  • 在设计LOL的时候,进攻类英雄有两种,一种是进行物理系攻击,一种是进行魔法系攻击 
  • 这时候,就可以使用接口来实现这个效果。 
  • 接口就像是一种约定,我们约定某些英雄是物理系英雄,那么他们就一定能够进行物理攻击。

  • 物理攻击接口
    • 创建一个接口 File->New->Interface 
    • AD ,声明一个方法 physicAttack 物理攻击,但是没有方法体,是一个“”方法

Java学习笔记:接口、对象转型、重写及多态_第1张图片

package charactor;
 
public interface AD {
        //物理伤害
    public void physicAttack();
}

  • 设计一类英雄,能够使用物理攻击
    • 设计一类英雄,能够使用物理攻击,这类英雄在LOL中被叫做AD
    • 类:ADHero
    • 继承了Hero 类,所以继承了name,hp,armor等属性
    • 实现某个接口,就相当于承诺了某种约定
    • 所以,实现了AD这个接口,就必须提供AD接口中声明的方法physicAttack()
    • 实现在语法上使用关键字 implements
package charactor;
 
public class ADHero extends Hero implements AD{
 
    @Override
    public void physicAttack() {
        System.out.println("进行物理攻击");
    }
 
}

  • 魔法攻击接口
    • 创建一个接口 File->New->Interface 
    • AP ,声明一个方法 magicAttack 魔法攻击,但是没有方法体,是一个“空”方法
package charactor;
 
public interface AP {
 
    public void magicAttack();
}

  • 设计一类英雄,只能使用魔法攻击
    • 设计一类英雄,只能使用魔法攻击,这类英雄在LOL中被叫做AP 
    • 类:APHero 
    • 继承了Hero 类,所以继承了name,hp,armor等属性 
    • 同时,实现了AP这个接口,就必须提供AP接口中声明的方法magicAttack() 
    • 实现在语法上使用关键字 implements
package charactor;
 
public class APHero extends Hero implements AP{
 
    @Override
    public void magicAttack() {
        System.out.println("进行魔法攻击");
    }
 
}

  • 设计一类英雄,既能进行物理攻击,又能进行魔法攻击
package charactor;
  
//同时能进行物理和魔法伤害的英雄
public class ADAPHero extends Hero implements AD,AP{
  
    @Override
    public void magicAttack() {
        System.out.println("进行魔法攻击");
    }
  
    @Override
    public void physicAttack() {
        System.out.println("进行物理攻击");
    }
  
}

 

 

  • 设计一个治疗者接口:Healer
    • 该接口声明有方法: heal()
    • 设计一个Support类,代表辅助英雄,继承Hero类,同时实现了Healer这个接口
  • 接口:
public interface Healer {
    public void heal(); //加血
}
  • 实现接口:
public class Support extends Hero implements Healer{
 
    @Override
    public void heal() {
        System.out.println(name+" 加了一口血");
    }
 
}

 

对象转型

  • 引用类型与对象类型的概念
    • 首先,明确引用类型与对象类型的概念
    • 在这个例子里,有一个对象 new ADHero(), 同时也有一个引用ad
    • 对象是有类型的, 是ADHero
    • 引用也是有类型的,是ADHero
    • 通常情况下,引用类型和对象类型是一样的
    • 接下来要讨论的类型转换的问题,指的是引用类型和对象类型不一致的情况下的转换问题
package charactor;
 
public class Hero {
    public String name;
    protected float hp;
     
    public static void main(String[] args) {
         
        ADHero ad = new ADHero();     
    }
}

  • 子类转父类(向上转型)
    • 所谓的转型,是指当引用类型和对象类型不一致的时候,才需要进行类型转换
    • 类型转换有时候会成功,有时候会失败(参考基本类型的类型转换)
    • 到底能否转换成功? 教大家一个很简单的判别办法
    • 把右边的当做左边来用,看说得通不
Hero h = new Hero();
ADHero ad = new ADHero();
h = ad;
  • 右边ad引用所指向的对象的类型是 物理攻击英雄
  • 左边h引用的类型是 普通英雄
  • 把物理攻击英雄 当做 普通英雄,说不说得通? 说得通,就可以转
  • 所有的子类转换为父类,都是说得通的。比如你身边的例子
    • 苹果手机 继承了 手机,把苹果手机当做普通手机使用
    • 怡宝纯净水 继承了 饮品, 把怡宝纯净水 当做饮品来使用
package charactor;
 
public class Hero {
    public String name;
    protected float hp;
     
    public static void main(String[] args) {
         
        Hero h = new Hero();
         
        ADHero ad = new ADHero();
         
        //类型转换指的是把一个引用所指向的对象的类型,转换为另一个引用的类型
         
        //把ad引用所指向的对象的类型是ADHero
        //h引用的类型是Hero
        //把ADHero当做Hero使用,一定可以
         
        h = ad;
         
    }
}

  • 父类转子类(向下转型)
    • 父类转子类,有的时候行,有的时候不行,所以必须进行强制转换。
    • 强制转换的意思就是 转换有风险,风险自担。
  • 什么时候行呢?
Hero h =new Hero();
ADHero ad = new ADHero();
h = ad;
ad = (ADHero) h;
  • 第3行,是子类转父类,一定可以的
  • 第4行,就是父类转子类,所以要进行强转。
  • h这个引用,所指向的对象是ADHero, 所以第4行,就会把ADHero转换为ADHero,就能转换成功。
  • 什么时候转换不行呢?
Hero h =new Hero();
ADHero ad = new ADHero();
Support s =new Support();
h = s;
ad = (ADHero)h;
  • 第4行,是子类转父类,是可以转换成功的
  • 第5行,是把h引用所指向的对象 Support,转换为ad引用的类型ADHero。 从语义上讲,把物理攻击英雄,当成辅助英雄来用,说不通,所以会强制转换失败,并且抛出异常

  • 没有继承关系的两个类,互相转换
    • 没有继承关系的两个类,互相转换,一定会失败
    • 虽然ADHero和APHero都继承了Hero,但是彼此没有互相继承关系
    • "把魔法英雄当做物理英雄来用",在语义上也是说不通的
package charactor;
 
public class Hero {
    public String name;
    protected float hp;
 
    public static void main(String[] args) {
        ADHero ad = new ADHero();
 
        APHero ap = new APHero();
 
        // 没有继承关系的类型进行互相转换一定会失败,所以会出现编译错误
        ad = (ADHero) ap;
    }

}

  • 实现类转换成接口(向上转型)
    • 引用ad指向的对象是ADHero类型,这个类型实现了AD接口
    • 10行: 把一个ADHero类型转换为AD接口
    • 从语义上来讲,把一个ADHero当做AD来使用,而AD接口只有一个physicAttack方法,这就意味着转换后就有可能要调用physicAttack方法,而ADHero一定是有physicAttack方法的,所以转换是能成功的。
package charactor;
   
public class Hero {
    public String name;
    protected float hp;
       
    public static void main(String[] args) {
        ADHero ad = new ADHero();
          
        AD adi = ad;         
    }       
}

  • 接口转换成实现类(向下转型)
    • 10行: ad引用指向ADHero, 而adi引用是接口类型:AD,实现类转换为接口,是向上转型,所以无需强制转换,并且一定能成功
    • 12行: adi实际上是指向一个ADHero的,所以能够转换成功
    • 14行: adi引用所指向的对象是一个ADHero,要转换为ADAPHero就会失败。 
    • 假设能够转换成功,那么就可以使用magicAttack方法,而adi引用所指向的对象ADHero是没有magicAttack方法的
package charactor;
     
public class Hero {
    public String name;
    protected float hp;
         
    public static void main(String[] args) {
        ADHero ad = new ADHero();
            
        AD adi = ad;
   
        ADHero adHero = (ADHero) adi;
            
        ADAPHero adapHero = (ADAPHero) adi;
        adapHero.magicAttack();
    }
         
}

  • instanceof
    • instanceof Hero 判断一个引用所指向的对象,是否是Hero类型,或者Hero的子类
package charactor;
  
public class Hero {
    public String name;
    protected float hp;
      
    public static void main(String[] args) {
        ADHero ad = new ADHero();
        APHero ap = new APHero();
         
        Hero h1= ad;
        Hero h2= ap;
         
        //判断引用h1指向的对象,是否是ADHero类型
        System.out.println(h1 instanceof ADHero);
         
        //判断引用h2指向的对象,是否是APHero类型
        System.out.println(h2 instanceof APHero);
         
        //判断引用h1指向的对象,是否是Hero的子类型
        System.out.println(h1 instanceof Hero);
    }
}

 

重写

  • 子类可以继承父类的对象方法 
  • 在继承后,重复提供该方法,就叫做方法的重写 
  • 又叫覆盖 override

  • 父类Item
    • 父类Item有一个方法,叫做effect
package property;
 
public class Item {
    String name;
    int price;
 
    public void buy(){
        System.out.println("购买");
    }
    public void effect() {
        System.out.println("物品使用后,可以有效果");
    }
 
}
  • 子类LifePotion
    • 子类LifePotion继承Item,同时也提供了方法effect
package property;
 
public class LifePotion extends Item{
     
    public void effect(){
        System.out.println("血瓶使用后,可以回血");
    }
     
}

  • 调用重写的方法
    • 调用重写的方法
    • 调用就会执行重写的方法,而不是从父类的方法
    • 所以LifePotion的effect会打印:
    • "血瓶使用后,可以回血"
package property;
 
public class Item {
    String name;
    int price;
     
    public void effect(){
        System.out.println("物品使用后,可以有效果");
    }
     
    public static void main(String[] args) {
        Item i = new Item();
        i.effect();
         
        LifePotion lp =new LifePotion();
        lp.effect();
    }     
}

  • 如果没有重写这样的机制怎么样?
    • 如果没有重写这样的机制,也就是说LifePotion这个类,一旦继承了Item,所有方法都不能修改了。
    • 但是LifePotion又希望提供一点不同的功能,为了达到这个目的,只能放弃继承Item,重新编写所有的属性和方法,然后在编写effect的时候,做一点小改动.
    • 这样就增加了开发时间和维护成本

多态

  • 操作符的多态 
    • + 可以作为算数运算,也可以作为字符串连接 
  • 类的多态 
    • 父类引用指向子类对象

 


  • 操作符的多态
    • 同一个操作符在不同情境下,具备不同的作用
    • 如果+号两侧都是整型,那么+代表 数字相加
    • 如果+号两侧,任意一个是字符串,那么+代表字符串连接
package charactor;
   
public class Hero {
    public String name;
    protected float hp;
 
    public static void main(String[] args) {
         
        int i = 5;
        int j = 6;
        int k = i+j; //如果+号两侧都是整型,那么+代表 数字相加
         
        System.out.println(k);
         
        int a = 5;
        String b = "5";
         
        String c = a+b; //如果+号两侧,任意一个是字符串,那么+代表字符串连接
        System.out.println(c);      
    }      
}

  • 观察类的多态现象
    • 观察类的多态现象:
      • 1. i1和i2都是Item类型
      • 2. 都调用effect方法
      • 3. 输出不同的结果
    • 多态: 都是同一个类型,调用同一个方法,却能呈现不同的状态
  • LifePotion.java文件:
package property;
 
public class LifePotion extends Item {
    public void effect(){
        System.out.println("血瓶使用后,可以回血");
    }
}
  • MagicPotion.java文件
package property;
 
public class MagicPotion extends Item{
 
    public void effect(){
        System.out.println("蓝瓶使用后,可以回魔法");
    }
}
  • Item.java文件
package property;
 
public class Item {
    String name;
    int price;
 
    public void buy(){
        System.out.println("购买");
    }
    public void effect() {
        System.out.println("物品使用后,可以有效果 ");
    }
     
    public static void main(String[] args) {
        Item i1= new LifePotion();
        Item i2 = new MagicPotion();
        System.out.print("i1  是Item类型,执行effect打印:");
        i1.effect();
        System.out.print("i2也是Item类型,执行effect打印:");
        i2.effect();
    }
 
}

  • 类的多态条件
    • 要实现类的多态,需要如下条件
      • 1. 父类(接口)引用指向子类对象
      • 2. 调用的方法有重写
    • 那么多态有什么作用呢? 通过比较不使用多态与使用多态来进一步了解
  • 类的多态-不使用多态
    • 如果不使用多态,
    • 假设英雄要使用血瓶和魔瓶,就需要为Hero设计两个方法
      • useLifePotion
      • useMagicPotion
    • 除了血瓶和魔瓶还有很多种物品,那么就需要设计很多很多个方法,比如
      • usePurityPotion 净化药水
      • useGuard 守卫
      • useInvisiblePotion 使用隐形药水
    • 等等
package charactor;
 
import property.LifePotion;
import property.MagicPotion;
   
public class Hero {
    public String name;
    protected float hp;
 
    public void useLifePotion(LifePotion lp){
        lp.effect();
    }
    public void useMagicPotion(MagicPotion mp){
        mp.effect();
    }
 
    public static void main(String[] args) {
         
        Hero garen =  new Hero();
        garen.name = "盖伦";
     
        LifePotion lp =new LifePotion();
        MagicPotion mp =new MagicPotion();
         
        garen.useLifePotion(lp);
        garen.useMagicPotion(mp);
         
    }
       
}

  • 类的多态-使用多态
    • 如果物品的种类特别多,那么就需要设计很多的方法
      • 比如useArmor,useWeapon等等
    • 这个时候采用多态来解决这个问题
      • 设计一个方法叫做useItem,其参数类型是Item
      • 如果是使用血瓶,调用该方法
      • 如果是使用魔瓶,还是调用该方法
    • 无论英雄要使用什么样的物品,只需要一个方法即可
package charactor;
 
import property.Item;
import property.LifePotion;
import property.MagicPotion;
   
public class Hero {
    public String name;
    protected float hp;
 
    public void useItem(Item i){
        i.effect();
    }
 
    public static void main(String[] args) {
         
        Hero garen =  new Hero();
        garen.name = "盖伦";
     
        LifePotion lp =new LifePotion();
        MagicPotion mp =new MagicPotion();
         
        garen.useItem(lp);
        garen.useItem(mp);              
    }       
}

  • 案例演示;
1. 设计一个接口
接口叫做Mortal,其中有一个方法叫做die
2. 实现接口
分别让ADHero,APHero,ADAPHero这三个类,实现Mortal接口,不同的类实现die方法的时候,都打印出不一样的字符串
3. 为Hero类,添加一个方法,在这个方法中调用 m的die方法。
public void kill(Mortal m)
4. 在主方法中
首先实例化出一个Hero对象:盖伦
然后实例化出3个对象,分别是ADHero,APHero,ADAPHero的实例
然后让盖伦 kill 这3个对象

  • Mortal .java文件
package charactor;
 
public interface Mortal {
    public void die();
}
  • AD.java文件
package charactor;
  
public interface AD {
    public void physicAttack();
}
  • AP .java文件
package charactor;
  
public interface AP {
  
    public void magicAttack();
}
  • ADHero .java文件
package charactor;
 
public class ADHero extends Hero implements AD ,Mortal{
 
    @Override
    public void physicAttack() {
         
    }
 
    @Override
    public void die() {
        System.out.println(name+ " 这个物理英雄挂了");
    }
 
}

 

  • APHero .java文件
package charactor;
 
public class APHero extends Hero implements AP,Mortal {
    public void magicAttack() {
 
    }
 
    @Override
    public void die() {
            System.out.println(name+ " 这个魔法英雄挂了");
    }
 
}

 

  • ADAPHero .java文件
package charactor;
 
public class ADAPHero extends Hero implements AD,AP,Mortal{
 
    @Override
    public void magicAttack() {
        // TODO Auto-generated method stub
         
    }
 
    @Override
    public void physicAttack() {
        // TODO Auto-generated method stub
         
    }
 
    @Override
    public void die() {
        System.out.println(name+ " 这个混合英雄挂了");
    }
 
}
  • Hero.java
package charactor;
 
public class Hero {
    public String name;
    protected float hp;
     
    public void kill(Mortal m){
        System.out.println(name + " 放了一个大招" );
        m.die();
    }
 
    public static void main(String[] args) {
        Hero h =new Hero();
        h.name = "盖伦";
         
        ADHero ad = new ADHero();
        ad.name = "艾希";
         
        APHero ap = new APHero();
        ap.name = "安妮";
         
        ADAPHero adap = new ADAPHero();
        adap.name = "库奇";
         
        h.kill(ad);
        h.kill(ap);
        h.kill(adap);
         
    }
}

 

你可能感兴趣的:(Java学习之路)