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