1-10 面向对象之多态

作业回顾

继承: 为了减少相同关联类的相关属性和方法,所抽取出来一个模板类【父类】,让当前抽取出来类和原有类产生关联,这种方式就是---》继承
提供继承信息的--》 父类    得到继承信息 --》 子类
Java中是单一继承,一个类只允许有一个直接父类,但是Java是允许间接继承【允许有爷爷辈..Java中若需要继承需要使用关键字   extends  
语法:
    public class  父类类名{
        子类共有的属性
        子类共有的方法
        提供父类有参和无参构造方法    
    }
PS: 在外部操时候,父类是不会直接创建对象,不会这样做  父类 父类对象名 = new 父类();
     父类--"模板" --》就是提供信息使用 --》 父类"直接"创建对象意义不大
     为了限制父类创建对象 --》 类的其他修饰符 ---abstract 关键字 --》 抽象类    
    
    public class 子类类名 extends 父类类名{
           子类自身的属性和方法
           可以继承到父类所提供的所有可见属性--》【只要不是private修饰】    
           子类无法继承父类的构造方法,所以子类需要提供自己的构造方法【无参和有参】
           PS:子类实例化的过程--》先创建父类对象,然后在创建子类对象
               子类构造方法默认调用父类构造方法
               隐式调用:默认调用父类无参
               显示调用:可以在子类使用super关键
               super 关键字 在子类中代表是父类对象
               --super.属性名 super.成员方法  --》 调用父类属性和父类方法
               --》 在子类的构造方法中可以使用super()形式调用父类构造方法【根据传入的参数区分】
               --super() 调用父类的构造方法,必须在子类构造方法第一句
            --》PS:在开发中约定,this关键说明这个属性属于子类,使用super(有参构造方法)父类属性的创建
               
          继承中一个专享的概念:子类可以重写父类的方法【不能重写父类使用以下任意一个修饰符修饰方法】
           --"private、static、final"
           --》 最低要求:1.必须和父类方法签名一致【方法+参数列表】
                        2.父类方法如何定义子类就如何定义
                        3.建议在子类重写方的位置上方添加一个注解 "@override"
           --》 子类一旦重写父类方法,外部就无法直接获取到原有父类的实现,只能获取到子类重写之后效果
           --》 非要调用:一种实在子类中使用 super 关键字 调用父类原有方法
                        直接创建父类对象,调用--》 否定,父类是不直接创建对象
           --》为了防止你调用父类重写法方法,提供一个关键字 abstract --》抽象方法    
               
          原则问题:
           "子类重写父类方法的原则:父类提供方法无法满足子类需求,此时子类就有权重写父类的方法"
           "但是,如果父类方法使用以下任意修饰符,子类无权重写【private、static、final】"    
               
           1.直接打印对象的时候,是无法打印出对象中存的数据,只会打印出一个字符串
             【包名+类名】类的全限定名称 + "@"+hashcode换算的十六进制
        某些情况之下,我们需要打印对象的时候输出一些我们想要的"结果",此时原有对象输出就无法满足我们的需求 
        打印对象的"结果" 它所需要出发的方法是父类Object中的toString方法,就需要重写这个方法
             
           2.引用类型比较问题,引用类型是不允许使用 ==  进行比较 【比较的是两个对象地址】
             所以引用类型需要使用API中提供equals方法
             PS:"系统API类中,所有equals方法都实现完毕了【重写了父类Object所提供equals方法】"
             自定义类所需要进行比较,需要重写父类所提供equals方法,才能比较引用类型是否相等
             PS:"自定义类提供的equals方法只对当前类所创建出来的对象有用"
          --》 equals重写原则,就是当前类中属性全部相等,或部分相等【属性中有,数组,集合,接口等等】
             在重写equals比较相等对象时候,还有一天原则
              --"只要两个对象的equals是相等,那么他们的hashcode也要相等"
             在重写equals的时候需要重写hashcode
             hashcode的重写原则: 引用类型就调用其对应的hashcode值类型  
               
          "obejct 是所有类直接间接父类,所有类都是直接或间继承于Object "
           "equals、hashcode、toString都是父类object所以提供,所以才可以重写"    
               
        
    }
1、机场安检系统,检查公民信息,如果信息是以下任意一个
姓名        ID
张学友, 9999
刘德华, 8888
郭富城, 7777
吴奇隆,6666
机场想起了警报,来了一群便衣将XXX带走了,否则祝XXX旅途愉快!

核心: 就是希望可以重写equals和hashcode
      需要数组
      一个公民类--> 提供基础信息 姓名和ID  equals 和 hashcode重写
      机场安监系统 -->  执行类
package com.qfedu.AirPortSystem;

import java.util.Objects;

/**
 * 公民类
 * PS:描述类【实体类】创建,分为两个派系
 * 一个忠实拥护IDEA --》IDEA在整合一个插件 Lombok【口碑是两级分化】
 * 一个是原始模板描述拥护
 *
 */
public class Citizen {
    //1.封装性,在类中体现,为了防止属性被恶意修饰,我们需要进行属性私有化private
    //多行一次编辑  alt+shift+鼠标左键
     private String name;
     private String ID;

    public Citizen() {
    }

    public Citizen(String name, String ID) {
        this.name = name;
        this.ID = ID;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getID() {
        return ID;
    }

    public void setID(String ID) {
        this.ID = ID;
    }

    //自定义公民信息打印
    @Override
    public String toString() {

             return "公民姓名"+name+" 公民ID:"+ID;
    }
   //equals比较的类的属性值,所以当前类中,需要比较就是名字和ID都要完全一致
    @Override
    public boolean equals(Object o) {
        //形参是Object类型即父类,可以接受任何子类传递,所以这里需要对父类进行--》对象的向下转型
        Citizen other = (Citizen)o;
        //因为name 是String类型,所以String类型中equals方法已经被重写了,所以可以只实用
        //String中equals方法比较的字符串的内容
        return this.name.equals(other.name) && this.ID.equals(other.ID);

    }

    @Override
    public int hashCode() {
        //引用类型使用hashcode+值类型直接使用
        return name.hashCode() + ID.hashCode();
    }
}

package com.qfedu.AirPortSystem;

/**
 * 数据模拟类 , 存储数据使用
 */
public class CitizenDB {
    //其实就是改名的工具类
    private CitizenDB(){}
    //随着类而加载属性并且是不可改变
    private  static final Citizen db[] = {
            new Citizen("张学友","9999"),
            new Citizen("刘德华","8888"),
            new Citizen("郭富城","7777"),
            new Citizen("吴奇隆","6666")};
    //获取当前存储数据的公民数组
    public static Citizen[] getCitizenDB(){
        return db;
    }
}
package com.qfedu.AirPortSystem;

import java.util.Scanner;

//机场安检系统
public class AiPortSystem {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("-------------------------------欢迎进入机场安检系统--------------------------------");
        Scanner input = new Scanner(System.in);
        System.out.println("请输入您的姓名:");
        String name = input.next();
        System.out.println("请输入您的ID号:");
        String ID = input.next();
        Citizen c = new Citizen(name,ID);
        System.out.println("--------------------------------请稍等正在验证您的信息-----------------------------------");
        Thread.sleep(2000);
        if(checkCitizenInfo(c)){
            //这里直接打印了c 对象,想打印c的信息,所以需要从写toString
            System.out.println("机场响起警报,"+c+"被便衣带走了.....");
        }else{
            System.out.println("祝:"+c.getName()+"旅行愉快....");
        }

    }
    private  static boolean checkCitizenInfo(Citizen c){
           //获取存储在数组中数据进行比较
        for(int i = 0 ;i<CitizenDB.getCitizenDB().length;i++){
            //这里是通过equals比较公民信息的,所以需要重写equals和hashcode
            if(CitizenDB.getCitizenDB()[i].equals(c)){
                return true;
            }
        }
        return  false;
    }
}


2.需求:
   凹凸曼 1个
   名字
   血量
   普通  必杀 一次只能打1只 随机大一只活着小怪兽
   魔法       所有
   凹凸曼的攻击 10%必杀 30%魔法 60%普攻
    
   小怪兽 4只
   名字
   血量
   普通  
  
   回合制游戏
   输出:
  ========X回合 ========
   XXX凹凸曼 血量XXX  
   使用了 魔法攻击全体/普攻,XXX小怪兽/必杀,XXX小怪兽
   XXX小怪兽 血量XXX
   XXX小怪兽 血量XXX
   XXX小怪兽 血量XXX
   XXX小怪兽 血量XXX
   小怪兽使用了普攻
  
   凹凸曼血量为0,小怪兽胜利
   所有的小怪兽都死了,凹凸曼胜利

   凹凸曼 普攻和必杀不能攻击死了小怪兽 随机
          魔法无所谓 小怪兽的血量不能出现负数 0
   小怪兽 死了小怪兽不能攻击 0
package com.qfedu.game;

/**
 * 奥特曼的类
 */
public class Ultraman {
    //属性
    private String name;
    private int hp;
    //提供有参和无参构造方法

    public Ultraman() {
    }

    public Ultraman(String name, int hp) {
        this.name = name;
        this.hp = hp;
    }

    //get和set

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getHp() {
        return hp;
    }

    public void setHp(int hp) {
        this.hp = hp;
    }

    //普通攻击[一次一只]
    public void attack(Monster m){
        //伤害计算  20~29产生的伤害
        int injury = (int)(Math.random()*10+20);
        //获取 小怪兽的血量
        int hp = m.getHp();
        hp -= injury;
        //如果小怪兽的血量只有10,会出现负数,但是打印的时候只能个出现0
        if(hp >= 0){
            m.setHp(hp);
        }else{
            m.setHp(0);
        }

    }

    //必杀[一次一只]
    public void Hugeattack(Monster m){
        //伤害计算 先判断小怪兽血量4分之3之上一次就攻击4分3 否则固定输出60
        int injury =(int)(m.getHp()*0.75) > 60 ? (int)(m.getHp()*0.75) : 60;
        //获取 小怪兽的血量
        int hp = m.getHp();
        hp -= injury;
        //如果小怪兽的血量只有10,会出现负数,但是打印的时候只能个出现0
        if(hp >= 0){
            m.setHp(hp);
        }else{
            m.setHp(0);
        }

    }

    //魔法攻击[全体]
    public void Magicattack(Monster[] ms){
      for(Monster m : ms) {
          //获取 小怪兽的血量
          int hp = m.getHp();
          hp -= 30;
          //如果小怪兽的血量只有10,会出现负数,但是打印的时候只能个出现0
          if (hp >= 0) {
              m.setHp(hp);
          } else {
              m.setHp(0);
          }
      }

    }

}
package com.qfedu.game;

/**
 * 小怪兽的类
 */
public class Monster {
    //属性
    private String name;
    private int hp;
    //提供有参和无参构造方法

    public Monster() {
    }

    public Monster(String name, int hp) {
        this.name = name;
        this.hp = hp;
    }

    //get和set

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getHp() {
        return hp;
    }

    public void setHp(int hp) {
        this.hp = hp;
    }

    //普通攻击
    public void attack(Ultraman u){
        //伤害计算  10~19产生的伤害
        int injury = (int)(Math.random()*10+10);
        //获取 小怪兽的血量
        int hp = u.getHp();
        hp -= injury;
        //如果小怪兽的血量只有10,会出现负数,但是打印的时候只能个出现0
        if(hp >= 0){
            u.setHp(hp);
        }else{
            u.setHp(0);
        }
    }


}
package com.qfedu.game;
//小怪兽工具类
public class MonsterUtils {
    //1. 构造方私有化
    private  MonsterUtils(){}
    /*
    挑选一只小怪兽
     */
    public static Monster selectMonster(Monster[] ms){
        //1.声明一个小怪兽对象,但是不赋值
        Monster m;
        do {
            //先获取下标
            int index = (int)(Math.random()*ms.length);
            m = ms[index];
        }while(m.getHp() == 0);

        return m;
    }

    /*
    判断是否还有活着的小怪兽
     */
    public static boolean aliveMonster(Monster[] ms){
        for(Monster m : ms){
            if(m.getHp() > 0){
                return true;
            }
        }
        return false;
    }


}


package com.qfedu.game;
//游戏执行
public class GameTest {
    public static void main(String[] args) {
        //1.先做先期准备
        //1.1需要有奥特曼
        Ultraman u = new Ultraman("5哥",1000);
        //1.2创建4只小怪兽并存储到数组
        String[] names = {"提莫","巨兔","腐儿","团子"};
        //1.3将小怪兽存储到数组中
        Monster[] monsters = new Monster[4];
        for(int i = 0 ;i<monsters.length;i++){
            Monster m = new Monster(names[i],300);
            monsters[i] = m;
        }

        //2.开始游戏
        //2.1设置回合数
        int round = 1;
        //执行操作
        do {
            System.out.println("=========================第"+round+"回合======================");
            //2.2要求: 60% 普通  30% 魔法 10% 必杀
            //随机数  [0~9) 范围
            int p = (int)(Math.random()*10);
            //if这套逻辑就是奥特曼攻击
            if(p<6){//60% 普通 0 1 2 3 4 5
                //2.3随机挑选一只或者的小怪兽
                Monster m = MonsterUtils.selectMonster(monsters);
                //2.4奥特曼攻击小怪兽
                u.attack(m);
                System.out.println(u.getName()+"使用了普通攻击"+m.getName());
            }else if(p < 9){// 30% 魔法 6 7 8
                //2.5 奥特曼魔法攻击小怪兽
                u.Magicattack(monsters);
                System.out.println(u.getName()+"使用了魔法攻击");

            }else{//10% 必杀 9
                //2.6随机挑选一只或者的小怪兽
                Monster m = MonsterUtils.selectMonster(monsters);
                //2.7奥特曼必杀攻击小怪兽
                u.Hugeattack(m);
                System.out.println(u.getName()+"使用了必杀攻击"+m.getName());
            }
            //小怪兽攻击
            for(Monster m : monsters){
                //只有活着的才可以攻击
                if(m.getHp()>0){
                    m.attack(u);
                }
            }
            System.out.println("小怪兽使用了普通攻击"+u.getName());

            //打印结果值
            System.out.println(u.getName()+"奥特曼HP是:"+u.getHp());
            for(Monster m : monsters) {
                System.out.println(m.getName()+"小怪兽HP是:"+m.getHp());
            }
            //回合+1;
            round +=1;

         //循环停止条件 ,只要一方死亡即可
        }while(u.getHp()>0 && MonsterUtils.aliveMonster(monsters));

        //循环已停止游戏自然结束
        if (u.getHp()>0){
            System.out.println("奥特曼胜利!!!");
        }else{
            System.out.println("小怪兽胜利!!!");
        }

    }
}



面向对象之多态

final关键字

final关键字的作用可以修饰**【变量、方法、类】**

1.final关键字修饰变量,这个变量就会变为**【定义】常量**

PS:final关键字即可以修饰全局也可以修饰局部

2.final修饰方法,这个方法被修饰之后只能被继承,不能被重写

3.final修饰类,这类就是终类【最终的类】,不可被继承

PS:final修饰类是类的两个其他修饰符中一个,类其他修饰符不能共存

package com.qfedu.Final;

/**
 * final关键字的演示使用
 */
public class FinalTest {
    //final修饰变量将变成 定义常量已经赋值 无法修改
    //1.它可以修饰成员变量和静态变量,但是必须赋值【静态变量除外,需要配合使用静态代码块】
    //PS:固定:常量和变量的分区,在名字上进行区分,变量名都小写, 常量都要大写比,并且每个单词之间使用_分隔
     final int A = 10;
     static final double PI = 3.14;
    public static void main(String[] args) {
        //允许修饰局部变量
         final int AA = 10;
         //PS:修饰局部变量的时候,它允许这样做
          final int BB;
          BB = 11;  //这个赋值只能进行一次
    }
}
//修饰符类的方法
class Father{
    public final void show(){
        System.out.println("让继承不让重写");
    }
}
class Son extends Father{
    //防止子类重写一些不能重写的方法
//   public void show(){
//       
//   }

    public static void main(String[] args) {
        //允许被继承
        new Son().show();
    }
   
}
//修饰类,不可被继承 ,API中存在这个操作,实际类中少很少除非限制工具类
final class  SuperClass{}
//class SubClass extends SuperClass{}

多态

PS:多态产生必须有继承关系

什么是多态?

【多种状态】同一个事物被不同对象所触发得到结果不同称之为【多态】

PS:

例如:一个父类,生出了一个女儿和一个儿子,两个孩子都是正常生产,但是女儿长得好看,儿子长得就有有点…

cut词,如果是导演听到了停止拍摄,如果理发师听到这个理发

在Java中多态分为两种

1.方法多态:同一个方法被不同参数所触发得到结果是不一样【即重载】

public int add(int a,int b)
public double add(double a,double b)    

2.对象多态:同一个事物被不同对象所触发得到结果不同【必要前提,必须有继承】

事物--》 行为 --》方法
同一个方法别不同对象所触发得到结果是不一样的
如何得到不同对象? 同一个方法-->子类重写    

多态概念中,提供一个软件设原则**【里氏代转换原则】**

里氏代转换原则

是对象中对多态概念的一个补充,这个概念的核心是允许【对象执行向上和向下转型】,如果要做对象向上和向下转型,需要依托于一个关系,类与类之间的而继承关系

对象的向上转型

父类的引用【对象】可以接收一个子类引用【对象】,子类会被自动提升为父类类型

注意:此时只能调用父类里面提供属性和方法,不能调用子类特有属性和方法

语法:

PS:"这个语法也是父类对象唯一创建对象方式"
    
   父类类型  对象名  = new 子类类型();

"前提:必须是继承关系,父类与子类"

案例:

年终Boss让所有员工进行一下自我介绍,自己薪水

经理 底薪+奖金

销售 底薪+提成

普通员工 底薪+补贴

package com.qfedu.polymorphic;
//创建一个员工类  --> 父类
public class Employee {
    private int salary;
    public Employee() {

    }
    public Employee(int salary) {
        this.salary = salary;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }
     /*
     父类提供一个空方法,主要是计算薪水使用,因为每个子类计算方式都不一样,此时父类提供实现
      */
    public  int  addMoney(){
        return 0;
    }

}
package com.qfedu.polymorphic;

/**
 *   经理类,只要不是老板都是员工
 */
public class Manager extends  Employee{
       private int jiangjin;
       private String name;
       public Manager(){}
       public Manager(String name,int jiangjin,int salary){
           super(salary);
           this.jiangjin = jiangjin;
           this.name = name;
       }
       //因为要介绍自己的薪水所以需要提供一个计算薪水的方式
     public int getJiangJin(){
           return jiangjin;
     }
    @Override
    public int addMoney() {
        return  getSalary()+jiangjin;
    }

    @Override
    public String toString() {
        return "经理名字:" + name+"薪水:"+addMoney();
    }


}
package com.qfedu.polymorphic;

/**
 * 销售
 */
public class Sell extends  Employee {
    private int ticheng;
    private String name;
    public Sell(){}
    public Sell(String name,int ticheng,int salary){
        super(salary);
        this.ticheng = ticheng;
        this.name = name;
    }
    //因为要介绍自己的薪水所以需要提供一个计算薪水的方式
    @Override
    public int addMoney() {
        return  getSalary()+ticheng;
    }

    @Override
    public String toString() {
        return "销售名字:" + name+"薪水:"+addMoney();
    }
}
package com.qfedu.polymorphic;

/**
 * 普通员工  
 */
public class Staff extends  Employee {
    private int butie;
    private String name;
    public Staff(){}
    public Staff(String name,int butie,int salary){
        super(salary);
        this.butie = butie;
        this.name = name;
    }
    //因为要介绍自己的薪水所以需要提供一个计算薪水的方式
    @Override
    public int addMoney() {
        return  getSalary()+butie;
    }

    @Override
    public String toString() {
        return "普通员工名字:" + name+"薪水:"+addMoney();
    }
}
package com.qfedu.polymorphic;
//测试类
public class BossTest {
    public static void main(String[] args) {
        System.out.println("-----------------年会中自我介绍-----------------");
        BossTest bt = new BossTest();
        Manager m = new Manager("小白",20000,30000);
        bt.showInfosEmployee(m);
        Sell sell = new Sell("小红",100000,1);
        bt.showInfosEmployee(sell);
        Staff staff = new Staff("小花",1000000,20000000);
        bt.showInfosEmployee(staff);




    }

    //除了老板 都是员工 对象向上转型
    /*
    Employee e = m --> Employee e = new Manager("小白",20000,30000);
    Employee e = sell --> Employee e = new Sell("小红",100000,1);
    Employee e = staff --> Employee e = new Staff("小花",1000000,20000000);
     */
    public  void showInfosEmployee(Employee e){
        System.out.println(e);
    }




//    public void showInfosManager(Manager m){
//        System.out.println(m);
//    }
//    public void showInfosSell(Sell sell){
//        System.out.println(sell);
//    }
//    public  void showInfosStaff(Staff staff){
//        System.out.println(staff);
//    }
}


对象的向下转型

将已经被提升为父类类型对象,转换为原有子类类型

注意:此时不仅可以调用父类中所提供属性和行为,也可以调用自身的属性和行为

语法:

PS:"向下转型的前提一定是已经被提升过后的对象【向上转型】"
    
    子类类型 对象名 = (子类类型)被提升为父类类型对象;

案例:

package com.qfedu.polymorphic;
//父类
public class Animal {
    private String name;
    private int age;
    public Animal() {

    }
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
package com.qfedu.polymorphic;
//子类猫类
public class Cat extends Animal {
    public Cat() {
    }

    public Cat(String name, int age) {

        super(name, age);
    }
    public void show(){

        System.out.println("猫吃鱼");
    }
}
package com.qfedu.polymorphic;
//子类狗类
public class Dog extends Animal {
    public Dog() {
    }

    public Dog(String name, int age) {
        super(name, age);
    }
    public void show(){
        System.out.println("狗吃肉");
    }
}


package com.qfedu.polymorphic;

public class AnimalTest {
    public static void main(String[] args) {
        //1.对象的向上转型
         Animal a1 = new Dog("小白",19);
         Animal a2 = new Cat("小花",20);
         //此时就已经发生了对象的向上转型,子类自动被提升为父类类型,仅能调用属性和行为
        System.out.println(a1.getName());

        //2.对象的向下转型
        //有一个先决条件,必须是被提升为父类类型的对象,才可以向下转型
        //只要语法对,编译时期,是不会报错,但是这里存在一个问题a2并不是Dog类型,是Cat
        //强制类型转换异常ClassCastException
//        Dog dog = (Dog)a2;
//        dog.show();
        //为了避免强制类型转换异常  Java中提供一个关键字可以用来检查对象数据类型 instanceof
        /*
        语法:
           转型对象  instanceof  转型类型    得到一个判断结果
          如果转型对象是转型类型的,返回true ,如果不是返回为false
         */
        if(a2 instanceof Dog){
            Dog dog = (Dog)a2;
            dog.show();
        }else{
            System.out.println("无法强制类型转换,因为a2不是Dog类型");
        }

        //这种操作是完全错误
        Animal a3 = new Animal();//父类类型对象
         Cat cat = (Cat)a3;//不能转换
         Cat cat1 = new Cat();//不能提升


    }
}



PS:集合或接口的实现,数据传参,多态的应用场景

多态成员变量和成员方法方法问题

package com.qfedu.polymorphic;
class Father{
    public int num = 10;
    public void show(){
        System.out.println("父类的show方法");
    }
    public Father(){}
}
class Son extends Father{
    //开发绝对禁止出现子类属性和父类同名
    public int  num = 20;
    public Son(){}

    @Override
    public void show() {
        System.out.println("子类重写的show方法");
    }
}
public class ValueAndMethod {
 
    public static void main(String[] args) {
      
        //1.对象的向上转型
        Father f = new Son();
        //当前f是被提升之后父类型, 只能调用父类属性和方法
        //属性不存在重写
        System.out.println(f.num);
        //重写之后,必然执行子类实现方式
        f.show();
        
        //2.对象的向下转型,必然会成为子类,技能调用父类属性和方法,也能调用字节的属性和方法
        Son s = (Son)f;
        //既然已明确类型是子类,所以s触发的num是自身空间中num值
        System.out.println(s.num);
        s.show();//子类重写方法

    }

}



抽象类和抽象方法

PS:抽象类就是一个特殊的父类

父类看做时一个模板,在这个模板上进行添加这个类是子类【子类会继承父类所有可见属性和行为,并且可以父类的基础上记性添加修改】

在实际开发中,父类是不会直接创建对象的【父类 对象 = new 父类()】;

现阶段,是无法防止父类直接创建对象,那么有没有什么方式即能保证父类不直接创建对象,又能保证保持原有父类的特点,Java中就提供了一个特殊类,这个类就叫做–》【抽象类】

在实际开发中,子类是可以重写父类方法的,**父类提供某些方法,子类必然重写,父类提供方法,每个子类的实现方式都不一样,父类无法给出正确实现方式,**如果单纯会将父类方法定义不实现,会出现一些问题

1.例如某些子类忘记了重写父类方法,此时子类重写不会做任何提示的

2.不仅忘记重写而且父类会对方法进行实现,此时子类调用了这个方法,必然会执行出现错误

Java为了解决这个问题,提供了一个特殊的方法 --》【抽象方法】

PS:抽象方法只能存在在抽象类

抽象类就是用来被继承的,而提供被继承的类都是父类,所以建议创建父类的时候设置成抽象类,父类提供方法,子类必然重写,建议将当前方法设置成抽象方法

语法说明:

ps:
    "1.使用到一个关键字 abstract,这个关键字,只能修饰类和方法"
    "2.这个关键字不能和final共存"
    "3.创建抽象类"
    访问权限修饰符 abstract class 类名{
     	 如何定义父类就如何定义这个类 
         子类的共有属性和方法    
         构造方法
         getter和setter
         抽象类中是允许书写抽象方法    
    }
    "4.创建抽象方法,绝对不允许有方法体并且是以[;]作为结尾"
     访问权限修饰符 abstract 返回值类型 方法名 (参数列表);   
    "5.抽象方法必须存在在抽象类中,抽象类中可以不存在抽象方法"


案例:

package com.qfedu.Abstract;

public abstract  class SunFlowerBible {
    private String name;
    public SunFlowerBible(){}

    public String getName() {
        return name;
    }
    public  void show(){}
    public static void showInfos(){}
    public abstract  void liangong();
}
package com.qfedu.Abstract;

public class Yuebuqun extends SunFlowerBible {
    @Override
    public void liangong() {
        System.out.println("啊......疼.......完蛋了.....后悔了!");
    }
}
package com.qfedu.Abstract;

public class Test {
    public static void main(String[] args) {
        //1.抽象类是一个特殊父类,所以支持多态特性
       // SunFlowerBible sunFlowerBible = new SunFlowerBible();
        SunFlowerBible sfb = new Yuebuqun();
    }
}


抽象类的特点

"1.抽象类是一个特殊的父类,特殊在于不能直接创建对象【含义: 父类  父类对象 = new 父类()】,但是支持多态的特性,允许对应进行向上和向下转型操作"
"2.抽象类和抽象方法,不能和private、static和final关键字共存"
"3.抽象类可以作为方的参数数据类型存在,也可以作为返回值类型存在"
"4.一个普通类若继承于一个抽象类,必须实现类中所有的抽象方法"
abstract  class A{
    public abstract  void show();
}
class B extends A{
    @Override
    public  void show(){
    }
}
"5.抽象类与抽象类之间是存在继承关系,一个抽象类继承于另外一个抽象类,此时抽象子类即可以实现父类中抽象方法,也可以不实现,并且还可以继续提供抽象方法"   
  abstract  class A{
    public abstract  void show();
}
abstract  class B extends  A{
    //可以实现父类抽象方法也可以不实现
    //并且还可以继续提供抽象方法
    public abstract  void display();
}  

PS:"无论如何继承普通类都要实现没有实现抽象方法,并且如果已经有重写过的方法,后续的子类可以继续继续重写"
    abstract  class A{
    public abstract  void show();
}
abstract  class B extends  A{
    //可以实现父类抽象方法也可以不实现

    @Override
    public void show() {
        
    }

    //并且还可以继续提供抽象方法
    public abstract  void display();
}
class C  extends  B{
    @Override
    public void show() {
        
    }

    @Override
    public void display() {
        
    }
}

接口

PS:接口就是一个特殊的抽象父类

硬件接口

指的是两个硬件之间设置的连接方式,硬件接口包括逻辑上和物理上,硬件接口最常见的体现就是【USB接口】

软件接口

软件接口是一个特殊的类,类中存在一些规范,这些规范都是等待实现着来实现

例如:

鸟会飞,飞机也会飞,通过代码描述这个两个对象时候,可以发都具备飞行的行为,但是两者之间没有客观现实存在逻辑,所以就不可能抽取出一个父类,这个父类一共飞行方法,此时就可以提供一个解决方法,提供一个飞行规范【飞行接口】,这要在这里提供一个飞行方法,谁需要飞行,必须遵守这个规则,即【实现】这个非常接口

PS:接口可以想象成一个规范,规定一些事物的原则,若需要实现调用当前事物,必须实现接口

JDK1.8之前

接口的定义:interface 关键字
    public interface 接口名{
    	全局静态常量
        抽象方法    
    
	}
package com.qfedu.Interface;

/**
 * 接口名字的规则,如果名字的在第一个字母是I,就不需要做任何任何操作
 * 如果第一个字母不是I,就建议在名字的前面添加一个 大写的I字母
 * 这样的目的是表示这个文件是接口文件
 */
public interface ISunFlowerBible {
    //1.8之前可以在接口中定义的式
    //全局静态常量 在接口中定义存在默认修饰 public static final
     String BOOK_NAME = "葵花宝典";
    //等价于  public static final String BOOK_NAME = "葵花宝典";
    //抽象方法,默认修饰 public abstract
    void liangong();
    //等价于 public abstract void liangong();
   
}
package com.qfedu.Interface;
/*
接口是规范,如果需要实现规范就需要使用类实现接口
这个类要是实现接口,这个类的名字必须添加Impl作为名字结尾
接口是 【实现】 不是 【继承】 --》所以使用关键字需要改变 implements
只要普通类实现接口,就必须实现接口中抽象方法
 */
public class PersonImpl implements ISunFlowerBible{
    @Override
    public void liangong() {
        System.out.println("武功秘籍:"+BOOK_NAME);
        System.out.println("......");
    }
}
class Demo{
    public static void main(String[] args) {
         //接口是一个特殊的抽象父类
         /*
         1.接口可以定义抽象方法
         2.接口主要是用来实现的和抽象父类类似,抽象父类是用来继承
         3.接口不能直接创建对象
         4.接口支持多态,可以当做父类来使用,作为接口值或,作为方法的返回值类型和参数类型
          */
         //ISunFlowerBible  is = new ISunFlowerBible();
        //这种方式必须是接口实现类否则不允许
        ISunFlowerBible is = new PersonImpl();
    }
}


JDK1.8之后

接口的定义:interface 关键字
    public interface 接口名{
    	全局静态常量
        抽象方法    
        //增加了两个方法
        default 方法 --》可以有方法体 --》相当于是类中成员方法
        static 方法  --》可以有方法体 --》相当于是类中静态方法 
	}
package com.qfedu.Interface;
//JDK1.8中的实现方式
public interface InterfaceForJDK1_8 {
    //和1.8之前一样的 全局静态常量和抽象方法
    int NUM = 10;
    void show();

    //这两个两个方法默认是public,default方法相当于是 类中成员方法
    //                           static方法相当于是 类中静态方法
    //允许有方法体
    default  void showInfosDefault(){
        System.out.println("接口中default方法");
    }
    static void showInfosStatic(){
        System.out.println("接口中static方法");
    }
}
package com.qfedu.Interface;
//JDK1.8中的实现方式
public interface InterfaceForJDK1_8 {
    //和1.8之前一样的 全局静态常量和抽象方法
    int NUM = 10;
    void show();

    //这两个两个方法默认是public,default方法相当于是 类中成员方法
    //                           static方法相当于是 类中静态方法
    //允许有方法体
    default  void showInfosDefault(){
        System.out.println("接口中default方法");
    }
    static void showInfosStatic(){
        System.out.println("接口中static方法");
    }
}


接口特点

"1.一个类可以实现多个接口【如果是普通类,需要实现接口中所有抽象方法,如果是抽象类,可以选择实现和不实现】"
 public interface InterfaceA{
		void showA();
 }
public interface InterfaceB{
		void showB();
 }
public class InterfaceImpl implements InterfaceA,InterfaceB{
     //需要实现接口中所有抽象方法
}
public abstract class InterfaceImpl implements InterfaceA,InterfaceB{
     //既可以实现也可以不实现,在于抽象类中可以存在抽象方法
}
"2.一个类即可以继承一个类同时可以实现多个接口"
class C{}    
public class InterfaceImpl extends C implements InterfaceA,InterfaceB{
     //需要实现接口中所有抽象方法
}  
"3.接口之间是存在继承关系,接口是可以单继承和多继承,继承过程中不允许出现相同方法名"
public interface A{}
public interface B{}
public interface C extends A{}
public interface D extends AB{}

"4.接口是不能直接创建对象,但是允许使用多态【必须是接口实现类】,接口是引用类型,所以可以作为方法的返回值和参数类型"    
    
    
    
    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值