• 简单工厂模式(一)在源码中的应用 | Calendar 日历 | 源码浅析 | 使用总结 | 建造者模式


    一、Calendar 日历类


    java.util.Calendar 是从 JDK1.1 就推出的支持日期处理的工具类,它本身是一个抽象类,提供了许多可以进行日期操作的变量与方法。

    源码中的介绍【译】:

    Calendar类是一个抽象类,它提供了一些方法,用于在特定的时间瞬间和一组日历字段(例如年、月、月的第几天、小时等)之间进行转换,并用于操作日历字段(例如获取下周的日期)。时间上的一个瞬间可以用毫秒值表示,毫秒值是从1970年1月1日00:00:00.000 GMT(公历)开始的偏移量。

    该类还提供了额外的字段和方法,用于在包外实现具体的日历系统。这些字段和方法被定义为受保护。

    与其他区域设置敏感类一样,Calendar提供了一个类方法getInstance,用于获取这种类型的常用对象。Calendar的getInstance方法返回一个日历对象,其日历字段已用当前日期和时间初始化:

    Calendar中定义的表示时间的常量 private final static int(部分):

    属性描述
    YEAR1年,1970~至今
    MONTH2月,1~12
    DAY_OF_MONTH5本月的日,从0开始,0~30
    DAY_OF_YEAR6本年的天,从1月1开始,1~366
    DAY_OF_WEEK7本星期的日,从星期天为1开始,1~7
    HOUR10当前小时(12小时制)0~11
    HOUR_OF_DAY11当前小时(24小时制)0~23
    MINUTE12当前的分钟 0~59
    SECOND13当前的秒 0~59
    MILLISECOND14当前的毫秒 0~999

    更多表示时间的常量属性可通过 JDK 源码 java.util.Calendar 查看

    1.1 内部属性

    private long instant;		// 当前时间戳
    
    private int[] fields;		// Calendar.stamp[] (下半部分) 和 Calendar.fields[] (上半部分) 组合  	
    // 从最小用户戳 MINIMUM_USER_STAMP 开始的伪时间戳。 
    
    private int nextStamp;      // (计算用于指示已设置瞬间。)
    
    private int maxFieldIndex;  // 保留已设置字段的最大索引(不包括week和year)。
    private String type;		// 日历类型, 支持 gregory、iso8601、buddhist、japanese 四种类型
    private TimeZone zone;		// 时区
    private boolean lenient = true;	// 表示日历是否宽松 
    private Locale locale;	    // 表示日历语言, 默认为 en 
    private int firstDayOfWeek, minimalDaysInFirstWeek;
    // firstDayOfWeek 设置星期中第几天是第一天, 默认为0,即星期天
    // minimalDaysInFirstWeek 设置一年中第一周所需的最少天数, 默认是1
    // 1 -->  第一周定义为包含一年中第一个月的第一天
    // 7 --> 如果必须是一整周
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    1.2 设置时间属性值

    Calendar 类中一共提供了16个set方法,用于设置类的一些属性,这里列举几个常见的:

    public void set(int field, int value){}
    
    public final void set(int year, int month, int date){}
    
    public final void set(int year, int month, int date, int hourOfDay, int minute){}
    
    public final void set(int year, int month, int date, int hourOfDay, int minute,
                              int second){}
    public void setTimeZone(TimeZone value){}
    
    public void setFirstDayOfWeek(int value){}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    【例】修改当前的星期

    import java.util.Calendar;
    public class Demo {
        public static void println(Object o){ System.out.println(o); }
        public static void main(String[] args) {
            Calendar calendar = Calendar.getInstance();
            println("当前时间:" + calendar.getTime());
            println("当前星期: " + calendar.get(Calendar.DAY_OF_WEEK));
    
            println("修改星期为星期日(1)");
            calendar.set(Calendar.DAY_OF_WEEK, 1);
            println("修改后的时间: " + calendar.getTime());
            println("修改后的星期: " + calendar.get(Calendar.DAY_OF_WEEK));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    运行结果
    当前时间:Wed Jul 20 09:26:48 CST 2022
    当前星期: 4
    修改星期为星期日(1)
    修改后的时间: Sun Jul 17 09:26:48 CST 2022
    修改后的星期: 1

    可以看到,如果只修改其中一个属性,那么就会修改为最接近的时间属性,而其他属性不会发生变化。

    1.3 获取时间属性

    public int get(int field){} 
    
    • 1

    【例】获取当前时间的一些属性

    import java.util.Calendar;
    public class Demo {
        public static void println(Object o){ System.out.println(o); }
        public static void main(String[] args) {
            Calendar calendar = Calendar.getInstance();
            println("默认时区: " + calendar.getTimeZone());
            println("当前时间:" + calendar.getTime());
            println("日历类型: " + calendar.getCalendarType());
            println("当前年份: " + calendar.get(Calendar.YEAR));
            println("当前月份: " + calendar.get(Calendar.MONTH));
            println("当前日期: " + calendar.get(Calendar.DATE));
            println("当天是今年的第几个星期: " + calendar.get(Calendar.WEEK_OF_YEAR));
            println("当天是本月的第几个星期: " + calendar.get(Calendar.WEEK_OF_MONTH));
            println("当天是今年中的第几天: " + calendar.get(Calendar.DAY_OF_YEAR));
            println("当天是本月的第几天: " + calendar.get(Calendar.DAY_OF_MONTH));
            println("当前是当天的第几个小时: " + calendar.get(Calendar.HOUR_OF_DAY));
            println("当前是一小时的第几分钟: " + calendar.get(Calendar.MINUTE));
            println("当前是一分钟的第几秒: " + calendar.get(Calendar.SECOND));
            println("当前是一秒中的第几毫秒: " + calendar.get(Calendar.MILLISECOND));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    1.4 使用 Calander 计算时间

    【例1】 计算指定天数后的日期

    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    import java.util.Date;
    
    public class Demo {
        public static void println(Object o){ System.out.println(o); }
    
        public static Date after(int day){
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DAY_OF_WEEK, day);
            return calendar.getTime();
        }
        public static void main(String[] args) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy 年 MM 月 dd 日 HH:mm:ss");
            println("今天是: " + sdf.format(new Date()));
            println("25天后是: " + sdf.format(after(25)));
            println("100天后是: " + sdf.format(after(100)));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    运行结果
    今天是: 2022 年 07 月 20 日 09:43:15
    25天后是: 2022 年 08 月 14 日 09:43:15
    100天后是: 2022 年 10 月 28 日 09:43:15

    【例2】 计算指定月份过某天的日期

    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    import java.util.Date;
    
    public class Demo {
        public static void println(Object o){ System.out.println(o); }
    
        public static Date after(int month, int day){
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.MONTH, month);
            calendar.add(Calendar.DAY_OF_YEAR, day);
            return calendar.getTime();
        }
        public static void main(String[] args) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy 年 MM 月 dd 日 HH:mm:ss");
            println("今天是: " + sdf.format(new Date()));
            println("1月再过2天后是: " + sdf.format(after(1, 2)));
            println("3月再过10天后是: " + sdf.format(after(3, 10)));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    运行结果
    今天是: 2022 年 07 月 20 日 09:45:27
    1月再过2天后是: 2022 年 08 月 22 日 09:45:27
    3月再过10天后是: 2022 年 10 月 30 日 09:45:27

    【例3】 计算两个日期相差多少年、多少月、多少天
    参考资料:https://www.sojson.com/blog/260.html

    static DayCompare dayCompare(String format, String fromDate, String toDate){
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Calendar from = Calendar.getInstance();
        Calendar to = Calendar.getInstance();
        try {
            from.setTime(sdf.parse(fromDate));
            to.setTime(sdf.parse(toDate));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return dayCompare(from.getTime(), to.getTime());
    }
    
    static DayCompare dayCompare(Date fromDate, Date toDate){
        assert toDate.compareTo(fromDate) >= 0 : "【ERROR】 must be earlier than .";
        Calendar from = Calendar.getInstance();
        Calendar to = Calendar.getInstance();
        from.setTime(fromDate);
        to.setTime(toDate);
    
        // 计算年月日
        int fromYear = from.get(Calendar.YEAR);
        int fromMonth = from.get(Calendar.MONTH);
        int fromDay = from.get(Calendar.DAY_OF_MONTH);
    
        int toYear = to.get(Calendar.YEAR);
        int toMonth = to.get(Calendar.MONTH);
        int toDay = to.get(Calendar.DAY_OF_MONTH);
    
        // 计算差值
        int year = toYear - fromYear;
        int month = toMonth - fromMonth;
        int day = toDay - fromDay;
        // 处理负值
        if(day < 0){
            to.add(Calendar.MONTH, -1);
            day += to.getActualMaximum(Calendar.DAY_OF_MONTH);
            month--;
        }
        if(month < 0){
            to.add(Calendar.YEAR, -1);
            month += to.getActualMaximum(Calendar.MONTH);
            year--;
        }
        return DayCompare.builder().day(day).month(month).year(year).build();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    测试:

    public static void main(String[] args){
        String FORMAT = "yyyy-MM-dd";
        SimpleDateFormat sdf = new SimpleDateFormat(FORMAT);
        Date fromDate = new Date();
        String fromStr = "2022-07-20";
        String[] to = {"2022-08-20", "2022-09-10", "2023-05-30", "2024-01-01"};
        for (String toStr : to) {
            DayCompare dayCompare = dayCompare(FORMAT, fromStr, toStr);
            System.out.printf(
                "从[%s]到[%s], 相差: [%s] 年 [%s] 月 [%s] 日%n"
                , fromStr, toStr, dayCompare.getYear(), dayCompare.getMonth(), dayCompare.getDay());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    测试结果
    从[2022-07-20]到[2022-08-20], 相差: [0] 年 [1] 月 [0] 日
    从[2022-07-20]到[2022-09-10], 相差: [0] 年 [1] 月 [21] 日
    从[2022-07-20]到[2023-05-30], 相差: [0] 年 [9] 月 [10] 日
    从[2022-07-20]到[2024-01-01], 相差: [1] 年 [4] 月 [12] 日

    【例4】 计算两个日期各自相差多少年、多少月、多少天
    参考资料:https://www.sojson.com/blog/260.html

    static DayCompare dayCompare(String format, String fromDate, String toDate){
        assert toDate.compareTo(fromDate) >= 0 : "【ERROR】 must be earlier than .";
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Calendar from = Calendar.getInstance();
        Calendar to = Calendar.getInstance();
        try {
            from.setTime(sdf.parse(fromDate));
            to.setTime(sdf.parse(toDate));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return dayCompare(from.getTime(), to.getTime());
    }
    public static DayCompare dayCompare(Date fromDate, Date toDate){
        Calendar from = Calendar.getInstance();
        Calendar to = Calendar.getInstance();
        from.setTime(fromDate);
        to.setTime(toDate);
    
        int fromYear = from.get(Calendar.YEAR);
        int fromMonth = from.get(Calendar.MONTH);
        int fromDay = from.get(Calendar.DAY_OF_MONTH);
    
        int toYear = to.get(Calendar.YEAR);
        int toMonth = to.get(Calendar.MONTH);
        int toDay = to.get(Calendar.DAY_OF_MONTH);
    
        int year = toYear - fromYear;
        // 相差月份 = 目标的总月份 - 当前的总月份
        int month = (toYear * 12 + toMonth) - (fromYear * 12 + fromMonth);
    
        // 相差天数 = 时间戳 / 1000 / 3600 / 24
        int day = (int) ((to.getTimeInMillis() - from.getTimeInMillis()) / (1000 * 3600 * 24));
    
        return DayCompare.builder().day(day).month(month).year(year).build();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    测试

    public static void main(String[] args) {
        String FORMAT = "yyyy-MM-dd";
        String fromStr = "2022-07-20";
        String[] to = {"2022-08-20", "2022-09-10", "2023-05-30", "2024-01-01"};
        for (String toStr : to) {
            DayCompare dayCompare = dayCompare(FORMAT, fromStr, toStr);
            System.out.printf(
                "从[%s]到[%s], 相差了: [%s] 年, 相差了 [%s] 月 相差了 [%s] 日%n"
                , fromStr, toStr, dayCompare.getYear(), dayCompare.getMonth(), dayCompare.getDay());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    运行结果
    从[2022-07-20]到[2022-08-20], 相差了: [0] 年, 相差了 [1] 月 相差了 [31] 日
    从[2022-07-20]到[2022-09-10], 相差了: [0] 年, 相差了 [2] 月 相差了 [52] 日
    从[2022-07-20]到[2023-05-30], 相差了: [1] 年, 相差了 [10] 月 相差了 [314] 日
    从[2022-07-20]到[2024-01-01], 相差了: [2] 年, 相差了 [18] 月 相差了 [530] 日

    二、Calender 类中的设计模式


    首先根据 Calender 类定义可以看出,它是一个实现了可序列化、可克隆、可比较的抽象类,这意味这它不能直接通过 new 来创建对象,一般是通过其继承子类来创建对象,它的实现类有三个,而在 java.util 包里的有两个,分别是 GregorianCalendar.java 和 JapaneseImperialCalendar,这里是两种不同日历类型的实现,前者 Gregorian 是 格力高日历,是公历的全称,后者是 JapaneseImperial 日本用的日历,我们通过 getInstance() 获取的Calender的对象默认是公历,即 Gregorian 。

    public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {}
    
    • 1

    2.1 简单工厂模式

    我们创建 Calendar时,可以通过具体的实现类,除此之外,Calendar 提供了getInstace()直接获取实例。

    public static Calendar getInstance()
    {
        return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
    }
    
    • 1
    • 2
    • 3
    • 4

    如果是默认配置,那么则将调用 createCalendar() 方法,并传入默认的时区和地区

    private static Calendar createCalendar(TimeZone zone,
                                           Locale aLocale)
    {
        // 适配器模式 
        CalendarProvider provider =
            LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
            .getCalendarProvider();
        // 如果适配器提供了当前 TimeZone 和 Locale的 Calendar 实现,那么直接调用提供者的实例化方法
        if (provider != null) {
            try {
                return provider.getInstance(zone, aLocale);
            } catch (IllegalArgumentException iae) {
               // 返回默认的实例化
            }
        }
    
        Calendar cal = null;
        // 判断地区是否具有扩展名
        if (aLocale.hasExtensions()) {
            // 获取地区所在的日历类型
            String caltype = aLocale.getUnicodeLocaleType("ca");
            if (caltype != null) {
                switch (caltype) {
                    case "buddhist": // 佛教日历
                        cal = new BuddhistCalendar(zone, aLocale);
                        break;
                    case "japanese": // 日本日历
                        cal = new JapaneseImperialCalendar(zone, aLocale);
                        break;
                    case "gregory": // 公历
                        cal = new GregorianCalendar(zone, aLocale);
                        break;
                }
            }
        }
        if (cal == null) {
            // 如果没有指定之前的三个日历类型,则根据地区的语言和国家来判断日历类型
            if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
                cal = new BuddhistCalendar(zone, aLocale);
            } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
                       && aLocale.getCountry() == "JP") {
                cal = new JapaneseImperialCalendar(zone, aLocale);
            } else {
                // 其他情况一律返回公历
                cal = new GregorianCalendar(zone, aLocale);
            }
        }
        return cal;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    通过解读 Calendar 类的源码,我们可以发现,它getInstance() 创建实例的方法,本质上就是调用了内部定义的 createCalendar()方法,创建实例时主要根据时区和地区来判断,共有三种日历类型,佛教日历、日本日历和公历。

    比较有趣的是,在 createCalendar() 方法里用到了适配器模式,即 CalendarProvider,这里就不继续深入了,有个印象即可,在创建 Canlendar实例时,底层源码先从这个适配器提供者去获取实例,如果不为空就直接返回,否则就根据时区和地区来判断,返回相应的日历,默认则返回 GregorianCalendar 日历,即公历。

    为什么说这是一种简单工厂模式呢?因为 Calendar 抽象类里的createCalendar() 创建实例时,直接根据该方法传入的参数来返回对应的 Calendar 实现类,符合工厂模式的思想,此时,我们可以把 Calendar就看成一个工厂,它能根据时区和地区返回对应的实例,这似乎有点未卜先知的意思,在抽象类里直接调用了该抽象类自身的实现类。

    【使用案例】 简单工厂模式创建 Calendar 实例对象,并将年月日改为2008年的1月1日

    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, 2008);
        calendar.set(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        System.out.println(calendar.getTime());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.2 建造者模式

    java.util.Calendar类是从 JDK1.1 开始出现的,在后来的版本中也升级过,如果不查看官方文档,我们可以看看其源码实现,比如在之前 createCalendar()方法里,调用了适配器类的一个方法,返回了 CalendarProvider 类型的对象,而这个类正是 JDK1.8 才出现的,这表示 Calendar 目前的这种简单工厂模式的创建实例方式,在 JDK1.8 时进行过升级。
    通过源码结构图,我们可以看到 Calendar类里只有三个内部类,而且两个还是私有的,另一个唯一公开的则是 Builder
    在这里插入图片描述
    部分源码:

      /**
         * ...省略了很多注释内容
         * @since 1.8
         * @see Calendar#getInstance(TimeZone, Locale)
         * @see Calendar#fields
         */
    public static class Builder {
            private static final int NFIELDS = FIELD_COUNT + 1; // +1 for WEEK_YEAR
            private static final int WEEK_YEAR = FIELD_COUNT;
            private long instant;
            private int[] fields;
            private int nextStamp;
            private int maxFieldIndex;
            private String type;
            private TimeZone zone;
            private boolean lenient = true;
            private Locale locale;
            private int firstDayOfWeek, minimalDaysInFirstWeek;
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这个Builder 内部类 同样是在 JDK8 开始出现的,它和getInstance() 一样可以创建 Calendar 的实例对象,不过在创建时可以链式的设置一些属性。在设置属性时,其内部进行了一系列的初始化操作。要想了解它是如何初始化的,查看 build() 方法的源码即可:

    public Calendar build() {
        // 如果为空则初始化为默认
        if (locale == null) {
            locale = Locale.getDefault();
        }
        if (zone == null) {
            zone = TimeZone.getDefault();
        }
        Calendar cal;
        if (type == null) {
            type = locale.getUnicodeLocaleType("ca");
        }
        if (type == null) {
            if (locale.getCountry() == "TH"
                && locale.getLanguage() == "th") {
                type = "buddhist";
            } else {	// 其他情况直接使用 gregory 公历
                type = "gregory";
            }
        }
        // 判断类型
        switch (type) {
            case "gregory":
                cal = new GregorianCalendar(zone, locale, true);
                break;
            case "iso8601":
                GregorianCalendar gcal = new GregorianCalendar(zone, locale, true);
                // 使gcal成为序言公历
                gcal.setGregorianChange(new Date(Long.MIN_VALUE));
                // 周定义与ISO 8601兼容
                setWeekDefinition(MONDAY, 4);
                cal = gcal;
                break;
            case "buddhist":
                cal = new BuddhistCalendar(zone, locale);
                cal.clear();
                break;
            case "japanese":
                cal = new JapaneseImperialCalendar(zone, locale, true);
                break;
            default:
                throw new IllegalArgumentException("unknown calendar type: " + type);
        }
        cal.setLenient(lenient);
        if (firstDayOfWeek != 0) {
            cal.setFirstDayOfWeek(firstDayOfWeek);
            cal.setMinimalDaysInFirstWeek(minimalDaysInFirstWeek);
        }
        // 如果只是初始化,直接返回计算后的实例
        if (isInstantSet()) {
            cal.setTimeInMillis(instant);
            cal.complete();
            return cal;
        }
    
        if (fields != null) {
            boolean weekDate = isSet(WEEK_YEAR)
                && fields[WEEK_YEAR] > fields[YEAR];
            if (weekDate && !cal.isWeekDateSupported()) {
                // 不支持当前设置的星期日期, 直接抛异常
                throw new IllegalArgumentException("week date is unsupported by " + type);
            }
            //将字段从min stamp设置为 max stamp,以便字段解析在日历中起作用。
            for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
                for (int index = 0; index <= maxFieldIndex; index++) {
                   ...
                }
            }
    
            if (weekDate) {
               ...
            }
            cal.complete();
        }
        return cal;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    代码看起来比较长,但是逻辑并不难理解,相比 createInstance(),这种方式 Builder 的build()方式似乎更复杂, 主要是因为需要处理一些默认的没有设置的属性。

    【应用案例】 使用建造者模式创建 Calendar 实例对象,并将年月日改为2008年1月1日

    public static void main(String[] args) {
        Calendar calendar = new Calendar.Builder()
            .set(Calendar.YEAR, 2008)
            .set(Calendar.MONTH, 1)
            .set(Calendar.DAY_OF_MONTH, 1)
            .build();
        System.out.println(calendar.getTime());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    R语言偏相关和典型相关
    Supervisor监控Go程序
    MATLAB程序设计与应用 2.4 MATLAB常用内部函数
    高级IO(Linux)
    Oculus开发入门
    漏洞分析:MS14-058(CVE-2014-4113)
    设备上架与调试步骤项目篇
    Docker容器网络安全性最佳实践:防止容器间攻击
    Qt调用sqlserver的存储过程
    IService的query()和update()
  • 原文地址:https://blog.csdn.net/Unirithe/article/details/125891161