zoukankan      html  css  js  c++  java
  • 复合和继承

    这里举一个继承的初始化例子

    // reuse/Detergent.java
    // (c)2017 MindView LLC: see Copyright.txt
    // We make no guarantees that this code is fit for any purpose.
    // Visit http://OnJava8.com for more book information.
    // Inheritance syntax & properties
    
    class Cleanser {
      private String s = "Cleanser";
      public void append(String a) { s += a; }
      public void dilute() { append(" dilute()"); }
      public void apply() { append(" apply()"); }
      public void scrub() { append(" scrub()"); }
      @Override
      public String toString() { return s; }
      public static void main(String[] args) {
        Cleanser x = new Cleanser();
        x.dilute(); x.apply(); x.scrub();
        System.out.println(x);
      }
    }
    
    public class Detergent extends Cleanser {
      // Change a method:
      @Override
      public void scrub() {
        append(" Detergent.scrub()");
        super.scrub(); // Call base-class version
      }
      // Add methods to the interface:
      public void foam() { append(" foam()"); }
      // Test the new class:
      public static void main(String[] args) {
        Detergent x = new Detergent();
        x.dilute();
        x.apply();
        x.scrub();
        x.foam();
        System.out.println(x);
        System.out.println("Testing base class:");
        Cleanser.main(args);
      }
    }
    /* Output:
    Cleanser dilute() apply() Detergent.scrub() scrub()
    foam()
    Testing base class:
    Cleanser dilute() apply() scrub()
    */

    继承的类初始化就是 base类先初始化。方法调用的话就是派生类第一优先级。

    带参数的构造器

    // reuse/Chess.java
    // (c)2017 MindView LLC: see Copyright.txt
    // We make no guarantees that this code is fit for any purpose.
    // Visit http://OnJava8.com for more book information.
    // Inheritance, constructors and arguments
    
    class Game {
      Game(int i) {
        System.out.println("Game constructor");
      }
    }
    
    class BoardGame extends Game {
      BoardGame(int i) {
        super(i);
        System.out.println("BoardGame constructor");
      }
    }
    
    public class Chess extends BoardGame {
      Chess() {
        super(11);
        System.out.println("Chess constructor");
      }
      public static void main(String[] args) {
        Chess x = new Chess();
      }
    }
    /* Output:
    Game constructor
    BoardGame constructor
    Chess constructor
    */

    因为继承的类都有构造器,所以我们需要重写构造器,当我们写一个构造器。为什么我们写一个带参构造函数,却要super,因为派生类的基类也是带参的,初始化顺序又是基类先开始,如果我们不super给基类一个值,岂不是基类就没法初始化了吗。问题事基类不是先初始化,我们怎么先派生类的构造再传值,这是个问题,不过你可以理解为你如果想吃美食,您得先给厨师一个菜谱,因为厨师是美食的基类。当然也有无参的,你比如说学生和老师的知识(大概),我们不需要给老师一个知识单,他就会先备课初始化。。。

    委托,真的有人这么用吗?

    // reuse/SpaceShipDelegation.java
    // (c)2017 MindView LLC: see Copyright.txt
    // We make no guarantees that this code is fit for any purpose.
    // Visit http://OnJava8.com for more book information.
    
    public class SpaceShipDelegation {
      private String name;
      private SpaceShipControls controls =
        new SpaceShipControls();
      public SpaceShipDelegation(String name) {
        this.name = name;
      }
      // Delegated methods:
      public void back(int velocity) {
        controls.back(velocity);
      }
      public void down(int velocity) {
        controls.down(velocity);
      }
      public void forward(int velocity) {
        controls.forward(velocity);
      }
      public void left(int velocity) {
        controls.left(velocity);
      }
      public void right(int velocity) {
        controls.right(velocity);
      }
      public void turboBoost() {
        controls.turboBoost();
      }
      public void up(int velocity) {
        controls.up(velocity);
      }
      public static void main(String[] args) {
        SpaceShipDelegation protector =
          new SpaceShipDelegation("NSEA Protector");
        protector.forward(100);
      }
    }

    这样的好处就是不用将基类的所有方法都暴露在派生类中。

    组合和继承结合

    // reuse/PlaceSetting.java
    // (c)2017 MindView LLC: see Copyright.txt
    // We make no guarantees that this code is fit for any purpose.
    // Visit http://OnJava8.com for more book information.
    // Combining composition & inheritance
    
    class Plate {
      Plate(int i) {
        System.out.println("Plate constructor");
      }
    }
    
    class DinnerPlate extends Plate {
      DinnerPlate(int i) {
        super(i);
        System.out.println("DinnerPlate constructor");
      }
    }
    
    class Utensil {
      Utensil(int i) {
        System.out.println("Utensil constructor");
      }
    }
    
    class Spoon extends Utensil {
      Spoon(int i) {
        super(i);
        System.out.println("Spoon constructor");
      }
    }
    
    class Fork extends Utensil {
      Fork(int i) {
        super(i);
        System.out.println("Fork constructor");
      }
    }
    
    class Knife extends Utensil {
      Knife(int i) {
        super(i);
        System.out.println("Knife constructor");
      }
    }
    
    // A cultural way of doing something:
    class Custom {
      Custom(int i) {
        System.out.println("Custom constructor");
      }
    }
    
    public class PlaceSetting extends Custom {
      private Spoon sp;
      private Fork frk;
      private Knife kn;
      private DinnerPlate pl;
      public PlaceSetting(int i) {
        super(i + 1);
        sp = new Spoon(i + 2);
        frk = new Fork(i + 3);
        kn = new Knife(i + 4);
        pl = new DinnerPlate(i + 5);
        System.out.println("PlaceSetting constructor");
      }
      public static void main(String[] args) {
        PlaceSetting x = new PlaceSetting(9);
      }
    }
    /* Output:
    Custom constructor
    Utensil constructor
    Spoon constructor
    Utensil constructor
    Fork constructor
    Utensil constructor
    Knife constructor
    Plate constructor
    DinnerPlate constructor
    PlaceSetting constructor
    */
    // reuse/CADSystem.java
    // (c)2017 MindView LLC: see Copyright.txt
    // We make no guarantees that this code is fit for any purpose.
    // Visit http://OnJava8.com for more book information.
    // Ensuring proper cleanup
    // {java reuse.CADSystem}
    package reuse;
    
    class Shape {
      Shape(int i) {
        System.out.println("Shape constructor");
      }
      void dispose() {
        System.out.println("Shape dispose");
      }
    }
    
    class Circle extends Shape {
      Circle(int i) {
        super(i);
        System.out.println("Drawing Circle");
      }
      @Override
      void dispose() {
        System.out.println("Erasing Circle");
        super.dispose();
      }
    }
    
    class Triangle extends Shape {
      Triangle(int i) {
        super(i);
        System.out.println("Drawing Triangle");
      }
      @Override
      void dispose() {
        System.out.println("Erasing Triangle");
        super.dispose();
      }
    }
    
    class Line extends Shape {
      private int start, end;
      Line(int start, int end) {
        super(start);
        this.start = start;
        this.end = end;
        System.out.println(
          "Drawing Line: " + start + ", " + end);
      }
      @Override
      void dispose() {
        System.out.println(
          "Erasing Line: " + start + ", " + end);
        super.dispose();
      }
    }
    
    public class CADSystem extends Shape {
      private Circle c;
      private Triangle t;
      private Line[] lines = new Line[3];
      public CADSystem(int i) {
        super(i + 1);
        for(int j = 0; j < lines.length; j++)
          lines[j] = new Line(j, j*j);
        c = new Circle(1);
        t = new Triangle(1);
        System.out.println("Combined constructor");
      }
      @Override
      public void dispose() {
        System.out.println("CADSystem.dispose()");
        // The order of cleanup is the reverse
        // of the order of initialization:
        t.dispose();
        c.dispose();
        for(int i = lines.length - 1; i >= 0; i--)
          lines[i].dispose();
        super.dispose();
      }
      public static void main(String[] args) {
        CADSystem x = new CADSystem(47);
        try {
          // Code and exception handling...
        } finally {
          x.dispose();
        }
      }
    }
    /* Output:
    Shape constructor
    Shape constructor
    Drawing Line: 0, 0
    Shape constructor
    Drawing Line: 1, 1
    Shape constructor
    Drawing Line: 2, 4
    Shape constructor
    Drawing Circle
    Shape constructor
    Drawing Triangle
    Combined constructor
    CADSystem.dispose()
    Erasing Triangle
    Shape dispose
    Erasing Circle
    Shape dispose
    Erasing Line: 2, 4
    Shape dispose
    Erasing Line: 1, 1
    Shape dispose
    Erasing Line: 0, 0
    Shape dispose
    Shape dispose
    */

    这里有个小地方注意就是在new Line[]的时候,并没有创建对象,因为并没有对数组进行初始化,所以还是先走构造。这边一开始也被误解了。这里也还有个GUI的注意地方,我们用语言将进行计算机图形操作的时候,需要在使用完后dispose,典型的一个例子就是Graphics2D。

    重写构造

    // reuse/Hide.java
    // (c)2017 MindView LLC: see Copyright.txt
    // We make no guarantees that this code is fit for any purpose.
    // Visit http://OnJava8.com for more book information.
    // Overloading a base-class method name in a derived
    // class does not hide the base-class versions
    
    class Homer {
      char doh(char c) {
        System.out.println("doh(char)");
        return 'd';
      }
      float doh(float f) {
        System.out.println("doh(float)");
        return 1.0f;
      }
    }
    
    class Milhouse {}
    
    class Bart extends Homer {
      void doh(Milhouse m) {
        System.out.println("doh(Milhouse)");
      }
    }
    
    public class Hide {
      public static void main(String[] args) {
        Bart b = new Bart();
        b.doh(1);
        b.doh('x');
        b.doh(1.0f);
        b.doh(new Milhouse());
      }
    }
    /* Output:
    doh(float)
    doh(char)
    doh(float)
    doh(Milhouse)
    */

    这里是构造器都是无参的,所以只是个最普通的继承。

    组合和继承的选择,我个人比较喜欢组合,当你想在新类中包含一个已有类的功能时,使用组合,而非继承。也就是说,在新类中嵌入一个对象(通常是私有的),以实现其功能。新类的使用者看到的是你所定义的新类的接口,而非嵌入对象的接口。

    老生常谈的Car例子

    // reuse/Car.java
    // Composition with public objects
    class Engine {
        public void start() {}
        public void rev() {}
        public void stop() {}
    }
    
    class Wheel {
        public void inflate(int psi) {}
    }
    
    class Window {
        public void rollup() {}
        pubilc void rolldown() {}
    }
    
    class Door {
        public Window window = new Window();
    
        public void open() {}
        public void close() {}
    }
    
    public class Car {
        public Engine engine = new Engine();
        public Wheel[] wheel = new Wheel[4];
        public Door left = new Door(), right = new Door(); // 2-door
    
        public Car() {
            for (int i = 0; i < 4; i++) {
                wheel[i] = new Wheel();
            }
        }
    
        public static void main(String[] args) {
            Car car = new Car();
            car.left.window.rollup();
            car.wheel[0].inflate(72);
        }
    }

    说到继承就不得不谈向上转型

    B extends A

    A a = new B();

    为什么呢,你说一辆凯迪拉克B算不算一辆汽车A呢,同理奥迪C...这是纯面向对象的理解。

    final的用法,常量,参数,方法,比较简单举几个不常见的例子

    空白final

    // reuse/BlankFinal.java
    // "Blank" final fields
    class Poppet {
        private int i;
    
        Poppet(int ii) {
            i = ii;
        }
    }
    
    public class BlankFinal {
        private final int i = 0; // Initialized final
        private final int j; // Blank final
        private final Poppet p; // Blank final reference
        // Blank finals MUST be initialized in constructor
        public BlankFinal() {
            j = 1; // Initialize blank final
            p = new Poppet(1); // Init blank final reference
        }
    
        public BlankFinal(int x) {
            j = x; // Initialize blank final
            p = new Poppet(x); // Init blank final reference
        }
    
        public static void main(String[] args) {
            new BlankFinal();
            new BlankFinal(47);
        }
    }

    虽然第一时间没有初始化final变量,但是必须要在运行时初始化,否则就出问题了。

    final方法虽然有个内嵌调用,但是现代java是禁止这么用的,一般来讲我们只对明确不让派生类重写的方法上final锁

    一个容易误解的初始化

    // reuse/Beetle.java
    // The full process of initialization
    class Insect {
        private int i = 9;
        protected int j;
    
        Insect() {
            System.out.println("i = " + i + ", j = " + j);
            j = 39;
        }
    
        private static int x1 = printInit("static Insect.x1 initialized");
    
        static int printInit(String s) {
            System.out.println(s);
            return 47;
        }
    }
    
    public class Beetle extends Insect {
        private int k = printInit("Beetle.k.initialized");
    
        public Beetle() {
            System.out.println("k = " + k);
            System.out.println("j = " + j);
        }
    
        private static int x2 = printInit("static Beetle.x2 initialized");
    
        public static void main(String[] args) {
            System.out.println("Beetle constructor");
            Beetle b = new Beetle();
        }
    }

    static Insect.x1 initialized
    static Beetle.x2 initialized
    Beetle constructor
    i = 9, j = 0
    Beetle.k initialized
    k = 47
    j = 39
     

    为什么不是先走sout?因为需要先加载,加载的目的主要事static这类的要提前处理,要不怎么不创建就调用static类的数据?这个我一开始也陷入了传统的顺序结构的误区了。

    一个没有高级趣味的人。 email:hushui502@gmail.com
  • 相关阅读:
    ZooKeeper学习第六期---ZooKeeper机制架构
    ZooKeeper学习第五期--ZooKeeper管理分布式环境中的数据
    ZooKeeper学习第四期---构建ZooKeeper应用
    ZooKeeper学习第三期---Zookeeper命令操作
    ZooKeeper学习第二期--ZooKeeper安装配置
    ZooKeeper学习第一期---Zookeeper简单介绍
    配置yum,nc,telnet
    Hadoop日记系列目录
    mysql主从复制、读写分离
    分布式事物
  • 原文地址:https://www.cnblogs.com/CherryTab/p/11929842.html
Copyright © 2011-2022 走看看