Scala学习笔记(3)-Scala特质

看到Scala特质,感觉用起来应该挺方便,把需要在Java中分开写的代码,直接写在一起,实现起来,以及看起来,都挺好的。

特质可以提供方法和字段的实现。

一个类可以扩展一个或多个特质。

Scala特质这玩意看起来又像接口,又像抽象类,到底是怎么回事?Scala编译器对特质到底做了什么?


通过代码来看应该比较容易。

定义一个Logger特质:

package gao.traits
trait Logger {
  def log(msg:String)
  def info(msg:String): Unit = {
    log("INFO:" + msg)
  }
  def warn(msg:String): Unit = {
    log("WARN:" + msg)
  }
  def error(msg:String): Unit = {
    log("ERROR:" + msg)
  }
}

实现ConsoleLogger扩展Logger特质:

package gao.traits
import java.util.Date
class ConsoleLogger extends Logger{
  override def log(msg: String): Unit = {
    println(new Date() + " " + msg)
  }
}

不管怎么说,看起来是比Java方便的。

Java中,要实现上边两段代码相同的功能,基本需要分三步完成:

1)定义接口Logger

2)定义抽象类AbstractLoggerimplements Logger,并实现infowarnerror三个方法

3)实现ConsoleLoggerextends AbstractLogger implements Logger

实现过程就像Java的集合框架实现流程。


到底Scala是怎么两步完成Java需三步才能完成的代码的呢?我们来看看编译后的.class文件吧。


上边两段代码会被Scala编译成3.class文件,如下:

$ ls target/scala-2.11/classes/gao/traits/

ConsoleLogger.class 

Logger.class 

Logger$class.class


使用javap命令来看一看这些.class文件都长什么样子。


$ javap -p target/scala-2.11/classes/gao/traits/Logger.class
Compiled from "Logger.scala"
public interface gao.traits.Logger {
    public abstract void log(java.lang.String);
    public abstract void info(java.lang.String);
    public abstract void warn(java.lang.String);
    public abstract void error(java.lang.String);
}


$ javap -p target/scala-2.11/classes/gao/traits/Logger\$class.class
Compiled from "Logger.scala"
public abstract class gao.traits.Logger$class {
    public static void info(gao.traits.Logger, java.lang.String);
    public static void warn(gao.traits.Logger, java.lang.String);
    public static void error(gao.traits.Logger, java.lang.String);
    public static void $init$(gao.traits.Logger);
}


$ javap -p target/scala-2.11/classes/gao/traits/ConsoleLogger.class
Compiled from "ConsoleLogger.scala"
public class gao.traits.ConsoleLogger implements gao.traits.Logger {
    public void info(java.lang.String);
    public void warn(java.lang.String);
    public void error(java.lang.String);
    public void log(java.lang.String);
    public gao.traits.ConsoleLogger();
}

OK,看起来清晰多了吧,要在JVM上运行,最终都是一样的,只是Scala编译器简化了代码编辑工作量,而且Scala特质使代码实现起来更合乎人的思维逻辑。


编译ConsoleLogger并没有继承gao.traits.Logger$class,可以想象只是调用了其静态方法。所以在Scala,类可以实现任意数量的特质,看起来就像多继承一样。而在Java规范中,是不允许多继承的(因为可能导致JVM无法选择吧)。


前几天看了一点点Java8的东西,看到在Java8中,接口也可以有默认方法实现,比如在java.util.Collection接口及其子接口中都添加了一些实现方法,如下是java.util.Collection接口新增的代码:

/**
 * Returns a sequential {@code Stream} with this collection as its source.
 *
 * <p>This method should be overridden when the {@link #spliterator()}
 * method cannot return a spliterator that is {@code IMMUTABLE},
 * {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()}
 * for details.)
 *
 * @implSpec
 * The default implementation creates a sequential {@code Stream} from the
 * collection's {@code Spliterator}.
 *
 * @return a sequential {@code Stream} over the elements in this collection
 * @since 1.8
 */
default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

这样,在Java8也能像Scala定义特质一样定义接口了。帮帮哒!!!


虽然没有看到,想象Java8应该为此修改、新增了JVM规范的内容,使JVM能接受既有抽象方法又有具体方法的接口;

或者,仅仅是修改了Java编译器,来实现上边描述的Scala编译器功能,如果这样,看起来好像低级了一点,简单粗暴的静态方法调用来组合功能,想想都混乱。

接下来打算学习学习Java8,看起来蛮吊的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Go in memory

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值