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。

  • 相关阅读:
    Effective Java 19 Use interfaces only to define types
    Effective Java 18 Prefer interfaces to abstract classes
    Effective Java 17 Design and document for inheritance or else prohibit it
    Effective Java 16 Favor composition over inheritance
    Effective Java 15 Minimize mutability
    Effective Java 14 In public classes, use accessor methods, not public fields
    Effective Java 13 Minimize the accessibility of classes and members
    Effective Java 12 Consider implementing Comparable
    sencha touch SortableList 的使用
    sencha touch dataview 中添加 button 等复杂布局并添加监听事件
  • 原文地址:https://www.cnblogs.com/wenruo/p/5366052.html
Copyright © 2011-2022 走看看