zoukankan      html  css  js  c++  java
  • Java学习之接口与多态篇

    Java学习之接口与多态篇

    0x00 前言

    在前面写的几篇文章里,讲了封装和继承,那么这篇文章就来讲讲第三大面向对象的特性多态吧,在此之前先接着上篇文章的抽象先来看看Java里面接口的应用。

    0x01 接口

    接口在java里面属于引用数据类型,是方法的集合。如果说的类的内部封装了成员变量、构造方法和成员方法,那么接口内部主要封装了方法,包括抽象方法,默认方法和静态方法,私有方法。

    接口的定义和定义类差不多,定义接口需要使用到interface关键字。虽然说他也会被编译为class文件,但是他并不是一个类,而是另一种引用数据类型。

    引用数据类型:数组、接口、类

    接口的使用,他和抽象类一样不能直接被创建,但是他可以被实现使用implements关键字。
    一个实现接口的类可以看作是接口的子类,需要实现接口里面所有的抽象方法,创建该类的对象,就可以调用方法了,否则他必须是抽象的子类。

    定义格式:

    public interface 接口名{
        
    }
    

    抽象方法使用 abstract 关键字修饰,可以省略,没有方法体。该方法供子类实现使用。

    public interface InterFaceName {
        public abstract void method();
    }
    

    接口里的默认方法和静态方法

    默认方法:使用default进行修饰,不能省略,提供给子类或者子类重写使用。

    静态方法:使用static修饰,提供给接口直接调用。

    public interface MyInterface {
        public static void method(){
            //执行语句
        }
        public default void method2(){
            //执行语句
        }
    }
    

    接口里的私有方法和静态方法

    私有方法和定义私有变量一样,使用private修饰,提供给接口的默认方法和静态方法调用。

    pubilc interface InterfaceName{
        
    }
    

    实现接口

    类和接口的关系为实现关系,这被称为类实现接口,这类可以称为接口的实现类,基本上和抽象类有点类似,也可以称为接口的子类。实现的动作蕾仕于继承,格式几乎一致,但是是使用implements关键字,而不是extends。

    实现接口必须重写所有的抽象方法

    集成了接口的默认方法,可以直接调用也可以重写

    接口代码:
    public interface MyInterface {
        void eat();
        void sleep();
    
    }
    实现类代码:
    public class Zi implements MyInterface {
    
    
        @Override
        public void eat() {
            System.out.println("吃");
        }
    
        @Override
        public void sleep() {
            System.out.println("睡");
    
        }
    }
    
    main方法代码:
    
    public static void main(String[] args) {
            Zi zi = new Zi();
            zi.eat();
            zi.sleep();
    
        }
    
    

    接口默认方法代码实现:

    定义接口:
    
    public interface MyInterface {
        default void eat() {
            System.out.println("吃");
            
        }
        public default void sleep(){
            System.out.println("睡");
        }
    
    }
    实现类代码:
    
    public class Zi implements MyInterface {
    
    
    
    }
    
    main方法代码:
    
    public static void main(String[] args) {
            Zi zi = new Zi();
            zi.sleep();
            zi.eat();
    
        }
    
    

    这里接口定义的第一个方法直接defalut使用这个关键字定义默认方法,第二个加上了public这两种写法都可以,前者是省略式的写法。

    实现类的任何代码都没写,只写了一个继承,默认方法是默认就定义好的,可以不用写,从实例化对象直接调用,当然也可以在实现类里面进行重写。

    接口静态方法使用

    静态与.class 文件相关,只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用。

    接口定义:
    public interface MyInterface {
        static void eat() {
            System.out.println("吃");
        }
    }
    
    实现类定义:
    
    public class Zi implements MyInterface {
    
        
    }
    
    main方法代码:
    
    public static void main(String[] args) {
            MyInterface.eat();
    
        }
        
    

    这里可以看到在main方法里面,实例化一个对象,然后去访问eat方法是报错的,定义为静态的方法必须使用接口名进行访问。

    私有方法的使用

    私有方法:只有默认方法可以访问。

    私有静态方法:只有默认方法和静态方法可以调用。

    如果一个接口有多个默认方法并且重复,那么就可以提取出来封装到私有方法里面,供默认方法去调用他。

    public interface LiveAble {
    default void func(){
    func1();
    func2();
    } p
    rivate void func1(){
    System.out.println("跑起来~~~");
    } p
    rivate void func2(){
    System.out.println("跑起来~~~");
    }
    }
    

    这种写法是jdk9的新特性,jdk8没有,此段描述纯属复制。

    0x02 接口多实现

    在前面说到因为java只支持单继承,所以一个类只能继承一个父类,但是对于接口来说,一个类是可以实现多个接口的,这就叫做接口的多实现,并且一个类里面可以继承一个父类,同时也实现多个接口。

    格式:

    class 类名 extends 父类名 impls 接口1,接口2{
        ...
    }
    或者
    class 父类名 impls 接口1,接口2{
        ...
    }
    

    接口多实现多抽象方法

    如果在多个接口中有重名的方法,该重名的方法只需重写一次。

    接口多实现多个默认方法

    接口中多个默认方法,实现类都可以继承使用。但是如果有重名的方法就必须重写一次。

    接口1:
    
    public interface MyInterface {
        default void method1(){
            System.out.println("我是一个没有感情的默认方法");
        }
        }
    接口2:
    public interface MyInterface2 {
        default void method1(){
            System.out.println("我是一个没有感情的默认方法");
        }
        }
    实现类:
    
    public class Zi implements MyInterface,MyInterface1 {
        @Override
        public void method1() {
            System.out.println("没有感情的方法");
        }
    }
    
    main方法代码:
    
        public static void main(String[] args) {
            Zi zi = new Zi();
            zi.method1();
        }
    
    

    而接口中的静态方法就不会存在重名的问他,静态方法访问可以直接使用接口名访问静态方法。

    优先级问题

    一个类中如果计策了一个父类又实现了多个接口时,父类中的成员方和接口中的默认方法重名,子类就近选择执行的父类成员方法。

    注意事项:

    接口中,无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用public static final修饰。

    接口中,没有构造方法,不能创建对象。

    接口中,没有静态代码块。

    0x03 多态

    多态是面向对象的第三大特性。

    多态:指同一种行为,具有不同的表现形式。

    多态前提:

    1.继承或者实现

    2.方法的重写

    3.父类引用指向子类[格式]

    格式:

    父类类型 变量名 = new 子类对象;
    变量名.方法名();
    

    父类类型:指向子类对象继承的父类类型,或者是实现的父类接口类型。

    当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写
    后方法。

    父类代码:
    
    public abstract class Animal {
        public abstract void play();
    }
    
    
    子类1代码:
    public class Cat extends Animal {
    
    
        @Override
        public void play() {
            System.out.println("撸猫");
        }
    }
    
    子类2 代码:
    public class Dog extends Animal{
    
        @Override
        public void play() {
            System.out.println("撸狗");
        }
    }
    
    main方法代码:
    
    public static void main(String[] args) {
            Animal cat = new Cat();
            Animal dog = new Dog();
            cat.play();
            dog.play();
        }
    
    

    0x04 多态引用类型转换

    多态的转型分为向上转型喝向下转型两种:

    我们经常用到的就是向上转型,多态本身就是子类类型向父类类型向上转换的过程。

    当父类引用指向子类对象的时候,这就是向上转型。
    代码:

    Antmal cat = new Cat();
    

    向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。

    一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。

    格式:

    子类类型 变量名 =(子类类型)父类变量名;
    

    在这里来说一下为什么要使用转型

    当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥
    有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子
    类特有的方法,必须做向下转型。

    总结:如果要调用子类拥有而父类没有的方法的时候就要使用到向下转型。

    父类代码:
    public abstract class Animal {
        public abstract void eat();
    }
    
    子类:
    public class Cat extends Animal {
    
    
        @Override
        public void eat() {
            System.out.println("吃鱼");
        }
        public void catchMouse(){
            System.out.println("抓鱼");
        }
    
    }
    
    main方法代码:
    
    public static void main(String[] args) {
            Animal cat = new Cat();
            cat.eat();
            Cat c =(Cat)cat;
            c.catchMouse();
        }
    

    为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验,格式如下:


    量名 instanceof 数据类型
    如果变量属于该数据类型,返回true。
    如果变量不属于该数据类型,返回false。

    所以,转换前,我们最好先做一个判断。

    public class Test {
    public static void main(String[] args) {
    // 向上转型
    Animal a = new Cat();
    a.eat(); // 调用的是 Cat 的 eat
    // 向下转型
    if (a instanceof Cat){
    Cat c = (Cat)a;
    c.catchMouse(); // 调用的是 Cat 的 catchMouse
    } else if (a instanceof Dog){
    Dog d = (Dog)a;
    d.watchHouse(); // 调用的是 Dog 的 watchHouse
    }
    }
    }
    

    0x05 结尾

    接口与多态篇章更新完成,检测每天一个小总结。

  • 相关阅读:
    [.net 面向对象程序设计深入](2)UML——在Visual Studio 2013/2015中设计UML用例图
    [.net 面向对象程序设计深入](1)UML——在Visual Studio 2013/2015中设计UML类图
    [.net 面向对象程序设计进阶] (28) 结束语——告别2015
    [.net 面向对象程序设计进阶] (27) 团队开发利器(六)分布式版本控制系统Git——在Visual Studio 2015中使用Git
    [.net 面向对象程序设计进阶] (26) 团队开发利器(五)分布式版本控制系统Git——图形化Git客户端工具TortoiseGit
    [.net 面向对象程序设计进阶] (25) 团队开发利器(四)分布式版本控制系统Git——使用GitStack+TortoiseGit 图形界面搭建Git环境
    [.net 面向对象程序设计进阶] (24) 团队开发利器(三)使用SVN多分支并行开发(下)
    [.net 面向对象程序设计进阶] (23) 团队开发利器(二)优秀的版本控制工具SVN(上)
    [.net 面向对象程序设计进阶] (22) 团队开发利器(一)简单易用的代码管理工具VSS
    [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦
  • 原文地址:https://www.cnblogs.com/nice0e3/p/13418404.html
Copyright © 2011-2022 走看看