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
    
    MON
    
  • 为枚举添加构造方法--无参构造方法和有参构造方法
    • 构造方法必须是私有的.

      package com.lxl;
      
      public class Weekend2 {
      
          //这时一个枚举内部类
      public enum Weekend {
      //枚举中每一项,实际上都是这个类的一个子类
      MON(), TUE(), 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 MON

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

    • 构造方法必须写在成员的下面.
    • 枚举的构造方法必须是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() {
    @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 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 亮灯时间: 

    结论

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

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(,); //现在我要通过反射获取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(, );
      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, );
      System.out.println(c);

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

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

   

张孝祥java高新技术 --- jkd1.5 新特性 -- 精华总结的更多相关文章

  1. 张孝祥java高新技术 --- jkd1.5 新特性

    1. 静态导入 import static java.lang.Math.max; 2. 可变参数 3. 自动装箱,拆箱 4. 枚举

  2. JAVA JDK1.5-1.9新特性

    1.51.自动装箱与拆箱:2.枚举(常用来设计单例模式)3.静态导入4.可变参数5.内省 1.61.Web服务元数据2.脚本语言支持3.JTable的排序和过滤4.更简单,更强大的JAX-WS5.轻量 ...

  3. Java 8 正式发布,新特性全搜罗

    经过2年半的努力.屡次的延期和9个里程碑版本,甲骨文的Java开发团队终于发布了Java 8正式版本. Java 8版本最大的改进就是Lambda表达式,其目的是使Java更易于为多核处理器编写代码: ...

  4. Java引入的一些新特性

    Java引入的一些新特性 Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本. Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程, ...

  5. 使用示例带你提前了解 Java 9 中的新特性

    使用示例带你提前了解 Java 9 中的新特性 转载来源:https://juejin.im/post/58c5e402128fe100603cc194 英文出处:https://www.journa ...

  6. Java学习之==>Java8 新特性详解

    一.简介 Java 8 已经发布很久了,很多报道表明Java 8 是一次重大的版本升级.Java 8是 Java 自 Java 5(发布于2004年)之后的最重要的版本.这个版本包含语言.编译器.库. ...

  7. JAVA笔记 之 JDK新特性

    JDK1.5新特性1.泛型(Generics) 为集合(collections)提供编译时类型安全,无需每刻从Collections取得一个对象就进行强制转换(cast) 2.增强的for循环(for ...

  8. Java系列 - 用Java8新特性进行Java开发太爽了

    本人博客文章网址:https://www.peretang.com/using-java8s-new-features-to-coding-is-awesome/ 前言 从开始写博客到现在已经过去3个 ...

  9. Java系列 – 用Java8新特性进行Java开发太爽了(续)

    本人博客文章网址:https://www.peretang.com/using-java8s-new-features-to-coding-is-awesome-2/ 前言 上周, 我们谈论了关于Ja ...

随机推荐

  1. Github 上热门的 Spring Boot 项目实战推荐

    最近经常被读者问到有没有 Spring Boot 实战项目可以学习,于是,我就去 Github 上找了 10 个我觉得还不错的实战项目.对于这些实战项目,有部分是比较适合 Spring Boot 刚入 ...

  2. 【Java基础】谈谈集合.CopyOnWriteArrayList

    目录 实现原理 遍历时不用加锁的原因 CopyOnWriteArrayLis的缺点 使用场景 总结 参考 本篇博客介绍CopyOnWriteArrayList类,读完本博客你将会了解: 什么是COW机 ...

  3. [案例分析] 政务云市场面临的复杂格局——重庆政务云模式的启示:多厂商竞争化、PaaS 化

    新闻背景: 2019 年 9 月底,重庆市大数据应用发展管理局发布政务云平台采购公告,预算金额为 5000 万元,以上 4 家入选. 最终项目被项目被阿里云.腾讯云.华为云.紫光云 4 家瓜分. 50 ...

  4. iOS cocoapods导入项目 出现 "___gxx_personality_v0", referenced from: 或者 clang: error: linker command failed with exit code 1 (use -v to see invocation) 错误

    今天想导入PNChart 编译的时候出现了  "___gxx_personality_v0", referenced from:  和 clang: error: linker c ...

  5. Java线程切换(一)

    (本文由言念小文原创,转载请注明出处) 一  前言有Android开发经验的同学都清楚,UI的更新必须在主线程中进行,且主线程不能被阻塞,否则系统ANR异常.我们往往做一些数据处理是耗时操作,必须要在 ...

  6. sublime设置 reindent 快捷键

    设置快捷键 使用快捷键 cmd + shift + p 打开控制面板 输入 key 关键词 点击进入 Key Bindings -User 添加如下代码 { "keys": [&q ...

  7. 变量 + 数据类型(数字 + 字符串)(day03整理)

    目录 一.上节课回顾 四 编程语言分类 (一) 机器语言 (二)汇编语言 (三) 高级语言 (四) 网络瓶颈效应 五.执行python程序两种方式 (一) 交互式(jupytre) (二) 命令行式( ...

  8. OptimalSolution(2)--二叉树问题(1)遍历与查找问题

    一.二叉树的按层打印与ZigZag打印 1.按层打印: 1 Level 1 : 1 / \ 2 3 Level 2 : 2 3 / / \ 4 5 6 Level 3 : 4 5 6 / \ 7 8 ...

  9. mysql笔记一

    普通操作, 查看数据库的大小,SELECT sum(DATA_LENGTH)+sum(INDEX_LENGTH) FROM information_schema.TABLES where TABLE_ ...

  10. AQL基本语法

    目录: 基本的CRUD 插入 检索 更新 删除 匹配文件 排序和限制 限制 排序 组合 图操作 地理位置查询 一.数据预览 本次使用的数据共有43条,每条数据包含姓氏.年龄.活动状态和特征等六个字段 ...