标签:
本文是《Java核心技术 卷1》中第六章接口与内部类中关于接口的阅读总结。
接口(interface)技术,描述了类具有什么功能,但不给出具体的实现(JDK1.8中新增了default方法)。一个类可以实现(implements)一个或多个接口,并在需要接口的地方,随时使用实现了相应接口的对象。
接口不是类,而是对类的一组需求描述,这些实现这个接口的类要遵从接口描述的同一格式进行定义。
比如,Arrays类有一个sort方法,这个方法承诺可以对对象数组进行排序,但要求对象所属的类必须实现了Comparable接口:
public interface Comparable<T>
{
int compareTo(Object other);
}这就是说,任何实现Comparable接口的类都需要包含compareTo方法,而且这个方法的定义必须和接口中声明的形式一样。
接口中所有的方法都自动的属于public,因此,在接口中声明方法时,可以不提供关键词public。
假如现在有一个学生类Student,要使用Arrays类中的sort方法对学生进行按成绩排序,那么就需要Student类事件Comparable接口。实现一个接口要使用implements关键字。如果要实现多个接口,那接口之间使用逗号分隔:
public class Student implements Comparable然后,就需要在类中定义接口中的所有方法。下面是Student中对compareTo方法的定义:
public int compareTo(Student o){
return Double.compare(this.score, o.score);
}这样,就会根据学生的成绩对学生数组进行排序了。
有时,为了描述一个通用的功能,需要自己定义一个接口。定义接口需要使用interface关键字,表明这是一个接口。同类一样,接口也可以继承,也使用extends关键字,不过,接口可以继承一个或多个接口,接口之间使用逗号分隔。
在JDK1.8中,接口新增了默认(default)方法和静态(static)方法,也就是说,在JDK1.8中,一个接口可以包含如下内容:抽象方法、默认方法、静态方法和常量。
定义一个接口和定义一个类类似,不同的是,除非方法是默认的(使用default)关键字,否则不能实现这个方法,这个方法要在实现这个接口的类中实现。比如,我们要自己实现一个Office工具组件,里面有好多组件比如Word、Excel和PPT等,这些组件都有一些共同的方法,这里为了简单比如启动方法(start),就可以定义一个接口Officeable,然后让这些组件实现这个接口,代码如下:
package interfaceTest;
public interface Officeable {
void start();
}public class Word implements Officeable {
@Override
public void start() {
System.out.println("Word is running...");
}
}
public class Excel implements Officeable {
@Override
public void start() {
System.out.println("Excel is running...");
}
}Officeable oa=new Word();
public class interfaceTest {
public static void main(String[] args){
Word w=new Word();
Officeable oa=w;
oa.start();
}
}Word is running...
同时,接口中还可以包含一个常量,这个常量将自动设置为公有静态常量(public static final),也可以省略这个标签。
考虑如下一个接口明叫DoIt:
public interface DoIt {
void doSomething(int i,double x);
int doSomethingElse(String s);
}这个接口有两个方法doSomething和doSomethingElse,这个接口已经被很多人使用了。不过,过了一段时间,开发者想在这里添加一个方法,那么接口可能会是这样:
public interface DoIt {
void doSomething(int i,double x);
int doSomethingElse(String s);
boolean didItWork(int i,double x,String s);
}public interface DoItPlus extends DoIt {
boolean didItWork(int i,double x,String s);
}不过到了JDK1.8中,接口的开发者有了新的选择,在接口中实现一个默认方法:
public interface DoIt {
void doSomething(int i,double x);
int doSomethingElse(String s);
default boolean didItWork(int i,double x,String s){
//method body
}
}在JDK1.8中,添加了一个特性,就是接口中也可以定义方法了。不过这个方法必须是默认的(default)或静态的(static)。默认方法可以增加接口的功能,同时还能保证对旧接口的兼容性。
考虑下面的接口TimeClient,可以设置并获取时间:
import java.time.*;
public interface TimeClient {
void setTime(int hour,int minute,int second);
void setDate(int day,int month,int year);
void setDateAndTime(int day,int month,int year,
int hour,int minute,int second);
LocalDateTime getLocalDateTime();
}import java.time.*;
import java.lang.*;
import java.util.*;
public class SimpleTimeClient implements TimeClient {
private LocalDateTime dateAndTime;
public SimpleTimeClient() {
dateAndTime = LocalDateTime.now();
}
public void setTime(int hour, int minute, int second) {
LocalDate currentDate = LocalDate.from(dateAndTime);
LocalTime timeToSet = LocalTime.of(hour, minute, second);
dateAndTime = LocalDateTime.of(currentDate, timeToSet);
}
public void setDate(int day, int month, int year) {
LocalDate dateToSet = LocalDate.of(day, month, year);
LocalTime currentTime = LocalTime.from(dateAndTime);
dateAndTime = LocalDateTime.of(dateToSet, currentTime);
}
public void setDateAndTime(int day, int month, int year,
int hour, int minute, int second) {
LocalDate dateToSet = LocalDate.of(day, month, year);
LocalTime timeToSet = LocalTime.of(hour, minute, second);
dateAndTime = LocalDateTime.of(dateToSet, timeToSet);
}
public LocalDateTime getLocalDateTime() {
return dateAndTime;
}
public String toString() {
return dateAndTime.toString();
}
public static void main(String... args) {
TimeClient myTimeClient = new SimpleTimeClient();
System.out.println(myTimeClient.toString());
}
}过一段时间,希望在TimeClient接口中增加功能,比如获得时区的功能,这时,接口可能这样:
import java.time.*;
public interface TimeClient {
void setTime(int hour,int minute,int second);
void setDate(int day,int month,int year);
void setDateAndTime(int day,int month,int year,
int hour,int minute,int second);
LocalDateTime getLocalDateTime();
ZonedDateTime getZonedDateTime(String zoneString);
}import java.time.*;
public interface TimeClient {
void setTime(int hour, int minute, int second);
void setDate(int day, int month, int year);
void setDateAndTime(int day, int month, int year,
int hour, int minute, int second);
LocalDateTime getLocalDateTime();
static ZoneId getZoneId (String zoneString) {
try {
return ZoneId.of(zoneString);
} catch (DateTimeException e) {
System.err.println("Invalid time zone: " + zoneString +
"; using default time zone instead.");
return ZoneId.systemDefault();
}
}
default ZonedDateTime getZonedDateTime(String zoneString) {
return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
}
}在声明方法前使用default关键字来指定一个方法是默认方法。由于接口中所有的方法默认都认为是public,所以可以省略public关键字。
这样,在SimpleTimeClient类和其它所有实现了TimeClient接口的类中都不需要做任何修改就有已经定义好的getZonedDateTime方法了。
当需要继承一个具有默认方法的接口时,子接口对默认方法的处理可以有一下三种方式:
如果像这样继承接口:
public interface AnotherTimeClient extends TimeClient { }如果这样继承接口:
public interface AbstractZoneTimeClient extends TimeClient {
public ZonedDateTime getZonedDateTime(String zoneString);
}如果像这样继承接口:
public interface HandleInvalidTimeZoneClient extends TimeClient {
default public ZonedDateTime getZonedDateTime(String zoneString) {
try {
return ZonedDateTime.of(getLocalDateTime(),ZoneId.of(zoneString));
} catch (DateTimeException e) {
System.err.println("Invalid zone ID: " + zoneString +
"; using the default time zone instead.");
return ZonedDateTime.of(getLocalDateTime(),ZoneId.systemDefault());
}
}
}除了默认方法,接口中还可以定义静态方法。这可以让你更加容易的主治库中的辅助方法,可以将静态函数放在特定接口中,而不是放在另一个单独的类中。就像上面接口中定义的静态方法一样。
就像在类中定义静态方法一样,在接口中定义静态方法也使用static关键词。在接口中定义静态方法也可以省略public关键词,会自动设置为public。
接口与抽象类有很多相似的地方,那么为什么要引入接口呢?
这时因为java中一个类只能继承一个父类,而不能继承多个类。不过接口的存在就满足了java的多继承需求,因为一个类可以继承一个或多个接口。这样,接口不但提供了多继承的大多数好处,同时还避免了多继承的复杂性和低效性。
在JDK1.8中,接口中也可以定义方法了,也就是接口把手伸向了抽象类的地盘,变得更像抽象类了。那么两者间还有什么不同么?
标签:
原文地址:http://blog.csdn.net/u012877472/article/details/51096936