• java编程思想第四版第七章总结


    1. 实现类的复用通常有两种方式

    • 组合:在新的类中产生现有类的对象
    • 继承:按照现有类的类型来创造新类

    2. 一个特殊的方法toString()

    • 在非基本类型的对象中, 都有toString()方法
    • 当编译器需要一个String而你只有一个对象时, toString()方法会被自动调用

    3. 父类方法的定义要求

    • 所有的方法都是public的.
      • 原因: 如果没有修饰符,则是包访问权限, 那么包以外的其他类继承了这个类, 依然不能访问这个父类的方法. 所以, 定义父类的公用方法需要时public的.
      • 为了继承一般的规则是: 成员变量是private的, 方法是public的.

    4. 基类初始化

    • java会在子类中自动调用父类的构造器
    • 父类如果没有默认构造器, 子类需要用super显示的调用父类的构造器. 而且调用父类构造器,必须是子类构造器要做的第一件事
      • 基类的默认构造器, 也要显示的调用父类的有参构造器

    5. 复用的第三种方式: 代理

    • 代理: java并不直接支持他, 它是继承和组合之间的一种中庸之道.
    • 无论我们使用的时组合, 还是继承. 都会暴露所有对象的成员方法
      • 组合:在类中new一个对象, 然后该对象的所有成员方法在这个类中就都可以被使用。
      • 继承:继承了父类, 那么父类的方法对这个子类来说, 更是完全可见的。
      • 这两种方法都会完全暴掠被使用的那个类的成员方法, 而有的时候, 我们不希望这样, 不想父类或者被调用类的成员方法被暴露在外, 就可以采用代理的方式, 如下例:太空船需要一个控制模块
        package net.mindview.reusing;
        
        public class SpaceShipControls {
            //velocity 速度
            void up(int velocity){}
            void down(int velocity){}
            void left(int velocity){}
            void right(int velocity){}
            void forward(int velocity){}
            void back(int velocity){}
            void turboBoost(int velocity){} //发动
            
        }

        构造一个太空船, 可以使用组合或者继承。 我们这里使用继承的方式构造。

        package net.mindview.reusing;
        
        public class SpaceShip extends SpaceShipControls {
            private String name;
            public SpaceShip(String name) {
                this.name = name;
            }
            
            @Override
            public String toString() {
                return name;
            }
            
            public static void main(String[] args) {
                SpaceShip protector = new SpaceShip("太空号");
                protector.up(2000);
            }
        
        }

        然而, SpaceShip并非一个真正的SpaceShipControls类型。太空船是太空船, 并不是太空控制器, 只是使用了太空控制器而已。更准确的说:SpaceShip包含SpaceShipControls。而且, 一旦继承, SpaceShipControls的所有方法都在SpaceShip中暴露了。这时我们可以使用代理方式来解决这个问题:

        package net.mindview.reusing;
        /**
         * 太空船代理
         */
        public class SpaceShipDelegation {
            String name;
            public SpaceShipControls controls = new SpaceShipControls();
            public SpaceShipDelegation(String name){
                this.name = name;
            }
            
            public void up(int velocity){
                controls.up(velocity);
            }
            void down(int velocity){
                controls.down(velocity);
            }
            void left(int velocity){
                controls.left(velocity);
            }
            void right(int velocity){
                controls.right(velocity);
            }
            void forward(int velocity){
                controls.forward(velocity);
            }
            void back(int velocity){
                controls.back(velocity);
            }
            void turboBoost(int velocity){//发动
                controls.turboBoost(velocity);
            }
            
            public static void main(String[] args) {
                SpaceShipDelegation protector = new SpaceShipDelegation("太空号2");
                protector.up(10000);
            }
        }

        这就是使用了代理。 主要关注上面的方法是如何传递给底层的controls对象的。 其接口与使用继承得到的接口一样了。 然而,我们使用代理时却得到了更多的控制力。

    6. 如何选择组合和继承

    • 组合通常是想在新类中使用现有类的功能而非他的接口。就是说,在新类中嵌入某个对象,让其实现所需要的功能,但新类的用户看到的只是为新类所定义的接口。而非锁嵌入对象的接口。为取得这个效果, 应该将现有类定义为private的。看下面的这个例子:
      package net.mindview.reusing;
      
      class Engine {
          public void start(){}
          public void rev(){}
          public void stop(){}
      }
      
      class Wheel {
          public void inflate(int psi){}
      }
      
      class Window{
          public void rollup(){}
          public 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[] wheels = new Wheel[4];
          public Door left = new Door(),right = new Door();
          public Car(){
              for(int i=0;i<4; i++){
                  wheels[i] = new Wheel();
              }
          }
          public static void main(String[] args) {
              Car car = new Car();
              car.left.window.rollup();
              car.wheels[0].inflate(72);
          }
      }

      这里面, 显示的car的组成部分, 所以使用的是组合的方式。 而如果有一个“交通工具”和car是什么关系呢? 显然他们车不是交通工具组成的。car确实一类交通工具, 所以,交通工具和car应该是继承的关系。

    • 向上转型
    package net.mindview.reusing;
    /**
     * 乐器
     */
    class Instrument {
        public void play(){}
        
        //用乐器弹奏曲调
        static void tune(Instrument i){
            i.play();
        }
    }
    
    //乐器的一种
    public class Wind extends Instrument{
        
        public static void main(String[] args) {
            Wind wind = new Wind();
            //使用wind弹奏曲调
            Instrument.tune(wind);
        }
    }
    • 上面的Instrument类中, 接收的Instrument的引用,在使用的时候, 我们可以将继承了Instrument的乐器传给tune方法。这称之为向上转型。
    • 到底什么时候使用组合, 什么时候使用继承呢?
      • 一个最清晰的判断就是, 问问自己,是否需要从新类向基类向上转型。如果需要转型, 那么就必须使用继承,否则就要好好想想了, 是否有使用集成的必要性。

    7.final关键字

    • final关键字的含义通常是“这是无法改变的
      • 作用于成员变量, 表示该变量编译时不可变。
      • 作用于成员变量, 和public static一起使用, 表示全局常量
      • 成员变量是对象类型时使用final表示, 对象的引用不可改变。 
    • 空白final
      • 所谓“空白final“指的是, 在定义final变量的时候不给他赋初始值, 而是在构造函数中为其赋值。这样就提供了更大的灵活性。使用方法如下所示:
        package net.mindview.reusing;
        
        class Poppet {
            private int i;
            Poppet(int i){
                this.i = i;
            }
        }
        
        public class BlankFinal {
            //定义的时候赋初始值
            private final int i = 0;
            //空白final
            private final int j;
            //空白final引用
            private final Poppet p;
            
            public BlankFinal(){
                j = 1;
                p = new Poppet(1);
            }
            
            public BlankFinal(int x){
                j = x;
                p = new Poppet(x);
            }
            
            public static void main(String[] args) {
                new BlankFinal();
                new BlankFinal(4);
            }
        }
    • 在参数列表中以声明的方式将参数指明为final
      • 如果final作用的参数是对象,则表明在方法中无法更改参数引用所指向的对象。
      • 如果final作用的是基本类型的参数, 则表示不可以改变传递过来的参数值。
        package net.mindview.reusing;
        
        class Gizmo{
            public void spin() {}
        }
        
        //final作用于方法参数
        public class FinalArguments {
            //final作用于对象类型的方法参数
            void with(final Gizmo g) {
                //在这里不可以对传递过来个g重新指向新的引用
                //g = new Gizmo();
            }
            
            void without(Gizmo g){
                g = new Gizmo();
                g.spin();
            }
            
            //final作用于基本类型的方法参数
            void f(final int i) {
                //在这里不可以对i重新赋值
                //i++;
            }
            
            int g(final int i) {
                return i+1;
            }
            
            public static void main(String[] args) {
                FinalArguments bf = new FinalArguments();
                bf.with(null);
                bf.without(null);
            }
        
        }
    • final方法
      • 方法被定义final,则不可以被继承类修改。也就是确保方法的行为保持不变,不可被覆盖。
    • final 类
      • 当某各类被定义为final时,不可被继承

      忠告:再设计类的时候, 将方法定义为final的,应该说是明智的。你可能会觉得,没人想要覆盖你的方法,但预见类是如何被复用是很困难的, 特别是对于一个通用类而言,更是如此。如果你将方法定义为final的, 可以防止其他程序员在项目中通过继承来复用你的类。

  • 相关阅读:
    Spring 声明式事务管理(11)
    Spring JdbcTemplate详解(9)
    Spring 基于xml配置方式的AOP(8)
    Spring AspectJ 切入点语法详解(7)
    Spring 基于Aspectj切面表达式(6)
    spring AOP 编程--AspectJ注解方式 (4)
    Spring 切面优先级(5)
    Spring 泛型依赖注入(3)
    python反射/自省 (目前是转载)
    flask_requirements
  • 原文地址:https://www.cnblogs.com/ITPower/p/8528378.html
Copyright © 2020-2023  润新知