zoukankan      html  css  js  c++  java
  • 第9章-接口

    Think in java 读书笔记

    pikzas

    2019.07.31

    第九章 接口

    知识点

    1.抽象类和抽象方法

    1.1.抽象类的设计目的

    抽象类的主要功能是为了在实现多态过程中,避免错误的创建了父类实例对象而提供的语法支持。
    在标准的多态实践中,父类仅仅是为子类提供了一个模板,子类提供具体实现。父类也是一个普通类的情形下,创建出一个父类的对象是没有意义的。他没有具体的方法实现。

    1.2.什么是抽象方法

    abstract void f(); 仅有声明而没有方法体的方法。

    1.3.什么是抽象类

    class 前有abstract修饰的类为抽象类

    1.4.抽象类的特点

    • 抽象类不能直接实例化,必须通过子类向上转型得到
    • 如果一个类中含有一个或多个抽象方法,那么该类必须为抽象类
    • 如果一个类是抽象类,其中也可以一个抽象方法也没有(可以有任意多个普通的方法)
    • 抽象方法的修饰符不能是private的,那样禁止override,和抽象类的设计初衷相违背
    • 抽象类中也可定义属性,属性的用法和普通类一致。
    • 继承抽象类的子类中,如果实现了父类所有的抽象方法,那么他可以申明为一个普通类(也可以依旧申明为一个抽象类,甚至还可添加新的抽象方法),也可以声明为抽象类,但是如果尚有抽象方法未完全实现,那么该类必须也是抽象类。

    2.接口

    接口是抽象方法的一种极端形式,要求所有的方法都是抽象方法

    2.1.接口的设计目的

    除了为了更方便的实现多态,更为了突破JAVA的单继承限制,实现一种隐式的多继承(内部类),因为接口可以多实现

    2.2.什么是接口

    用interface关键字而不是class关键字标明的类,其中可以有属性,只能有抽象方法(提供方法名,确定参数列表和返回值),却不给任何实现。

    2.3.接口的特点

    • 接口类上的修饰符可以是public和default,和普通类的修饰符一样效果。
    • 接口中的属性默认是public static final的,所以可以直接通过接口点属性拿来用,也不能对属性作出修改。而且不能添加访问修饰符private protected或者是default,会提示编译错误。
    • 接口中的方法默认也是public abstract的,不写修饰符也默认是public abstract的,不能添加private protected default这些修饰符。

    3.JAVA中的多继承

    JAVA允许一个类单继承自一个实体类或者是抽象类,但是可以多实现多个接口。

    public class Actor {
        public void fight(){
            System.out.println("do nothing");
        };
    }
    
    public interface CanFight {
        void fight();
    }
    
    public interface CanFly {
        void fly();
    }
    
    public interface CanSwim {
        void swim();
    }
    
    public class ActActor extends Actor implements CanFight,CanFly,CanSwim {
        @Override
        public void fly() {
    
        }
        @Override
        public void swim() {
    
        }
    }
    
    public class Test {
        public static void a(Actor actor) {
            actor.fight();
        }
    
        public static void b(CanFight canFight) {
            canFight.fight();
        }
    
        public static void c(CanFly canFly) {
            canFly.fly();
        }
    
        public static void d(CanSwim canSwim ) {
            canSwim.swim();
        }
    
        public static void main(String[] args) {
            ActActor actActor = new ActActor();
            a(actActor);
            b(actActor);
            c(actActor);
            d(actActor);
        }
    }
    
    

    上面的例子中注意fight()方法并没有在ActActor中做实现,这是因为Actor类中已有实现
    如果将Actor类中的fight()方法改为非public的,那么ActActor就相当于未对CanFight中的fight()方法做实现,此时编译会出错。
    如果Actor类中没有fight()方法,但是Actor继承自Human类,Human类中有fight()方法,那么此时也是可以的。

    此处示例也说明了接口的两个用处

    • 可以将子类向上转型为不同的基类,代码更灵活
    • 接口也不能实例化,从编译器就可以防止误用。

    4.接口与接口,接口与类之间的关系

    类可以实现接口,接口可以继承接口并且可以多继承接口

    
    public interface Monster {
        void menace();
    }
    
    /**
     * 接口之间用继承
     */
    public interface DangerousMonster extends Monster {
        void destory();
    }
    
    public interface Lethal {
        void kill();
    }
    
    /**
     * 接口可以多继承接口,只要用逗号隔开就行。
     */
    public interface Vampire extends DangerousMonster,Lethal {
        void drinkBlood();
    }
    
    
    public class VeryBadVampire implements Vampire {
        @Override
        public void drinkBlood() {
    
        }
    
        @Override
        public void destory() {
    
        }
    
        @Override
        public void kill() {
    
        }
    
        @Override
        public void menace() {
    
        }
    }
    
    

    5.组合接口时候可能发生的名字冲突

    前面讲过如果某个类的父类和其实现的接口都有同一个方法的时候,这个类可以不用再对该方法做实现。
    但是如果多个接口,其中都有同一个方法,导致重载与覆盖同时发生,这时候可能就会发生错误。

    
    public interface InterfaceA {
        void f();
    }
    
    public class Father {
        public int f(){}
    }
    
    /**
    * 如下写法的子类会提示编译错误,因为方法必须override,但是又会与父类的方法冲突(同名,同参数列表,就返回值不同,不是overload,所以会提示编译错误)
    */
    public class Son extends Father implements InterfaceA {
    
    }
    

    6.接口中的属性都默认是public static final的(不需要特别写明,默认就是)

    接口中的属性如果是基本数据类型,他们都要大写,都是编译器常量,可以拿来替代枚举使用
    接口中定义的域是不能为空final的,但是可以被非常量表达式初始化
    这些属性不是接口的一部分,他们的值会存储在接口的静态存储区域内

    import java.util.Random;
    
    public interface RandVals {
        Random RAND = new Random(47);
        int RANDOM_INT = RAND.nextInt(10);
        long RANDOM_LONG = RAND.nextLong() * 10;
    }
    

    7.接口的嵌套

    接口可以嵌套在类或者其他接口中

    • 接口嵌套在类内部,除了public,包访问权限之外,还多了private访问权限
    package com.pikzas.thinkinjava.chapter09.demo6;
    public class OuterClass {
        //1.类内部接口可以是包访问权限
        interface B{
            void f();
        }
    
        //1.1. 对应的实现类可以是public的
        public class BImpl implements B{
            public void f(){}
        }
        //1.2. 对应的实现类可以是private的
        private class BImpl2 implements B{
            public void f(){}
        }
        //1.3. 对应的实现类可以是默认访问权限的
        class BImpl3 implements B{
            public void f() {
    
            }
        }
    
        //2. 类内部接口可以是包访问权限
        public interface C{
            void f();
        }
    
        //2.1. 对应的实现类可以是public的
        public class CImpl implements C{
            public void f(){}
        }
        //2.2. 对应的实现类可以是private的
        private class CImpl2 implements C{
            public void f(){}
        }
        //2.3. 对应的实现类可以是默认访问权限的
        class CImpl3 implements C{
            public void f() {}
        }
    
        //2. 类内部接口可以是private的
        private interface D{
            void f();
        }
    
        //2.1. 对应的实现类可以是public的
        public class DImpl implements D{
            public void f(){}
        }
        //2.2. 对应的实现类可以是private的
        private class DImpl2 implements D{
            public void f(){}
        }
        //2.3. 对应的实现类可以是默认访问权限的
        class DImpl3 implements D{
            public void f() {}
        }
    
    }
    
    package com.pikzas.thinkinjava.chapter09.demo6;
    
    public class TestClass {
        public static void main(String[] args) {
            OuterClass outerClass = new OuterClass();
            OuterClass.B b1 =  outerClass.new BImpl();
    //        OuterClass.B b2 =  outerClass.new BImpl2(); BImpl2是private的,访问不到,编译报错
            OuterClass.B b3 =  outerClass.new BImpl3(); //BImpl3是包访问权限,可以访问到
    
            OuterClass.C c1 = outerClass.new CImpl();
    //        OuterClass.C c2 = outerClass.new CImpl2();  CImpl2是private的,访问不到,编译报错
            OuterClass.C c3 = outerClass.new CImpl3();
    
    //        OuterClass.D D接口是private的 访问不到
        }
    }
    
    package com.pikzas.thinkinjava.chapter09;
    
    import com.pikzas.thinkinjava.chapter09.demo6.OuterClass;
    
    public class TestOuter {
        public static void main(String[] args) {
            OuterClass outerClass = new OuterClass();
    //        OuterClass.B b3 =  outerClass.new BImpl3();  访问不到B接口,因为不和他在同一个包路径下
            OuterClass.C c1 =  outerClass.new CImpl();
    //        OuterClass.C c2 =  outerClass.new CImpl2();  // 访问不到CImpl2实现,因为是private的
    //        OuterClass.C c3 =  outerClass.new CImpl3();  // 访问不到CImpl3实现,因为不和他在同一个包路径下
    //        OuterClass.C c3 =  outerClass.new CImpl3();  // 访问不到CImpl3实现,因为不和他在同一个包路径下
    //        OuterClass.D d =  outerClass.new DImpl();    // 访问不到D接口,因为D接口是private的
        }
    }
    
    
    
    • 接口嵌套在接口内部,内部的接口默认就是public的,如要标明访问权限,也只能写public
    public class TestInterface {
    
    }
    class EImp implements E{
        public void g(){}
    }
    class EGImp implements E.G{
        public void f(){}
    }
    
    class EImp2 implements E{
        @Override
        public void g() {}
        class EG implements E.G{
            @Override
            public void f() {}
        }
    }
    

    8.接口在工厂方法的应用

    public interface Game {
        int play();
    }
    
    public class Dice implements Game {
        Random random = new Random(47);
        @Override
        public int play() {
            return (random.nextInt(6)+1);
        }
    }
    
    public class CoinFlip implements Game {
        Random random = new Random(47);
        @Override
        public int play() {
            int rand = random.nextInt(10);
            return rand > 5? 1:-1;
        }
    }
    
    public interface GameFactory {
        Game getGame();
    }
    
    public class DiceFactory implements GameFactory {
        @Override
        public Game getGame() {
            return new Dice();
        }
    }
    
    public class CoinFlipFactory implements GameFactory {
        @Override
        public Game getGame() {
            return new CoinFlip();
        }
    }
    
    public class StartGame {
        public static void play(GameFactory gameFactory) {
           Game game = gameFactory.getGame();
            System.out.println(game.getClass().getSimpleName() + "---"+game.play());
        }
        public static void main(String[] args) {
            for(int i = 0 ; i < 5 ; i++){
                play(new DiceFactory());
                play(new CoinFlipFactory());
                System.out.println("-----");
            }
        }
    }
    
  • 相关阅读:
    软件构架实践_阅读笔记04(-11)
    软件构架实践_阅读笔记03(7-9)
    Tsinsen-A1488 : 魔法波【高斯消元+异或方程组】
    Tsinsen-1487:分配游戏【树状数组】
    Tsinsen-1486:树【Trie树 + 点分治】
    Splay初步【bzoj1503】
    Treap初步
    [BZOJ3207] 花神的嘲讽计划Ⅰ
    可持久化Trie树初步
    可持久化线段树初步
  • 原文地址:https://www.cnblogs.com/Pikzas/p/11306424.html
Copyright © 2011-2022 走看看