zoukankan      html  css  js  c++  java
  • java 抽象类与接口

    http://www.cnblogs.com/wenruo/p/5366052.html

    抽象类

    当基类比较抽象的时候一些函数就无法实现。比如动物类,你可以知道猫如何叫狗如何叫,但你无法说清动物如何叫,于是对于比较抽象的基类,其中的一些方法可以只声明,不实现。这样的方法叫做抽象方法,含有抽象方法的类叫做抽象类。抽象方法和抽象类需要用关键字abstract来标识。

    含有抽象方法的类的对象是不安全的,因此java中不允许创建抽象类的对象。

    对于一个不含有抽象方法的类也可以设为抽象类,这样,就能限制这个类不能产生对象了。

    接口

    当一个类足够抽象,将不会实现任何方法。接口(interface)是一个完全抽象的类,不提供任何具体实现。

    接口同类一样有public和默认(包)访问权限。

    接口中的域默认是static和final的

    接口中的方法默认是public的,所以继承的时候注意实现的时候要声明为public。

    接口的用处和抽象类看起来并不相同。比如上面说的抽象基类动物类,动物会叫,继承类包括猫狗。但是汽车,电视都会“叫”,却并不合适继承,这时一个“声音”接口就比较合适。

    接口的多重继承

    Because an interface has no implementation at all—that is, there is no storage associated with an interface—there’s nothing to prevent many interfaces from being combined.

    一个类可以实现多个接口,却只能继承一个类。接口可以继承多个接口。

    1、一个类实现两个接口而两个接口的存在完全相同的方法时,实现一个就可以了。

    interface A { void f(); }
    interface B { void f(); }
    
    class C implements A, B {
        @Override
        public void f() {
            System.out.println("f()");
        }    
    }
    
    public class Test {
        public static void main(String[] args) {
            new C().f();
        }
    }

    2、如果两个方法名字相同参数列表不同,会实现重载。

    interface A { void f(int x); }
    interface B { void f(); }
    
    class C implements A, B {
        @Override
        public void f() {
            System.out.println("f()");
        }
        @Override
        public void f(int x) {
            System.out.println("f(" + x + ")");
        }    
    }
    
    public class Test {
        public static void main(String[] args) {
            C c = new C();
            c.f(); c.f(1);
        }
    }

    3、如果参数列表相同,返回值不同,将会报错。

    4、实现接口的方法也可以是继承自父类

    interface A { void f(); }
    interface B { void f(); }
    
    class C {
        public void f() {
            System.out.println("f()");
        }
    }
    
    class D extends C implements A, B {
    }
    
    public class Test {
        public static void main(String[] args) {
            D d = new D();
            d.f();
        }
    }

     也就是对于一个实现接口的类,只要类中有接口所有函数的实现就可以。

    但是注意,未通过implements实现接口,只有相同函数没有用的。

    interface A { void f(); }
    class B {
        public void f(){};
    }
    public class Test {
        public static void main(String[] args) {
            //A a = new B(); <-- Type mismatch: cannot convert from B to A
        }
    }

    C++中存在菱形继承的问题。

    class A{};

    class B:public A{};

    class C:public A{};

    class D:public B,public C();

    这样会出现一些问题,因为D中有两个A,因此调用A内的成员是编译器会分不清是哪个。【记得大概是这样吧。。C++无能。。。

     java虽然不存在类的多重继承,但是存在接口多重继承。考虑下面的代码

    interface F { void f(); }
    interface S1 extends F { void s1(); }
    interface S2 extends F { void s2(); }
    interface T extends S1, S2 { void t(); }
    
    class Fo implements T {
        public void f() { System.out.println("f"); }
        public void s1() { System.out.println("s1"); }
        public void s2() { System.out.println("s2"); }
        public void t() { System.out.println("t"); }    
    }
    
    public class Diamond {
        public static void main(String[] args) {
            Fo fo = new Fo(); fo.f();
        }
    }

    其实由上面的讨论也可以想到这完全不会有问题。因为java的接口根本不提供具体实现。这也是Java设计单一继承和接口的原因。

     接口中的域

    定义时即要初始化,可以是被非常量的表达式初始化。

    interface F {
        int i = 0;//int i; <- error
        int j = i;
        int k = j * 10;
        void f(); 
    }

    这些域不是接口的一部分,它们的值被存储在该接口的静态存储区域内。

     

    配适器设计模式

    某个现有的类的接口和需求不同,可以通过实现某个接口达到要求。(因为《thinking in java》提到所以稍微看了一下。。理解浅显。。

    一般都是用插头举例,如果插头型号不合适就在外面在套一个转换插头实现工作。(原谅我是在写不出符合逻辑的例子。。。。。

    class A {
        public void solveByA() {}
    }
    interface B {
        public void solveByB();
    }
    class C {
        public static void solve(B b) {
            b.solveByB();
        }
    }
    /* 想要在solve中调用A明显是不行的,于是加一个配适器给A,让它套一个B的外壳   */
    class AImplementsB extends A implements B {
        @Override
        public void solveByB() {
            solveByA();
        }
    }
    /* 由此可以想到对于所有的类  只要我们能对它实现接口B 就可以使该类作用于solve 提高了复用性 */
    public class AdapterDemo {
        public static void main(String[] args) {
            C.solve(new AImplementsB());
        }
    }

    举个实际的用处。Scanner的构造器接受的是一个Readable接口,也就是说只要一个类实现了Readable接口,就可以使Scanner作用于它。

    Readable接口中只有一个方法public int read(CharBuffer arg0);在read内部将输入内容添加到CharBuffer参数中,返回添加或者没有输入返回-1。

    import java.nio.CharBuffer;
    import java.util.Random;
    import java.util.Scanner;
    
    public class RandomWords implements Readable {
        private static Random rand = new Random();
        private static final char[] capitals = 
                "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm".toCharArray();
        private int count = 0;
        public RandomWords(int count) {
            this.count = count;
        }
        @Override
        public int read(CharBuffer cb) {
            if (count-- == 0) return -1;
            cb.append(capitals[rand.nextInt(capitals.length)]);
            cb.append(" ");
            return 1;
        }
        public static void main(String[] args) {
            Scanner in = new Scanner(new RandomWords(10));
            while (in.hasNext()) {
                System.out.print(in.next() + ",");
            }
            in.close();
        }
    }

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

    private 或 public 或 默认访问权限 都可以。

    没弄明白什么用ing。

  • 相关阅读:
    面试时面试官想要听到什么答案(关于一些vue的问题)
    Redis主从复制以及主从复制原理
    当面试官问你:如何进行性能优化?
    swoole通往大神之路——swoole任务中心说明及进程任务架构搭建
    全局句柄表
    句柄表(私有句柄表)
    关于VAD的两种内存隐藏方式
    通过修改VAD属性破除锁页机制
    R3环申请内存时页面保护与_MMVAD_FLAGS.Protection位的对应关系
    利用内存锁定技术防止CE修改
  • 原文地址:https://www.cnblogs.com/wenruo/p/5366052.html
Copyright © 2011-2022 走看看