• 张孝祥java高新技术 --- jkd1.5 新特性 -- 精华总结


    1. 抽象方法的使用

      如果一个方法中大量出现if语句, 那么, 就应该考虑使用抽象来处理. 如下例:

    package com.lxl;
    
    public class Weekend {
        
        
        //周日
        public static Weekend SUN = new Weekend();
        //周一
        public static Weekend MON = new Weekend();
        //周二
        public static Weekend TUE = new Weekend();
        //周三
        public static Weekend WES = new Weekend();
        //周四
        public static Weekend TUR = new Weekend();
        //周五
        public static Weekend FRI = new Weekend();
        //周六
        public static Weekend SAR = new Weekend();
        
        /*
         * 有一个if语句用来判断, 当前日期的下一个日期是星期几. 
         */
        public Weekend nextDay(Weekend day){
            if(day == SUN) {
                return MON;
            }else if(day == MON){
                return TUE;
            }else if(day == TUE){
                return WES;
            }else if(day == WES){
                return TUR;
            }else if(day == TUR){
                return FRI;
            }else if(day == FRI){
                return SAR;
            }else if(day == SAR){
                return SUN;
            }else{
                return null;
            }
        }
        
        public static void main(String[] args) {
            Weekend sun = Weekend.SUN;
            sun.nextDay(sun);
            
            
        }
    
    }

      在这个方法中, 我定义了一周七天. 如果我想知道明天是星期几, 那么我需要写一个if语句, 大量的 if语句来判断, 明天是星期几. 当程序中出现大量的if语句的时候, 就要想到这样的程序不完美, 需要优化. 比如, 我现在有星期八了, 那么你出来需要添加星期八, 还需要修改if语句. 

      使用抽象来代替if语句.是一个好办法.

      修改后的方法如下: 定义了一个抽象方法nextDay

    package com.lxl;
    
    public abstract class Weekend {
        
        
        //周日
        public static Weekend SUN = new Weekend(){
            @Override
            public Weekend nextDay(Weekend day) {
                return MON;
            }
        };
        //周一
        public static Weekend MON = new Weekend(){
            @Override
            public Weekend nextDay(Weekend day) {
                return TUE;
            }
        };
        //周二
        public static Weekend TUE = new Weekend(){
            @Override
            public Weekend nextDay(Weekend day) {
                return WES;
            }
        };
        //周三
        public static Weekend WES = new Weekend(){
            @Override
            public Weekend nextDay(Weekend day) {
                return TUR;
            }
        };
        //周四
        public static Weekend TUR = new Weekend(){
            @Override
            public Weekend nextDay(Weekend day) {
                return FRI;
            }
        };
        //周五
        public static Weekend FRI = new Weekend(){
            @Override
            public Weekend nextDay(Weekend day) {
                return SAR;
            }
        };
        //周六
        public static Weekend SAR = new Weekend(){
            @Override
            public Weekend nextDay(Weekend day) {
                return SUN;
            }
        };
        
        /*
         * 当有大量的if语句时, 要考虑如何优化
         */
        /*public Weekend nextDay(Weekend day){
            if(day == SUN) {
                return MON;
            }else if(day == MON){
                return TUE;
            }else if(day == TUE){
                return WES;
            }else if(day == WES){
                return TUR;
            }else if(day == TUR){
                return FRI;
            }else if(day == FRI){
                return SAR;
            }else if(day == SAR){
                return SUN;
            }else{
                return null;
            }
        }*/
        
        //定义一个抽象方法
        public abstract Weekend nextDay(Weekend day);
        
        public static void main(String[] args) {
            Weekend sun = Weekend.SUN;
            sun.nextDay(sun);
            
            
        }
    
    }

      采用抽象方法定义nextDay, 就是可以将if..else转换为独立的类.

      这样做的好处是, 一旦有了星期八, 那么只需要定义星期八这个常量就好了, 不用修改其他地方.

     2. 枚举 

    • 枚举类的定义
      package com.lxl;
      
      public class Weekend2 {
          
          //这时一个枚举内部类
          public enum Weekend {
              //枚举中每一项,实际上都是这个类的一个子类
              MON, TUE, WEN, THI, FRI, SAT, SUN
          }
          
          public static void main(String[] args) {
              
              //1. 选择的时候, 只能在枚举范围内进行选择
              Weekend day = Weekend.MON;
          }
      }

      重点:1. 枚举类中每一个元素都是这个类的子类. 下面的操作更能说明这一点. 2. 枚举类对可选的对象做了范围限定

    • 枚举类中可用的方法
      package com.lxl;
      
      public class Weekend2 {
          
          //这时一个枚举内部类
          public enum Weekend {
              //枚举中每一项,实际上都是这个类的一个子类
              MON, TUE, WEN, THI, FRI, SAT, SUN
          }
          
          public static void main(String[] args) {
              
              //1. 选择的时候, 只能在枚举范围内进行选择
              Weekend day = Weekend.MON;
              //2. 可用的方法
              // 打印名字
              System.out.println(day.name());
              // 序号
              System.out.println(day.ordinal());
              // 将某个字符串转换为枚举类型
              System.out.println(day.valueOf("MON"));
              //获取枚举列表
              System.out.println(Weekend.values().length);
          }
      }

      运行结果

      MON
      0
      MON
      7
    • 为枚举添加构造方法--无参构造方法和有参构造方法
      • 构造方法必须是私有的.
        package com.lxl;
        
        public class Weekend2 {
            
            //这时一个枚举内部类
            public enum Weekend {
                //枚举中每一项,实际上都是这个类的一个子类
                MON(), TUE(1), WEN, THI, FRI, SAT, SUN;
                
                //3. 为枚举添加构造方法
                private Weekend(){System.out.println("first");}
                
                private Weekend(int i){System.out.println("second");}
                
                
            }
            
            public static void main(String[] args) {
                
                //1. 选择的时候, 只能在枚举范围内进行选择
                Weekend day = Weekend.MON;
                //2. 可用的方法
                // 打印名字
                System.out.println(day.name());
                // 序号
                System.out.println(day.ordinal());
                // 将某个字符串转换为枚举类型
                System.out.println(day.valueOf("MON"));
                //获取枚举列表
                System.out.println(Weekend.values().length);
            }
            
        
        }

        输出结果

        first
        second
        first
        first
        first
        first
        first
        MON
        0
        MON
        7

        从结果中可以看出一下几点

      • 构造方法必须写在成员的下面.
      • 枚举的构造方法必须是private的
      • 枚举的每一个成员都是枚举的子类
      • 只要调用枚举类, 就会初始化枚举子类, 子类又会调用父类的构造方法.
      • 每一个枚举类的子类默认调用的是枚举类的无参构造方法.
      • 调用枚举的有参构造方法,可以使用"子类名(参数)"的形式
    • 为枚举添加抽象方法, 下面是一个交通信号灯亮的顺序枚举类
      package com.lxl;
      
      public class EnumTest3 {
          //交通信号灯
          public enum TrafficLamp{
              RED {
                  @Override
                  public TrafficLamp nextLamp() {
                      return YELLOW;
                  }
              }, 
              YELLOW {
                  @Override
                  public TrafficLamp nextLamp() {
                      return BLUE;
                  }
              }, 
              BLUE {
                  @Override
                  public TrafficLamp nextLamp() {
                      return RED;
                  }
              };
              
              //下一个亮的信号灯--抽象方法
              public abstract TrafficLamp nextLamp();
              
          } 
          public static void main(String[] args) {
              TrafficLamp red = TrafficLamp.RED;
              System.out.println(red.nextLamp());
          }
      
      }

      运行结果:

      YELLOW

      从这个demo可以得出以下结论:

      • 枚举中可以定义抽象方法
      • 进一步说明, 每一个枚举的成员都是枚举的子类, 子类必须实现父类的抽象方法. 
    • 为上一个交通信号灯案例添加时间. 这个时间我们可以放在构造方法中.
      package com.lxl;
      
      public class EnumTest3 {
          //交通信号灯
          public enum TrafficLamp{
              RED(30) {
                  @Override
                  public TrafficLamp nextLamp() {
                      return YELLOW;
                  }
              }, 
              YELLOW(45) {
                  @Override
                  public TrafficLamp nextLamp() {
                      return BLUE;
                  }
              }, 
              BLUE(5) {
                  @Override
                  public TrafficLamp nextLamp() {
                      return RED;
                  }
              };
              
              //下一个亮的信号灯--抽象方法
              public abstract TrafficLamp nextLamp();
              
              public int time;
              
              private TrafficLamp(int time){
                  this.time = time;
              }

      public String toString(){
                    return this.name() + " 亮灯时间: " + time;
                }

      
          } 
          public static void main(String[] args) {
              TrafficLamp red = TrafficLamp.RED;
              System.out.println(red.nextLamp());
          }
      
      }

      运行结果

      YELLOW 亮灯时间: 45

      结论

      • 子类调用父类的构造方法。
      • 每一个枚举成员都是父类的一个子类。
    • 如果枚举类中只有一个元素, 那么这个枚举可以看做一个单例的实现方法。

     3. 反射

    • 内存中同一个类只有一份字节码
      String str = "abc";
      Class cla1 = str.getClass();
      Class cla2 = String.class;
      Class cla3 = Class.forName("java.lang.String");
      /*
       * 同一份字节码, 在内存中只有一份
       */
      System.out.println(cla1 == cla2 );
      System.out.println(cla2 == cla3);
      
      /*
       * 判断,一个类型是否是基本类型. 基本类型有9个: 8个基本类型+void.
       * int long short float double char byte boolean 
       */
      //String 不是基本类型
      System.out.println(str.getClass().isPrimitive());
      //int 是基本类型
      System.out.println(int.class.isPrimitive());
      //Integer 不是基本类型
      System.out.println(Integer.class.isPrimitive());
      //int 和 Integer 是不同的类型, 他们在内存中的字节码是不同的
      System.out.println(int.class == Integer.class);
      //Integer.Type方法返回的是基本类型int的字节码
      System.out.println(Integer.TYPE == int.class);
      //数组也是一个Class对象
      //int[]数组不是基本类型
      System.out.println(int[].class.isPrimitive());
      //int[] 数组是数组么? 是的
      System.out.println(int[].class.isArray());
    • 如何得到字节码对应的实例对象: 有三种方法
      • Class.class(); 类名.class();
      • new Date().getClass()
      • Class.forName("类的全限定名")
    •  九个预定义的class实例对象
      • 参考Class类的isPrimitive方法.
      • 8个基本类型+void
      • int , long, short, double, float, char, byte, bollean, 以及void
    •  Constructor类
      //获得String这个类的所有个构造方法
      Constructor<?>[] cons = String.class.getConstructors();
      //获得String的指定构造方法: String(StringBuffer s){}
      //下面表示只接受一个参数StringBuffer类型的构造方法
      Constructor<?> con = String.class.getConstructor(StringBuffer.class);
      //将构造方法实例化
      Object o = con.newInstance(new StringBuffer("abc"));
      System.out.println(o);

      我记得 之前说过, 得到Class类以后, 可以调用Class.newInstances()

      /*
       * 实例化
       */
      Class cla4 = Class.forName("java.lang.String");
      //我们可以直接使用Class的newInstance()方法. 但注意这个方法是无参的构造方法.
      Object o4 = cla4.newInstance();
      /*
       * 如果调用一个类的有参构造方法呢?
       * 使用构造器. 如下操作, 就是调用了含有一个StringBuffer类型参数的构造方法
       * 这样调用的就是有参的构造方法
       */
      Constructor<?> con4 = cla4.getConstructor(StringBuffer.class);
      Object o44 = con4.newInstance(new StringBuffer("aaa"));
      System.out.println(o44);
    • Field 
      • 如何获取共有字段
        public class RefelectPoint {
            private int x;
            public int y;
            public RefelectPoint(int x, int y){
                this.x = x;
                this.y =y;
            }
        }

        下面的代码在main方法中执行

        /**
         * 字段
         * 如何获取共有字段
         */
        RefelectPoint rp = new RefelectPoint(4,6);
        
        //现在我要通过反射获取rp对象中的x字段的值和y字段的值
        Field fieldy = rp.getClass().getField("y");
        
        /*
         * 注意: 这里的fieldx表示的是字段, 他不代表任何值. 因为RefelectPoint有很多歌对象, 
         * fieldx仅表示这些对象中的指定字段. 那到底是哪个对象的值呢? 也就是如何获取这个值呢?
         * 
         * 注意, 使用这种方法只能获得public域的参数
         */
        System.out.println(fieldy.get(rp));
      • 如何获取私有字段
        /*
         * 那如何获取private类型的参数呢
         * 如果直接获取会报告异常:   java.lang.NoSuchFieldException: x
         * 
         * 我们可以通过对象的getDeclareField("x")来获取.
         * 这个时候, 我们调用这个方法, 返回的依然是一个异常 :modifiers "private"
         * 这时我们要调用setAccessible(true)强制通知,告诉编译器我可以获取这个私有属性
         */
        
        Field fieldx = rp.getClass().getDeclaredField("x");
        fieldx.setAccessible(true);
        System.out.println(fieldx.get(rp));

        练习: 将一个对象中的所有String类型的成员变量的值中的b改成a

        /**
         * 将一个对象中的所有String类型的成员变量的值中的b改成a
         * 思路: 
         * 1. 获取所有的String类型的成员
         * 2. 获取成员对应的值
         * 3. 通过正则表达式或者replaceAll方法对字符串进行替换
         */
        Class cla5 = RefelectPoint.class;
        Constructor<?> cons5 = cla5.getConstructor(int.class, int.class);
        Object o5 = cons5.newInstance(5, 10);
        Field[] f5s = cla5.getFields();
        for(Field f5: f5s){
            //获取Field的类型
            Class<?> t5 = f5.getType();
            //判断是否是String类型,只需看他的字节码是否是同一份就可以了.
            if(t5 == String.class){
                String v5 = (String) f5.get(o5);
                v5 = v5.replaceAll("b", "a");
                f5.set(o5, v5);
                System.out.println(v5);
            }
        }

        运行结果:

        aall
        aasketaall
        itcas 
    •  Method
      • 如何获取一个类的指定方法呢
        /**
         * 方法反射
         */
        String str1 = "abc";
        //第一步:通过反射调用指定方法
        Method method = String.class.getMethod("charAt", int.class);
        //第二步: 执行方法
        char c = (char) method.invoke(str1, 2);
        System.out.println(c);                

        通过反射调用getMethod()方法,在执行invoke方法即可。 如果想获取所有的方法, 可以使用getMethods()方法。

      • 如果在使用Method.invoke(参数1,参数2): 如果第一个参数是null,则表示这是调用的一个静态方法。

       

  • 相关阅读:
    二叉树计算叶子节点的计算问题
    操作系统中有关读者写者问题
    Java中关于CountDownLatch的使用
    Java中关于CyclicBarrier的使用
    将毫秒 换算成(天 时 分 秒 毫秒)
    数据库訪问技术之JDBC
    窥探开发人员与用户
    Cocos2d-x游戏开发之lua编辑器 Sublime 搭建,集成cocos2dLuaApi和自有类
    高速排序,归并排序,堆排序python实现
    svn 批量加入没有加入版本号控制的文件命令
  • 原文地址:https://www.cnblogs.com/ITPower/p/8717741.html
Copyright © 2020-2023  润新知