接口方法可以有方法体吗?

91

我知道接口就像是一个100%纯抽象类。因此,它不能在内部实现方法。但我看到了一段奇怪的代码。有人能解释一下吗?

代码片段:

 interface Whoa {
        public static void doStuff() {
            System.out.println("This is not default implementation");
        }
 }

编辑:

我的IDE是Intellij Idea 13.1。项目SDK是Java 7 <1.7.0_25>。IDE没有显示任何编译器错误。但是,当我在命令行上编译代码时,出现以下消息。

Whoa.java:2: error: modifier static not allowed here
    public static void doStuff() {
                       ^

不要使用。请改用抽象类。 - tobias_k
47
Java8允许接口定义默认方法实现。 - sp00m
Idea IDE 不会抱怨它吗? - user3034861
2
Java 8,是的。在那之前,不行。 - Ian McLaird
5
仅在Java 8中引入了默认方法。在此之前是不支持的。 - Omoro
显示剩余9条评论
4个回答

121

Java 8开始,除了默认方法外,接口中可以定义静态方法。

  • 静态方法是与其所在类相关联的方法,而不是与任何对象相关联的方法。类的每个实例共享其静态方法。

  • 这使您更容易在库中组织帮助器方法。您可以将特定于接口的静态方法保存在同一接口中,而不是在单独的类中。

  • 以下示例定义了一个静态方法,该方法检索与时区标识符对应的ZoneId对象;如果没有对应于给定标识符的ZoneId对象,则使用系统默认时区。(因此,您可以简化方法getZonedDateTime)

下面是代码:

public interface TimeClient {
   // ...
    static public 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 public ZonedDateTime getZonedDateTime(String zoneString) {
      return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
   }    
}

参见


5
方法的默认实现。 - Ian McLaird
1
我没有使用Java 8,而是使用的是javac 1.7.0_25。 - user3034861
4
您的IDE是否使用了代码兼容性8?如果是,那么它应该无法在7及以下版本下编译。这里有一篇很好的文章。 - Giovanni Botta
1
@Phoenix我也在使用1.7.0_25版本,但是在这个版本中不被允许。 - Shekhar Khairnar
2
这似乎真的模糊了接口和抽象类之间的界限。 - asteri
显示剩余4条评论

21
这仅在Java 8中才可能实现。在Java 7 Language Specification §9.4中,它明确指出:
“如果在接口中声明的方法被声明为静态的,则会在编译时出现错误,因为静态方法不能是抽象的。”
因此,在Java 7中,接口中不能存在静态方法。
如果您转到Java 8 Language Specification §9.4.3,您可以看到它说:
“静态方法也有一个代码块体,它提供了该方法的实现。”
因此,它明确说明在Java 8中,它们可以存在。
我甚至尝试在Java 1.7.0_45中运行您的确切代码,但它给了我错误“修饰符static不允许在此处”。
以下是来自Java 8教程默认方法(学习Java语言>接口和继承)的一句话引用:

Static Methods

In addition to default methods, you can define static methods in interfaces. (A static method is a method that is associated with the class in which it is defined rather than with any object. Every instance of the class shares its static methods.) This makes it easier for you to organize helper methods in your libraries; you can keep static methods specific to an interface in the same interface rather than in a separate class. The following example defines a static method that retrieves a ZoneId object corresponding to a time zone identifier; it uses the system default time zone if there is no ZoneId object corresponding to the given identifier. (As a result, you can simplify the method getZonedDateTime):

public interface TimeClient {
    // ...
    static public 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 public ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }    
}

Like static methods in classes, you specify that a method definition in an interface is a static method with the static keyword at the beginning of the method signature. All method declarations in an interface, including static methods, are implicitly public, so you can omit the public modifier.


16

对于Java版本7或以下,您可以使用在接口主体内声明的嵌套类来实现类似的功能。并且此嵌套类实现外部接口。

示例:

For java version 7 or below, similar functionally you can achieve using nested class declared within interface body. and this nested class implements outer interface.

Example:

interface I1{
    public void doSmth();

    class DefaultRealizationClass implements  I1{

        @Override
        public void doSmth() {
           System.out.println("default realization");
        }
    }
}

我们如何在代码中使用它?

class MyClass implements I1{

    @Override
    public void doSmth() {
         new I1.DefaultRealizationClass().doSmth();
    }   
}

因此在接口内封装默认实现。


0

Java接口在过去的时间里有了很大的发展,而Java 8彻底改变了接口的假设方式。

回到问题上,是的,我们可以在接口中拥有方法体。

然而,在Java 8中,我们可以在静态方法默认方法中拥有方法体,就像下面的例子一样。

interface CheckMyEvolution{   
 default void whatsNew() {   
     System.out.print("Hello there!Check my Evolution");   
 } 

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();
    }
}
}

我们从Java 9开始,接口中也可以有私有方法。像下面的代码在Java 9及以上版本中编译正常,但在Java 8及以下版本中会失败。

interface CheckMyEvolution{   
     default void whatsNew() {   
         checkIt();   
     }   
     // Private method  
     private void checkIt() {   
         System.out.println("Hello there! I can have private method now. Make sure you are using JDK 9 or Above.");   
     }   
 }   
    public class CheckMyEvolutionImpl implements CheckMyEvolution{   
     public static void main(String[] args) {   
         CheckMyEvolution evolution= new CheckMyEvolutionImpl();   
         evolution.whatsNew();   
     } 
}   
 

References: https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html [https://www.quora.com/profile/Rajat-Singh-187/Private-Method-in-the-Java-Interface]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接