最近学习了一下scala,对scala做了一些学习后总结了一些心得,跟大家分享一下: 首先,scala基于java,是一种JVM语言,跟java一样,都是通过编译器编译成class文件,由java解释器解析执行,其核心与java一样,都是运行在java虚拟机上。从语法和特性层面,scala除了具备java的面向对象基本特性(继承、封装、多态)以外,增加了函数式编程特性,而且scala语法比java更灵活,scala编程效率要比java高很多,特别是增加了许多数据操作的函数,用起来非常爽,另外scala对java的一些数据结构进行了优化提升,期性能提升不少。同样scala程序灵活易用的同时其可读性就大大降低,特别是一个初学scala的新鸟看一个scala老鸟程序的时候感觉无从下手(这点本人深有体会),当然关于这一块的讨论,网上众说纷纭,我们就不再多扯了,下面是我个人总结的一些java和scala特点对比 
?
下面通过以下几点深入对比一下Java和Scala都有哪些异同点
1.是否相等
写过java代码的同学都知道,java对象比较有“==”和equals两种方法,“==”符号用于对象引用地址比较,equals方法默认实现与“==”相等,如果想要对比两个对象的值必须重写Object的equals方法,java的String类重写了equals方法(当然String在使用的时候也有很多注意事项,后续在做扩展)。
package com.eoi.test.scala.equals;
public class JavaEquals {
public static void main(String args[]) {
String aaa = "aaa";
String bbb = "aaa";
String ccc = new String("aaa");
System.out.println(aaa == bbb);
System.out.println(aaa.equals(bbb));
System.out.println(aaa == ccc);
System.out.println(aaa.equals(ccc));
UserBean bean1 = new UserBean("jack", 20);
UserBean bean2 = new UserBean("jack", 20);
System.out.println(bean1.equals(bean2));
System.out.println(bean1 == bean2);
EmptyBean emptyBean1 = new EmptyBean();
EmptyBean emptyBean2 = new EmptyBean();
System.out.println(emptyBean1.equals(emptyBean2));
System.out.println(emptyBean1 == emptyBean2);
}
}
class EmptyBean {
}
class UserBean {
private String name;
private int age;
UserBean(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof UserBean) {
UserBean bean = (UserBean) obj;
return name.equals(bean.name) && age == bean.age;
}
return false;
}
}
运行结果:
true
true
false
true
true
false
false
false
scala语言里“==”和equals都是用于对象值比较,scala新增了“eq”和“ne”两个方法,比较两个对象的引用地址是否相同,例如代码:
case class User(name:String, age: Int)
class User2(name:String, age: Int)
object ScalaEquals {
def main(args: Array[String]): Unit = {
val aaa = "bbb"
val bbb = "bbb"
var ccc = "ccc1"
var ddd = "ccc2"
println("=============String compare=========")
println(aaa == bbb)
println(aaa.equals(bbb))
println(aaa.eq(bbb))
println(ccc == ddd)
println(ccc.equals(ddd))
println(ccc.eq(ddd))
ddd = "ccc1"
println("=============compare after value changed =========")
println(ccc == ddd)
println(ccc.equals(ddd))
println(ccc.eq(ddd))
val eee = new String("111")
val fff = new String("111")
var ggg = new String("222")
var hhh = new String("222")
println("============= compare new String ========")
println(eee == fff)
println(eee.equals(fff))
println(eee.eq(fff))
println(ggg == hhh)
println(ggg.equals(hhh))
println(ggg.eq(hhh))
val jack = new User("jack", 21)
val jack2 = new User("jack", 21)
val jack3 = new User("jack", 20)
val jack4 = jack
println("==========cass class compare============")
println(jack == jack2)
println(jack.equals(jack2))
println(jack.eq(jack2))
println(jack == jack3)
println(jack.equals(jack3))
println(jack.eq(jack3))
println(jack == jack4)
println(jack.equals(jack4))
println(jack.eq(jack4))
val jack5 = new User2("jack", 21)
val jack6 = new User2("jack", 21)
val jack7 = new User2("jack", 20)
val jack8 = jack5
println("============class compare============")
println(jack5 == jack6)
println(jack5.equals(jack6))
println(jack5.eq(jack6))
println(jack5 == jack7)
println(jack5.equals(jack7))
println(jack5.eq(jack7))
println(jack8 == jack6)
println(jack8.equals(jack6))
println(jack8.eq(jack6))
}
}
运行结果:
=============String compare=========
true
true
true
false
false
false
=============compare after value changed =========
true
true
true
============= compare new String ========
true
true
false
true
true
false
==========cass class compare============
true
true
false
false
false
false
true
true
true
============class compare============
false
false
false
false
false
false
false
false
false
从上面的例子中可以看出,User和User2的对比结果完全不一样,因为一个是case class 一个是 class,透过现象看本质,我们两个类的class文件反编译以后可以看到,User2
import scala.reflect.ScalaSignature;
public class User2
{
public User2(String name, int age) {}
}
?User编译后生成两个class文件,User.class和User$.class,User.class里面重写了equals、hashCode等方法,User.class方法的实际调用时User$.class里的MODULE$?
?
package com.eoi.test.scala.equals;
import scala.Function1;
import scala.Option;
import scala.Product;
import scala.Product.class;
import scala.Serializable;
import scala.Tuple2;
import scala.collection.Iterator;
import scala.reflect.ScalaSignature;
import scala.runtime.BoxesRunTime;
import scala.runtime.ScalaRunTime.;
import scala.runtime.Statics;
public class User
implements Product, Serializable
{
private final String name;
public User(String name, int age)
{
Product.class.$init$(this);
}
/* Error */
public boolean equals(Object x$1)
{
// Byte code:
// 0: aload_0
// 1: aload_1
// 2: if_acmpeq +90 -> 92
// 5: aload_1
// 6: astore_2
// 7: aload_2
// 8: instanceof 2
// 11: ifeq +8 -> 19
// 14: iconst_1
// 15: istore_3
// 16: goto +5 -> 21
// 19: iconst_0
// 20: istore_3
// 21: iload_3
// 22: ifeq +74 -> 96
// 25: aload_1
// 26: checkcast 2 com/eoi/test/scala/equals/User
// 29: astore 4
// 31: aload_0
// 32: invokevirtual 53 com/eoi/test/scala/equals/User:name ()Ljava/lang/String;
// 35: aload 4
// 37: invokevirtual 53 com/eoi/test/scala/equals/User:name ()Ljava/lang/String;
// 40: astore 5
// 42: dup
// 43: ifnonnull +12 -> 55
// 46: pop
// 47: aload 5
// 49: ifnull +14 -> 63
// 52: goto +36 -> 88
// 55: aload 5
// 57: invokevirtual 113 java/lang/Object:equals (Ljava/lang/Object;)Z
// 60: ifeq +28 -> 88
// 63: aload_0
// 64: invokevirtual 56 com/eoi/test/scala/equals/User:age ()I
// 67: aload 4
// 69: invokevirtual 56 com/eoi/test/scala/equals/User:age ()I
// 72: if_icmpne +16 -> 88
// 75: aload 4
// 77: aload_0
// 78: invokevirtual 115 com/eoi/test/scala/equals/User:canEqual (Ljava/lang/Object;)Z
// 81: ifeq +7 -> 88
// 84: iconst_1
// 85: goto +4 -> 89
// 88: iconst_0
// 89: ifeq +7 -> 96
// 92: iconst_1
// 93: goto +4 -> 97
// 96: iconst_0
// 97: ireturn
// Line number table:
// Java source line #3 -> byte code offset #0
// Local variable table:
// start length slot name signature
// 0 98 0 this User
// 0 98 1 x$1 Object
}
public String toString()
{
return ScalaRunTime..MODULE$._toString(this);
}
public int hashCode()
{
int i = -889275714;i = Statics.mix(i, Statics.anyHash(name()));i = Statics.mix(i, age());return Statics.finalizeHash(i, 2);
}
public boolean canEqual(Object x$1)
{
return x$1 instanceof User;
}
public Iterator<Object> productIterator()
{
return ScalaRunTime..MODULE$.typedProductIterator(this);
}
public Object productElement(int x$1)
{
int i = x$1;
switch (i)
{
default:
throw new IndexOutOfBoundsException(BoxesRunTime.boxToInteger(x$1).toString());
case 1:
break;
}
return name();
}
public int productArity()
{
return 2;
}
public String productPrefix()
{
return "User";
}
public int copy$default$2()
{
return age();
}
public String copy$default$1()
{
return name();
}
public User copy(String name, int age)
{
return new User(name, age);
}
public int age()
{
return this.age;
}
public String name()
{
return this.name;
}
public static Function1<String, Function1<Object, User>> curried()
{
return User..MODULE$.curried();
}
public static Function1<Tuple2<String, Object>, User> tupled()
{
return User..MODULE$.tupled();
}
public static User apply(String paramString, int paramInt)
{
return User..MODULE$.apply(paramString, paramInt);
}
public static Option<Tuple2<String, Object>> unapply(User paramUser)
{
return User..MODULE$.unapply(paramUser);
}
}
?
?
package com.eoi.test.scala.equals;
import scala.None.;
import scala.Option;
import scala.Serializable;
import scala.Some;
import scala.Tuple2;
import scala.runtime.AbstractFunction2;
import scala.runtime.BoxesRunTime;
public final class User$
extends AbstractFunction2<String, Object, User>
implements Serializable
{
public static final MODULE$;
private User$()
{
MODULE$ = this;
}
private Object readResolve()
{
return MODULE$;
}
public Option<Tuple2<String, Object>> unapply(User x$0)
{
return x$0 == null ? None..MODULE$ : new Some(new Tuple2(x$0.name(), BoxesRunTime.boxToInteger(x$0.age())));
}
public User apply(String name, int age)
{
return new User(name, age);
}
public final String toString()
{
return "User";
}
static
{
new ();
}
}
?
总结,Scala中的case class自动重写了equals和hashCode方法,所以实现了直接的值对比
?