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. Python3的编码整理总结

    python3在内存中是用unicode编码方式存储的,所以不能直接储存和传输,要转化为其他编码进行储存和传输. 字符串通过编码转换成字节码,字节码通过解码成为字符串 encode:str --> ...

  2. vue-router之to属性赋值

    to属性赋值 <!-- html --> <div id="app"> <router-link to="/bj/朝阳区"> ...

  3. 《深入理解Java虚拟机》-----第10章 程序编译与代码优化-早期(编译期)优化

    概述 Java语言的“编译期”其实是一段“不确定”的操作过程,因为它可能是指一个前端编译器(其实叫“编译器的前端”更准确一些)把*.java文件转变成*.class文件的过程;也可能是指虚拟机的后端运 ...

  4. WebSocket学习简书

    1.什么是Websocket? WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议. 2.单工,半双工和全双工通信? 在单工通信中,通信的信道是单向的,发送端 ...

  5. python编程系列---tcp客户端的简单实现

    实现流程如下: """ TCP客户端实现流程1. 创建一个tcp 客户端对象2. 与服务端建立连接3. 通过tcp socket 收发数据4. 关闭连接 关闭tcp &q ...

  6. Spring Boot项目中如何定制拦截器

    本文首发于个人网站:Spring Boot项目中如何定制拦截器 Servlet 过滤器属于Servlet API,和Spring关系不大.除了使用过滤器包装web请求,Spring MVC还提供Han ...

  7. 玩转u8g2 OLED库,一篇就够(分篇)

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  8. java.lang.OutOfMemoryError GC overhead limit exceeded原因分析及解决方案

    最近一个上线运行良好的项目出现用户无法登录或者执行某个操作时,有卡顿现象.查看了日志,出现了大量的java.lang.OutOfMemoryError: GC overhead limit excee ...

  9. Linux配置部署_新手向(五)——Docker的安装与使用

    前言 最近还是在考虑Linux下net core的部署问题,还是发现了很多麻烦的问题,这里还是继续把需要使用的东西部署介绍下吧. Docker 其实对于Docker我也是一星半点儿,了解的不够深入,大 ...

  10. PHP5底层原理之垃圾回收机制

    概念 垃圾回收机制 是一种内存动态分配的方案,它会自动释放程序不再使用的已分配的内存块. 垃圾回收机制 可以让程序员不必过分关心程序内存分配,从而将更多的精力投入到业务逻辑. 与之相关的一个概念,内存 ...