Explanation of Chapter 10 in Quick Learning Scala Exercises

The 1 java. awt. Rectangle class has two useful methods translate and grow, but unfortunately there are no classes like java.awt.geom.Ellipse2D. In Scala, you can solve this problem. Define a RenctangleLike trait and add specific translate and group methods. Provide any abstract method you need to implement so that you can incorporate this feature as follows:

val egg = new java.awt.geom.Ellipse2D.Double(5,10,20,30) with RectangleLike
egg.translate(10,-10)
egg.grow(10,20)
trait RectangleLike {
  def translate(x: Int, y: Int) {}
  def grow(x: Int, y: Int)
}
class Shape {}
object xx extends App {
  val p1 = new Shape() with RectangleLike {
    def grow(x: Int, y: Int) {} //override abstract methods in objects
  }
  p1.translate(1, 2)
  p1.grow(3, 6)
}

2. Define the OrderedPoint class by mixing scala.math.Ordered[Point] with java.awt.Point. Sort by dictionary editing, that is, if x < x'or x=x'and Y < y', then (x, y) < (x', y')

import java.awt.Point
import scala.math.Ordered
class OrderPoint(x: Int, y: Int) extends Point(x, y) with Ordered[Point] {
  def compare(that: Point): Int = {
    if ((this.x <= that.x) && this.y < that.y) -1
    else 1
  }
}
object xx extends App {
  val p1 = new OrderPoint(1, 3)
  val p2 = new OrderPoint(0, 1)
  print(p1.compareTo(p2))
}

Look at the BitSet class and draw a graph of all its superclasses and features. Ignore type parameters ([... ] Everything in it. Then the linearization specification of the feature is given.

The difficulty is conceivable.

4. Provide a CryptoLogger class that encrypts log messages in Caesar password. The key is 3 by default, but the user can also override it. Provide examples of using default keys and - 3 as keys

trait Logger {
  def log(msg: String)
}
class CryptoLogger extends Logger {
  def log(msg: String): Unit = {
    println("Before encryption:" + msg)
    println("After encryption:" + encryptz(msg, -3))
  }
  def encryptz(str: String, key: Int): String = {
    for (i <- str) yield if (key >= 0) (97 + ((i - 97 + key) % 26)).toChar
    else (97 + ((i - 97 + 26 + key) % 26)).toChar
  }
}
object xx extends App {
  new CryptoLogger().log("Asdf")
}

There is a reference in the JavaBean specification called property change listener, which is the standard way beans notify their property changes. The PropertyChangeSupport class is a convenient superclass for any bean that wants to support a property change notification for its property change listener. Unfortunately, other superclass classes, such as JComponent, have to re-implement the corresponding methods. Re-implement PropertyChangeSupport as a feature, and then incorporate it into the java.awt.Point class

import java.awt.Point
import java.beans.PropertyChangeSupport
trait PropertyChange extends PropertyChangeSupport {}
object xx extends App {
  // Point is not a subclass of PropertyChangeSupport
  // java.awt.Point has inherited Point2D
  // PropertyChange cannot extend the PropertyChangeSupport class
  // The method in Property Change Support should be copied into trait
  val p1 = new Point() with PropertyChange //Report errors
}

6 In the Java AWT class library, we have a Container class, a Component subclass that can be used for various components. For example, Button is a Component, but Panel is a Container. This is a working combination mode. Swing has JComponent and JContainer, but if you look carefully, you will find some strange details. Although it makes no sense to add other components such as JButton, JComponent still extends from Container. Swing designers would ideally prefer the design in Figure 10-4. But that's impossible in Java. Please explain why? How does Scala use traits to design such an effect?
Java can only inherit independently, and JContainer cannot inherit from both Container and JComponent. Scala can solve this problem through traits.

There are dozens of Scala traits tutorials on the market, using silly examples such as "barking dogs" and "philosophical frogs". Reading and understanding these clever inheritance hierarchies is tedious and not helpful in understanding problems, but designing a set of inheritance hierarchies yourself is different and enlightening. To be your own hierarchy of inheritance of traits, you need to embody superimposed traits, concrete and abstract methods, and concrete and abstract fields.

trait A {
  def f: String = "A:"
}
trait B extends A {
  override def f = {
    super.f + "B:"
  }
}
trait C extends A {
  override def f = {
    super.f + "C:"
  }
}
class Person {}
object xx extends App {
  val p1 = new Person() with B with C
  val p2 = new Person() with C with B

  println(p1.f)
  println(p2.f)
}

Output: A:B:C:
A:C:B:
The sequence of calls is more interesting when the traits are superimposed, and the others are similar, so we will not repeat them.
8 In the java.io class library, you can add buffering mechanism to the input stream through the BufferedInputStream modifier. Re-buffering with traits. For simplicity, rewrite the read method

trait Buffering {
  this: InputStream =>
  val BUF_SIZE: Int = 256
  val buf: Array[Byte] = new Array[Byte](BUF_SIZE)
  var bufsize: Int = 0 // Cached data size
  var pos: Int = 0 // current location
  override def read(): Int = {
    if (pos >= bufsize) { // Read data
      bufsize = this.read(buf, 0, BUF_SIZE)
      if (bufsize <= 0) return bufsize
      pos = 0
    }
    pos += 1 // Displacement
    buf(pos - 1) // Return data
  }
}
object xx extends App {
  val f = new FileInputStream("c:/") with Buffering
  for (i <- 1 to 20) println(f.read())
}

9 Use the characteristics of the log generator in this chapter to add the log function to the scheme in the previous exercise, requiring the effect of buffer.

package day
import java.io.FileInputStream
import java.io.InputStream
trait Logger {
  def log(msg: String)
}
trait PrintLogger extends Logger {
  def log(msg: String) = println(msg)
}
trait Buffering {
  this: InputStream with Logger =>
  val BUF_SIZE: Int = 5
  val buf: Array[Byte] = new Array[Byte](BUF_SIZE)
  var bufsize: Int = 0 // Cached data size
  var pos: Int = 0 // current location
  override def read(): Int = {
    if (pos >= bufsize) { // Read data
      bufsize = this.read(buf, 0, BUF_SIZE)
      if (bufsize <= 0) return bufsize
      log("buffered %d bytes: %s".format(bufsize, buf.mkString(", ")))
      pos = 0
    }
    pos += 1 // Displacement
    buf(pos - 1) // Return data
  }
}
object Eight {
  def main(args: Array[String]) {
    val f = new FileInputStream("myapp.log") with Buffering with PrintLogger
    for (i <- 1 to 20) println(f.read())
  }
}

10 Implement an Iterable InputStream class, extend java.io.InputStream and blend in Iterable[Byte] features

package day
import java.io.{ FileInputStream, InputStream }
trait IterableInputStream extends InputStream with Iterable[Byte] {
  class InputStreamIterator(outer: IterableInputStream) extends Iterator[Byte] {
    def hasNext: Boolean = outer.available() > 0
    def next: Byte = outer.read().toByte
  }
  override def iterator: Iterator[Byte] = new InputStreamIterator(this)
}
object Ten extends App {
  val fis = new FileInputStream("c:/my.ini") with IterableInputStream
  val it = fis.iterator
  while (it.hasNext)
    println(it.next())
  fis.close()
}

Keywords: Java Scala

Added by RedDragon on Thu, 18 Jul 2019 03:21:29 +0300