zoukankan      html  css  js  c++  java
  • Java编程思想(四) —— 复用类

    复用类这标题刚开始很难懂,后面专门去看了书的英文原版,其实标题是reusing classes,重新使用类,其实复用就是“利用现成的东西”的意思,其实实现的两种方法就是java中经常听到的——组合和继承。

    (1)组合

    has-a的作用。

    1. public class TV {  
    2.    Show show;  
    3.    public String toString(){  
    4.      return "showgirl";  
    5.    }  
    6. }  
    7.   
    8. class Show{  
    9. }  
    public class TV {
       Show show;
       public String toString(){
         return "showgirl";
       }
    }
    
    class Show{
    }


    提一下toString方法,当你需要String而你是一个对象的时候,编译器会调用对象的toString方法。

    TV里有Show,现在的show没有初始化,为null,不能调用show的方法。

    组合的作用强大,以面向对象看,假如你在造一个Car类,那么你可以用组合轻易的将Glass,Light,Engine等等的Car这些部件组合起来。

    (2)继承

    is-a

    1. package com.myown.iaiti;  
    2.   
    3. public class Father {  
    4.      public int i;  
    5.      void get(){  
    6.          System.out.println("father");  
    7.      }  
    8. }  
    9.   
    10. package son;  
    11. import com.myown.iaiti.*;  
    12.   
    13. public class Son extends Father{  
    14.         Father f = new Father();  
    15.         int j = f.i;  
    16.         Son son = new Son();  
    17.         son.get();  
    18.     }  
    19.       
    20.     public void get(){  
    21.         super.get();  
    22.         System.out.println("son");  
    23.     }  
    24. }  
    25.    
    package com.myown.iaiti;
    
    public class Father {
         public int i;
         void get(){
             System.out.println("father");
         }
    }
    
    package son;
    import com.myown.iaiti.*;
    
    public class Son extends Father{
            Father f = new Father();
            int j = f.i;
            Son son = new Son();
            son.get();
        }
        
        public void get(){
            super.get();
            System.out.println("son");
        }
    }
     

    这里有个包访问权限的问题,假如没有加public的时候,默认是包内成员访问,不同包访问,即Son中的Father成员访问get方法是不可见的。而public的话是可见的,所以i访问得到。

    private部分是不能继承,属于父类私有,而public的部分,将继承,需要修改的方法,可以进行重写。要添加的属性可以单独添加。

    而且继承的方法,如果原本的father的public方法重写之后没将public加上,会有Cannot reduce the visibility of the inherited method from Father,也就是不能减少父类中继承方法的可见性。super指的是父类,即Father。

    还有一点是,其实java中所有的类都隐式地继承了Object类。Object是父类,其他类是子类

    老外喜欢讲为基类。子类也叫导出类或者派生类。

    (3)代理

    设计模式里面有个比较难懂的——代理模式,作者讲的很有趣,代理是组合和继承的中庸之道。

    1. package son;  
    2. class Father{  
    3.     public void get(){  
    4.         System.out.println("father");  
    5.     }  
    6. }  
    7. public class Son extends Father{  
    8.     public static void main(String[] args) {  
    9.         Father f = new Father();  
    10.         f.get();  
    11.     }  
    12. }  
    13.   
    14. class FatherProxy{  
    15.     private Father f = new Father();  
    16.     public void get(){  
    17.         f.get();  
    18.     }  
    19. }  
    package son;
    class Father{
        public void get(){
            System.out.println("father");
        }
    }
    public class Son extends Father{
        public static void main(String[] args) {
            Father f = new Father();
            f.get();
        }
    }
    
    class FatherProxy{
        private Father f = new Father();
        public void get(){
            f.get();
        }
    }


    像直接把Father当做成员,那么father的方法就暴露给这个类了,那我们可以使用FatherProxy这样的代理类,我自己定义好get方法是怎么拿的,我自己知道是调用father的get方法,但是使用我这个代理的人不知道,我只告诉他你要用就用代理的get的方法就可以了。封装性就体现出来了。上面只是随便敲的一个简单例子。

    (4)重写和重载

    1. class Father{  
    2.     public void get(String s){  
    3.         System.out.println("father");  
    4.     }  
    5.       
    6.     public void get(boolean b){  
    7.         System.out.println("boolean");  
    8.     }  
    9. }  
    10. public class Son extends Father{  
    11.     @Override  
    12.     public void get(String s){  
    13.         System.out.println("father");  
    14.     }  
    15.       
    16.    // @Override //会有错误提示 因为父类没有该方法,不是重写  
    17.     public void get(int i ){  
    18.         System.out.println("sonint");  
    19.     }  
    20.       
    21.     public static void main(String[] args) {  
    22.         Son s = new Son();  
    23.         s.get("d");  
    24.         s.get(false);  
    25.         s.get(1);  
    26.     }  
    27. }  
    class Father{
        public void get(String s){
            System.out.println("father");
        }
        
        public void get(boolean b){
            System.out.println("boolean");
        }
    }
    public class Son extends Father{
        @Override
        public void get(String s){
            System.out.println("father");
        }
        
       // @Override //会有错误提示 因为父类没有该方法,不是重写
        public void get(int i ){
            System.out.println("sonint");
        }
        
        public static void main(String[] args) {
            Son s = new Son();
            s.get("d");
            s.get(false);
            s.get(1);
        }
    }


    重写是重新覆盖父类的方法,如果没有重写或者重载,那么子类调用一个子类没有的方法时,其实是调用父类。

    重载是同样的方法名,但参数名称不同,为了防止你错误的进行重载可以加上@Override标签,那样会提示你并没有重写方法。

    (5)protected

    Java编程思想(三) —— 访问权限的控制
    在前面一篇提前写了,因为之前没讲继承的东西。

    可以简单将protected看成父类给儿子继承的遗产,其他非继承类不能访问。

    (6)final关键字

    加上final关键字的基本类型,表示这个变量初始化后不会改变。类似c的define,你希望一个变量在这个程序里就是这个值不需要改变。就可以用final。

    1. public class Son{  
    2.     int  age = 2;  
    3.     public static void main(String[] args) {  
    4.           
    5.         final int i = 1;  
    6.         // i = 2;  值不能再改变  
    7.         final Son son = new Son();  
    8.         //  son = new Son();  
    9.         //The final local variable son cannot be assigned.   
    10.         //It must be blank and not using a compound assignment  
    11.         //final修饰的局部变量son不能被分配,必须为空或者不要再次分配  
    12.           
    13.         son.age = 4;  
    14.         //虽然引用恒定不变,但是,对象本身却可以改变。  
    15.     }  
    16.       
    17.     void  change(final int c){  
    18.         // c= this.age; 无法赋予新值 因为值只有在方法传参决定   对象引用和这个类似  
    19.         //age ++;       无法改变  
    20.     }  
    21. }  
    public class Son{
        int  age = 2;
        public static void main(String[] args) {
            
            final int i = 1;
            // i = 2;  值不能再改变
            final Son son = new Son();
            //  son = new Son();
            //The final local variable son cannot be assigned. 
            //It must be blank and not using a compound assignment
            //final修饰的局部变量son不能被分配,必须为空或者不要再次分配
            
            son.age = 4;
            //虽然引用恒定不变,但是,对象本身却可以改变。
        }
        
        void  change(final int c){
            // c= this.age; 无法赋予新值 因为值只有在方法传参决定   对象引用和这个类似
            //age ++;       无法改变
        }
    }

    static本来是静态初始化,和final一起用就是占据了一块不能改变的存储空间。

    static final即编译期常量,常量名按照c的常量命名传统,全部用大写字母,单词之间用下划线分开。

    1. static final VALUE_ONE = 1;  
    static final VALUE_ONE = 1;

    final修饰方法时

    1. public class Print {  
    2.     final void cannotprint(){  
    3.         System.out.println(1);  
    4.     }  
    5. }  
    6.   
    7. public class PrintSon extends Print{  
    8.     //void cannotprint(){}  
    9.     //无法重写 因为被final修饰了  
    10.       
    11.     public static void main(String[] args) {  
    12.         PrintSon ps = new PrintSon();  
    13.         ps.cannotprint();  
    14.     }  
    15. }  
    public class Print {
        final void cannotprint(){
            System.out.println(1);
        }
    }
    
    public class PrintSon extends Print{
        //void cannotprint(){}
        //无法重写 因为被final修饰了
        
        public static void main(String[] args) {
            PrintSon ps = new PrintSon();
            ps.cannotprint();
        }
    }


    可以看成父类要求子类必须继承的不可修改财产(祖传)。private隐式地指定为final,因为private根本就不给你继承。这比给你继承但不能修改还更私有。

    顺便将权限理清。

    public,公共财产,不止是子类,其他类也可以用。

    final,祖传珍宝,留给子类,但不允许修改。

    private,父类私有财产,不会给子类继承。

    protected,父类专门留给子类的财产,其他人不能用它。


    当final修饰的是类的时候,是为了让这个类不会被继承。

    (7)继承和初始化

    这里的顺序问题是一个很有趣的问题。看例子。

    1. class GrandFather{  
    2.     private static int i = print();  
    3.     private static int print(){  
    4.         System.out.println("g");  
    5.         return 1;  
    6.     }  
    7. }  
    8. class Father extends GrandFather{  
    9.     private static int i = print();  
    10.     private static int print(){  
    11.         System.out.println("f");  
    12.         return 1;  
    13.     }  
    14. }  
    15. public class Son extends Father{  
    16.     private static int i = print();  
    17.     private static int print(){  
    18.         System.out.println("s");  
    19.         return 1;  
    20.     }  
    21.     public static void main(String[] args) {  
    22.         System.out.println("first");  
    23.     }  
    24. }  
    class GrandFather{
        private static int i = print();
        private static int print(){
            System.out.println("g");
            return 1;
        }
    }
    class Father extends GrandFather{
        private static int i = print();
        private static int print(){
            System.out.println("f");
            return 1;
        }
    }
    public class Son extends Father{
        private static int i = print();
        private static int print(){
            System.out.println("s");
            return 1;
        }
        public static void main(String[] args) {
            System.out.println("first");
        }
    }


    打印的结果是first吗?错了。

    虽然执行的是main方法,但是看到son这个需要静态初始化的i没有,结果是s,first吗?

    这还有初始化的问题,son是继承father,那么编译器会加载father,并初始化i,那father继承grandfather,那么编译器会去加载grandfather,类似递归。

    那最后最先初始化的是grandfather的i。

    所以最后的结果是:g,f,s,first。

    至于这章提到的向上转型,是和多态联系着的,所以放到下一篇来讲。

    面向对象的三大基本特性之一 —— Java编程思想(五) —— 多态。

  • 相关阅读:
    面向过程
    生成器
    迭代器
    装饰器
    函数及嵌套
    字符编码与文件操作
    linux_ssh
    LNMP
    BZOJ 3238: [Ahoi2013]差异
    BZOJ 3998: [TJOI2015]弦论
  • 原文地址:https://www.cnblogs.com/jizhuan/p/5165416.html
Copyright © 2011-2022 走看看