Scala13

Object Equality

  • 定义 equals会出现四种不一致定义的情况

    1. Defining equals with the wrong signature

    2. Changing equals wihtout also changing *hashCode. (一般利用hashCode来实现是否相等)

    3. Defining equals in terms of mutable fields.

    4. Faling to define equals as an equivalence relation.

  • The contract of the equals method in scala.Any specifies that equals must implement an equivalence relation on non-null objects:

  • As with hashCode, Any’s equals contract is based on the contract of equals in java.lang.Object

  • 如何实现一个理智的方法呢? The idea is that as soon as a class redefiens equals it should also explicitly state that object of this class are never equal to objects of some superclass that implements a different equality

  • elements types of parameterized types are eliminated by the compiler’s erasure phase.

  • a type parameter in a pattern starting with a lower-case letter represents an unknown type.

  • existential type. So even though technically the underscore stands for two different things in a pattern match and in a type parameter of a method call, in essence the meaning is the same: it lets you label something that is unknown.

Recipes for equals and hashCode
Recipes for equals
  • If you’re going to override equals in a non-final class, you should create a canEqual method. If the inherited definition of equals is from AnyRef, the definition of canEqual will be new, otherwise it will override a previous definition of a method with the same name.The only exception to this requirement is for final classes that redefine the equals method inherited from AnyRef.

  • The canEqual method should yield true if the argument object is an instance of the current class, false otherwise

  • In the equals method, make sure you declare the type of the object passed as an Any

  • Write the body of the equals method as a single match expression. The selector of the match should be the object passed to equals

  • The match expression should have two cases. The first case should declare a typed pattern for the type of the class on which you’re defining the equals method

  • In the body of this case, write an expression that logical-ands together the individual expressions that must be true for the objects to be equal. If the equals method you are overriding is not that of AnyRef, you will most likely want to include an invocaton of the superclass’s equals method. If you are defining equals for a class that first introduced canEqual, you should invoke canEqual on the argument to the equality method, passing this as the argument.

  • For the second case, use a wildcard pattern that yields false.

Recipes for hashCode
  • Include in the calculation each field in your object that is used to determine equality in the equals method ( the “relevant” fields).

  • For each relevant field, no matter its type, you can calculate a hash code by invoking hashCode on it.

  • If you wish, you can leave off the hashCode invocation on field of type Int, Short, Byte, and Char. The hash code for an Int is the value of the Int, as are the hash codes of Shorts, Bytes, and Chars when automatically widened to Int.

  • If the equals method invokes super.equals(that) as part of its calculation, you should start your hashCode calculation with an invocation of super.hashCode

  • If one of your fields is a collection, you probably want a hash code for that field that is based on all the elements contained in the collection. If the field is a List, Set, Map, or tuple, you can simply call hashCode on the field, because equals and hashCode are overriden in those classes to take into account the contained elements. However the same is not true for Arrays, which do not take elements into account when calculating a hash code. Thus for an array, you should treat each element of the array like an individual field of your object, calling hashCode on each element explicitly, or passing the array to one of the hashCode methods in singleton object java.util.Arrays.

Conclusion
  • In retrospect, defining a correct implementation of equals has been surprisingly subtle. You must be careful about the type signature; you must override hashCode; you should avoid dependencies on mutable state; and you should implement and use a canEqual method if your class is non-final.

  • Given how difficult it is to implement a correct equality method, you might prefer to define your classes of comparable objects as case classes. That way, the Scala compiler will add equals and hashCode methods with the right properties automatically.

Combining Scala and Java

  • 这一章主要讲如何将 Scala 与 Java 结合起来,主要包括两个方面。1. 讨论了 Scala 是如何被翻译到 Java 中去的,2. 讨论了如何使用 Java 的注解
Using Scala from Java
General rules
  • Scala is implemented as a translation to standard Java bytecodes. As much as possible, Scala features map directly onto the equivalent Java features.
Special cases
Value types
  • A value type like Int can be translated in two different ways to Java. Whenever possible, the compiler translates a Scala Int to a Java int to get better performance. In cases where the compiler is unsure whether an object is a value type or not, the compiler uses objects and relies on wrapper classes. Wrapper classes such as java.lang.Integer allow a value type to be wrapped inside a Java object and thereby manipulated by code that needs objects.
Singleton objects
  • The Scala translation of singleton objects uses a combination of static and instance methods. For every Scala singleton object, the compiler will create a Java class for the object with a dollar sign added to the end. If you have a “standalone” singleton object, one which does not come with a class of the same name. In that case, the compiler will create a Java class named that has a static forwarder method for each method of the Scala singleton object.
Traits as interfaces
  • Compiling any trait creates a Java interface of the same name. This interface is usable as a Java type, and it lets you call methods on Scala objects through variables of that type.
Annotations
Deprecation
  • For any method or class marked @deprecated, the compiler will add Java’s own deprecation annotation to the emitted code.
Volatile fields
  • an field marked @volatile in Scala is given the Java volatile modifier in the emitted code.
Serialization
  • Scala’s three standard serialization annotations are all translated to Java equivalents.
Exceptions thrown
  • Scala does not check that thrown exceptions are caught. That is, Scala has no equivalent to Java’s throws declarations on methods. All Scala methods are translated to Java methods that declare no thrown exceptions.
Java annotations
  • Existing annotations from Java frameworks can be used directly in Scala code. Any Java framework will see the annotations you write just as if you were writing in Java.
Writing your own annotations
  • To make an annotation that is visible to Java reflection, you must use Java annotation and compile it with javac.

  • Be aware that when you use Java annotations you have to work within theri limitations. For example, you can only use constatns, not expressions, in the arguments to annotations.

Existential types
  • For Java wildcard types and raw types, Scala uses an extra kind of type called an existential type

  • Existential types are a fully supported part of the language, but in practice they are mainly used when accessing Java types from Scala.

  • The general form of an existential typs is as follows:

type forSome { declarations}

  • The type part is an arbitrary Scala type, and the declarations part is a list of abstract vals and types. The interpretation is that the declared variables and types exist but are unknown, just like abstract members of a class. The type is then allowed to refer to the declared variables and types even though it is unknown what they refer to.

  • By the way, There is also a placeholder syntax for existential types, and is similar in spirit ot the placeholder syntax for function literals. You can also insert upper and lower bounds when using the placeholder syntax.

  • When passing an existential type into a method, move type parameters from the forSome clause to type parameters of the method. Inside the body of the method, you can use the type parameters to refer to the types that were in the forSome clause.

  • Instead of returning an existential type from a method, return an object that has abstract members for each of the types in the forSome clause.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值