Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Scala:类参数访问与对象字段访问_Java_Scala_Class_Parameters_Field - Fatal编程技术网

Java Scala:类参数访问与对象字段访问

Java Scala:类参数访问与对象字段访问,java,scala,class,parameters,field,Java,Scala,Class,Parameters,Field,我来自Java背景,刚接触Scala,目前正在阅读《Scala编程》一书 书中有一个例子如下: class Rational(n: Int, d: Int) { // This won't compile require(d != 0) override def toString = n + "/" + d def add(that: Rational): Rational = new Rational(n * that.d + that.n * d, d * that.d) }

我来自Java背景,刚接触Scala,目前正在阅读《Scala编程》一书

书中有一个例子如下:

class Rational(n: Int, d: Int) { // This won't compile
  require(d != 0)
  override def toString = n + "/" + d

  def add(that: Rational): Rational = new Rational(n * that.d + that.n * d, d * that.d)
}
class Rational(n: Int, d: Int) {
  require(d != 0)
  val numer: Int = n
  val denom: Int = d

  override def toString = numer + "/" + denom

  def add(that: Rational): Rational =
    new Rational(
      numer * that.denom + that.numer * denom,
      denom * that.denom
    )
}
但是,鉴于此代码,编译器会抱怨:

error: value d is not a member of Rational
       new Rational(n * that.d + that.n * d, d * that.d)
                             ^
error: value n is not a member of Rational
       new Rational(n * that.d + that.n * d, d * that.d)
                                      ^
error: value d is not a member of Rational
       new Rational(n * that.d + that.n * d, d * that.d)
                                                      ^
解释说:

尽管类参数n和d在add方法的代码中属于作用域,但您只能在调用add的对象上访问它们的值。因此,当您在add的实现中说n或d时,编译器很乐意为您提供这些类参数的值。但它不允许您说.n或.d,因为它不引用调用add的Rational对象。要访问上面的分子和分母,需要将它们放入字段中

下面给出了正确的实现方法:

class Rational(n: Int, d: Int) { // This won't compile
  require(d != 0)
  override def toString = n + "/" + d

  def add(that: Rational): Rational = new Rational(n * that.d + that.n * d, d * that.d)
}
class Rational(n: Int, d: Int) {
  require(d != 0)
  val numer: Int = n
  val denom: Int = d

  override def toString = numer + "/" + denom

  def add(that: Rational): Rational =
    new Rational(
      numer * that.denom + that.numer * denom,
      denom * that.denom
    )
}
我多次试图理解这一点,但仍然不清楚

我已经有了类级别的
n
d
参数。我可以在
add
方法中访问它们。我正在将另一个
Rational
对象传递给
add
方法。它还应该有
n
d
,对吗

that.n
that.d
有什么问题?为什么我需要在字段中获取参数

另外,被重写的
toString
方法只是简单地取
n
d
,这怎么不失败呢


我可能听起来很愚蠢,但在我继续之前,我确实需要清楚地理解这一点,以便更好地了解基本原理。

传递给类构造函数的参数默认为私有成员,因此可用于所有类代码(如
toString
覆盖中所示),但它们不能作为实例成员访问(因此,
说明.d
不起作用)

您可以告诉编译器不要使用默认值

class Rational(val n: Int, val d: Int) { // now it compiles
  ...
或者,传递给
案例类的参数默认为实例成员

case class Rational(n: Int, d: Int) { // this also compiles
  ...

Scala比Java有更多类型的访问修饰符。在Scala中有一种叫做
private[this]
的东西,它意味着“对当前对象私有”,比普通的
private
更严格,后者意味着“对这个类的所有对象私有”

基本上与

class Rational(private[this] val n: Int, private[this] val d: Int)
从更高的、近乎哲学的角度来看,你可以这么说

class Rational(n: Int, d: Int) { ... }
就像一个静态方法返回一个
Rational
,它有参数
n
d
,并且在任何方法中,它的参数都是方法的局部参数。通过使用
val
var
限定参数,您可以将这些参数转换为
Rational
的字段,而不必将它们写入twice:一次作为方法的参数(或构造函数,这是此静态方法更具体的名称),一次作为字段