欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java 接口 (interface) and Scala 特质 (trait) 博客分类: Java Scala interface trait  

程序员文章站 2024-03-17 19:12:34
...

摘要:本文将简要介绍Java中的接口(interface)Java 8中接口default方法,以及Scala中的特质(trait),同时会比较Java接口与Scala特质的相似与差异。


1. Java 接口 (interface) 介绍


1.1 Java传统的接口 (interface)


Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。


Java接口本身没有任何实现,因为Java接口不涉及表象,而只描述public行为,所以Java接口比Java抽象类更抽象化。


Java接口的方法只能是抽象的和公开的,Java接口不能有构造器Java接口可以有public静态的和final属性。即接口中的属性可以定义为 public static final int value=5;


假设我们有用于记录日志的Logger接口,有两种不同的实现方式,一种是输出的到Console,一种是输出到文件。


以下为参考实现:


Logger接口 (interface):


publicinterface Logger {

    //only public, static and final property is permitted

    publicstaticfinalintmaxLength = 50;

 

    //only public and abstract method

    publicabstractvoid log(String msg);

}


ConsoleLogger输出到Console


publicclass ConsoleLogger implements Logger {

 

    @Override

    publicvoid log(String msg) {

        System.out.println(msg);

    }

}


FileLogger输出到文件:


publicclass FileLogger implements Logger {


    private PrintWriter fileOutput;

    public FileLogger () {

        try {

            fileOutput = new PrintWriter("applog");

        } catch (FileNotFoundException e) {

            e.printStackTrace();

        }

    }

    @Override


publicvoid log(String msg) {       

        fileOutput.println(msg);

        fileOutput.flush();

    }

}

 

1.2 Java 8中的interface


Java 8 允许我们使用default关键字,为接口声明添加非抽象的方法实现。


publicinterface Logger {

   

    //only public, static and final property is permitted

    publicstaticfinalintmaxLength = 50;

 

    //Java 8 interface default implementation

    publicdefaultvoid log(String msg) {

        //You could implement default log behavior here

        //......

    }

}


 可以在实现类中改变它接口中的缺省行为和实现:

publicclass ConsoleLogger implements Logger {

    //Change default log behavior here


@Override

    publicvoid log(String msg) {

        System.out.println(msg);

    }

}


Java 8之后的interface可以包含包含abstract方法,也可以都是default方法。

 

 2. Scala 特质 (trait) 介绍


Scala中的特质 (trait) Java 8中的接口 (interface) 比较类似,一个Scala类可以扩展一个或多个特质,Scala特质可以给出方法的缺省实现。


2.1 纯接口的特质


traitLogger {

    //abstract method, but no abstract declare required

    deflog(msg: String)

}


你不需要将方法声明为abstract,特质中未被实现的方法默认就是抽象的。


//Use extends but not implements

classConsoleLoggerextendsLogger {

    //no override required

    deflog(msg: String) {

        println(msg)

    }

}


在重写特质的抽象方法时不需要给出override关键字


2.2 带缺省实现的特质


traitConsoleLogger {

 

    //with implementation

    deflog(msg: String) { println(msg) }

}


带有实现方法的特质类似于Java 8接口中的缺省方法。


以下是如何使用这个特质的示例:


class Circle extends Shape withConsoleLogger {


def draw() {


    log(“Draw a circle …”);


    //draw circle here


    ……


}


}


Scala中,我们说ConsoleLogger的功能被“混入”了Circle类中。


2.3 带有特质的对象


Scala可以在创建对象时添加特质,这是Java接口所不具备的特性。


缺省的log方法什么没做:
traitLogger {   


    deflog(msg: String) { }


}


下面使用这个特质的Class什么日志都不会被记录:


class Circle extends Shape withLogger{


def draw() {


    log(“Draw a circle …”);


    //draw circle here


}


}


你可以实现一个更好的Logger特质,并在创建Circle对象是动态“混入”此特质。


traitConsoleLoggerextendsLogger { 


    overridedeflog(msg: String) { println(msg) }


}


val circle1 = new CirclewithConsoleLogger


这样circle在调用draw方法时,ConsoleLoggerlog方法会被执行。


类似的,你可以在另一个对象加入另外一个特质:


val circle2 = new CirclewithFileLogger


2.4 叠加在一起的特质


就像Java Class可以实现多个接口一样,Scala Class也可以叠加多个特质,一般来说,特质从最后一个开始被处理。


假设有如下的Logger trait定义,分别有3trait扩展自Logger


traitLogger {   


    deflog(msg: String) { }


}


 


traitConsoleLogger extends Logger {   


    overridedeflog(msg: String) { println(msg) }


}


traitTimestampLoggerextends Logger {   


    overridedeflog(msg: String) { super.log(new Date() + “ “ + msg) }


}


traitShortLoggerextends Logger {   


    val maxLength = 15


overridedeflog(msg: String) {


    super.log( if(msg.length<= maxLength) msg else msg.substring(0,


    maxLength-3) + “…” )


}


}


上述log方法都将修改过的msg传递给super.log.


实际上,super.log调用的是特质层级中的下一个特质,具体是哪一个,取决于特质添加的顺序。一般来说,特质从最后一个开始被处理。


可以通过如下方式添加混入特质:


val circle1 = new CirclewithConsoleLogger with TimestampLogger with ShortLogger


此例中,ShortLoggerlog方法先被执行,然后才是TimestampLoggerlog方法。


val circle2 = new CirclewithConsoleLogger with ShortLogger with TimestampLogger


此例中,TimestampLoggerlog方法先被执行,然后才是ShortLoggerlog方法。


3. Java接口 (interface) Scala特质 (trait) 比较


通过上面对Java接口和Scala特质的学习,我们发现它们之间有很多的相似性,同时也有差别。


相似性:


Java接口和Scala特质都可以包含抽象方法和具体实现;


ScalaJava一样都不允许类从多个超类继承,但分别可以叠加多个特质和实现多个接口;


差异性:


Java只能在Class层面添加接口的实现,Scala可以在Class和对象层面“混入”特质。Scala通过在对象层面动态“混入”特质,相比而言具有更大的灵活性。