1. 程式人生 > >Java8特性總結(三)介面方法,註解,日期,Base64

Java8特性總結(三)介面方法,註解,日期,Base64

導航

前言

這幾個知識點相對內容較少,放到一篇文章裡介紹。

介面方法

介面方法如何寫,大家都知道了,很簡單。
談到介面方法,那就難免不談談他的繼承關係。

多個介面

Java是可以實現多個介面的,那這個時候實現的多個介面有同名,同參的介面方法會發生什麼情況呢。
接下來我們就通過程式碼示例,展開分析一下。

介面IA,
兩個子介面IB1,IB2,
實現了IB1和IB2的類CC,
繼承了IB1,IB2的介面IC, 大致就是3層關係。

程式碼:

public interface IA
{
    default void print(String str)
    {
        System.out.println(this
.getClass()+".print() IA "+str); } } public interface IB1 extends IA { } public interface IB2 extends IA { } public interface IC extends IB1,IB2 { } public class C implements IB1, IB2 { public static void main(String[] args) { new C().print("test"); } }

1:IA的預設方法print(),IB1,IB2沒有Override print().
這種情況一切正常,沒有任何問題,最後執行C的輸出是:

class my.test.java8.second.interfaceMethod1.C.print() IA test

2:IA定義預設方法print(),IB1 Override了print().

public interface IB1 extends IA
{
    default void print(String str)
    {
        System.out.println(this.getClass()+".print() IB1 "+str);
    }
}

這種情況也是正常,編譯器也沒有報任何錯誤,最後是C的輸出

class my.test
.java8.second.interfaceMethod1.C.print() IB1 test

發現輸出呼叫的是IB1的預設方法。

可以得出結論,實現類只在乎離自己最近的那個介面的預設方法。

3:IA定義了預設方法print(),IB1和IB2分別Override。

public interface IB2 extends IA
{
    default void print(String str)
    {
        System.out.println(this.getClass()+".print() IB2 "+str);
    }
}

出事了,IC和C都報錯了,因為編譯器已經混亂了,不知道該呼叫IB1的方法還是IB2的方法。
Java給出的解決問題的辦法就是每個子類Override這個方法,告訴編譯器,我不呼叫別人的,我呼叫我自己的方法。

為C類新增函式,類似的也給IC新增。

@Override
public void print(String str)
{
    IB1.super.print(str);
    IB2.super.print(str);
}

編譯過去了,看看輸出吧

class my.test.java8.second.interfaceMethod1.C.print() IB1 test
class my.test.java8.second.interfaceMethod1.C.print() IB2 test

我們分別呼叫了兩個父介面的預設方法。
當然我們也可以在方法中自己實現。

父類和介面

接下來就是繼承類,實現介面,介面和類有同名,同參函式的情況了。

介面IA;
類CA;
抽象類ACA;
類CB1繼承CA,實現IA;
類CB2繼承ACA,實現IA。

public interface IA
{
    default void print(String str)
    {
        System.out.println(this.getClass()+".print() IA  "+str);
    }
}
public class CA
{
    public void print(String str)
    {
        System.out.println(this.getClass()+".print() CA  "+str);
    }
}
public abstract class ACA
{
    public abstract void print(String str);
}
public class CB1 extends CA implements IA
{
    public static void main(String[] args)
    {
        new CB1().print("hello");
    }
}
public class CB2 extends ACA implements IA
{

}

CB2直接報錯。必須要Override print()方法。
修改CB2

public class CB2 extends ACA implements IA
{

    @Override
    public void print(String str)
    {       
    }
}

執行CB1.輸出如下

class my.test.java8.second.interfaceMethod2.CB1.print() CA  hello

呼叫的是父類的方法。

可以得出結論,父類的方法優先於介面。

註解的變化

註解的變化還是比較小,增加了可以反覆添加註解的功能。
通過程式碼來看看如何實現。
在一個註解中使用另外一個註解陣列,這個以前版本是支援的

@Retention(RetentionPolicy.RUNTIME)
public @interface Student
{
    String value();
}

@Retention(RetentionPolicy.RUNTIME)
public @interface Classes
{
    Student[] value();
}

實際使用情況

@Classes({@Student("李壯"),@Student("王靜")})
public class MyClasses
{

}

現在的版本可以寫成這樣。和上面的寫法是等價的。

@Student("李壯")
@Student("王靜")
public class MyClasses
{

}

編譯器報錯了!提示我們@Student不是一個repeatabel的註解。
@Repeatable這個註解的註釋說的很清楚,value必須是當前註解的註解集合。
如下所示:

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Classes.class)
public @interface Student
{
    String value();
}

改成這樣錯誤消失。

列印測試一下結果。

public static void main(String[] args)
{
    Student student=MyClasses.class.getAnnotation(Student.class);
    System.out.println(student);

    Student[] students=MyClasses.class.getAnnotationsByType(Student.class);
    Arrays.asList(students).stream().forEach(e->System.out.println(e.value()));

    Classes classes=MyClasses.class.getDeclaredAnnotation(Classes.class);
    Arrays.asList(classes.value()).stream().forEach(e->System.out.println(e.value()));

}    

可以看出現在這種重複的註解方式,實際上是隱式的包裝成Classes。
這個知識點使用較少,也就Mark一下,以備不時之需。

Base64

Base64編碼引入了標準包裡,使用更方便了。
以前版本使用Base64一般會用第三方的類。
比如我常用apache 的 commmon-codec.jar裡Base64進行編碼和解碼。

String base64String = "I am  base64";  
byte[] result = Base64.encodeBase64(base64String.getBytes());

當然還有一些其他的。
現在直接使用Java自己的,而且據說也是效率最高的。

import java.util.Base64;

public class Base64Test
{

    public static void main(String[] args) throws Exception
    {
        String base64String = "I am  base64";  
        String encoded=Base64.getEncoder().encodeToString(base64String.getBytes("UTF-8"));
        String end=new String(Base64.getDecoder().decode(encoded),"UTF-8");
        System.out.println(encoded);
        System.out.println(end);
    }

}

日期

新的時間變化包括有。
LocalDate,LocalTime,LocalDateTime,Clock,時區的概念,時間差的概念。

LocalDate

public class LocalDateTest
{

    public static void main(String[] args)
    {
        LocalDate today = LocalDate.now();
        LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS);
        LocalDate yesterday = tomorrow.minusDays(2);
        System.out.println(tomorrow);
        System.out.println(yesterday);

        LocalDate independenceDay = LocalDate.of(2014, Month.JULY, 4);
        DayOfWeek dayOfWeek = independenceDay.getDayOfWeek();
        System.out.println(dayOfWeek); // FRIDAY
    }

}   

輸出結果

2017-01-20
2017-01-18
FRIDAY

直觀的感覺運算比以前簡單了不少。

LocalTime

public class LocalTimeTest
{

    public static void main(String[] args)
    {

        LocalTime time=LocalTime.now();
        System.out.println(time);
        System.out.println(time.minusHours(1));
        System.out.println(time.minusMinutes(10));
        System.out.println(time.plusHours(10));
        LocalTime late = LocalTime.of(23, 59, 59);
        System.out.println(late); // 23:59:59       
    }
}

輸出結果

14:22:14.033
13:22:14.033
14:12:14.033
00:22:14.033
23:59:59

感覺運算好方便。

LocalDateTime

public class LocalDateTimeTest
{

    public static void main(String[] args)
    {
        LocalDateTime sylvester = LocalDateTime.of(2014, Month.DECEMBER, 31, 23, 59, 59);

        DayOfWeek dayOfWeek = sylvester.getDayOfWeek();
        System.out.println(dayOfWeek);      // WEDNESDAY

        Month month = sylvester.getMonth();
        System.out.println(month);          // DECEMBER

        long minuteOfDay = sylvester.getLong(ChronoField.MINUTE_OF_DAY);
        System.out.println(minuteOfDay);    // 1439

        LocalDateTime localdt=LocalDateTime.now();
        System.out.println(localdt);

    }

}

輸出結果

WEDNESDAY
DECEMBER
1439
2017-01-19T14:23:34.938

ZoneId時區

public class TimeZoneTest
{
    public static void main(String[] args)
    {
        //列印所有的時區
        System.out.println(ZoneId.getAvailableZoneIds());

        ZoneId zone1 = ZoneId.of("Europe/Berlin");
        ZoneId zone2 = ZoneId.of("Brazil/East");
        ZoneId zone3=ZoneId.of("Asia/Shanghai");
        System.out.println(zone1.getRules());
        System.out.println(zone2.getRules());
        System.out.println(zone3.getRules());

        LocalTime now2 = LocalTime.now(zone2);
        LocalTime now1 = LocalTime.now(zone1);      

        System.out.println(now1);
        System.out.println(now2);

        System.out.println(now1.isBefore(now2));  // false

        long hoursBetween = ChronoUnit.HOURS.between(now1, now2);
        long minutesBetween = ChronoUnit.MINUTES.between(now1, now2);

        System.out.println(hoursBetween);       // -3
        System.out.println(minutesBetween);     // -239

    }
}

列印結果

[Asia/Aden, America/Cuiaba, 。。。。。 Europe/Monaco]//太長了
ZoneRules[currentStandardOffset=+01:00]東一區
ZoneRules[currentStandardOffset=-03:00]西三區
ZoneRules[currentStandardOffset=+08:00]東八區
07:24:39.798
04:24:39.798
false
-3
-180

Clock

public class ClockTest
{
    public static void main(String[] args)
    {
        Clock clock = Clock.systemDefaultZone();
        long millis = clock.millis();
        System.out.println(millis);

        Instant instant = clock.instant();
        Date legacyDate = Date.from(instant);   // legacy java.util.Date
        System.out.println(legacyDate);
    }
}

輸出

1484807586661
Thu Jan 19 14:33:06 CST 2017

和當前日期型別的轉換關係,獲取當前時區時間的毫秒。

Duration

public class DurationTest
{
    public static void main(String[] args)
    {
        final LocalDateTime from = LocalDateTime.of( 2014, Month.MARCH, 16, 0, 0, 0 );
        final LocalDateTime to = LocalDateTime.now();

    final Duration duration = Duration.between( from, to );
    System.out.println( "Duration in days: " + duration.toDays() );
    System.out.println( "Duration in hours: " + duration.toHours() );
    }

}

輸出

Duration in days: 1040
Duration in hours: 24974