关于swing.Button的构造

shivawu 2010-09-24
我们在构造一个swing button的时候会有这样一段代码,

new Button {
  text = "Click me"
}


看了下Button的源代码,没搞明白这个构造是调用了哪一个构造函数?

package scala.swing

import event._
import javax.swing._

object Button {
  def apply(text0: String)(op: => Unit) = new Button(Action(text0)(op))
}

/**
 * A button that can be clicked, usually to perform some action.
 *
 * @see javax.swing.JButton
 */
class Button(text0: String) extends AbstractButton with Publisher {
  override lazy val peer: JButton = new JButton(text0) with SuperMixin
  def this() = this("")
  def this(a: Action) = {
    this("")
    action = a
  }
  
  def defaultButton: Boolean = peer.isDefaultButton
  
  def defaultCapable: Boolean = peer.isDefaultCapable
  def defaultCapable_=(capable: Boolean) { peer.setDefaultCapable(capable) }
} 


照例说应该是Button(Action)这个构造函数,但是为什么=>Unit可以转换成Action呢?是因为button object中的apply函数么?
请高手解释一下。
night_stalker 2010-09-25
apply 是伴随对象的 () 方法,不是构造函数。

new Button { 
  text = "Click me" 
}

调用的是这个构造函数:
def this(a: Action) = { 
  this("") 
  action = a 
}


(=> Unit) 到 Action 大概有隐式转换吧 …… scaladoc 有全文检索就好了 ……
shivawu 2010-09-25
做了个小实验,大致知道了,实际往往看起来奇怪的问题都有很简单的解释。

应该就是一个匿名类,java中也有的功能。
public class Test1 {
	String str = "hello, world";
	public void test() {
		System.out.println(str);
	}
	
	public static void main(String[] args) {
		Test1 t = new Test1() {
			public void test() {
				System.out.println("override");
				System.out.println(str);
			}
		};

		t.test();
	}
}

输出一下t.getClass().getName()可以看到是Test1$1。

对应的,在scala中:

scala> new Button { text = "click me" }.getClass.getName
res6: java.lang.String = $anon$1

scala> (new Button).getClass.getName
res8: java.lang.String = scala.swing.Button

以前还真不习惯用匿名类override非abstract的方法。
我们在new Button { text = "click me" }中调用的是text_=方法,利用了scala中类的默认构造函数的函数体就是类的内部代码,加上Button.apply()等应该是为了达到同样的效果做的相应措施,所以看起来很有迷惑性。

scala果然是非常神奇的语言:)
itang 2010-09-28

确实是匿名类的处理, 使用scalac -Xprint:cleanup 验证一下:

 

  AnClassTest.scala

 

 

package testscala

import scala.swing.Button

object ButtonTest {
    def main(args: Array[String]) {
        val button = new Button {
            text = "Click me"
        }
        println(button.text)
    }
}

 

 

 

$>scalac -Xprint:cleanup testscala\AnClassTest.scala

 

 

[[syntax trees at end of cleanup]]// Scala source: AnClassTest.scala
package testscala {
  final class ButtonTest extends java.lang.Object with ScalaObject {
    def main(args: Array[java.lang.String]): Unit = {
      val button: scala.swing.Button = {
        new testscala.ButtonTest$$anon$1()
      };
      scala.this.Predef.println(button.text())
    };
    def this(): object testscala.ButtonTest = {
      ButtonTest.super.this();
      ()
    }
  };
  final class ButtonTest$$anon$1 extends scala.swing.Button { 
    def this(): testscala.ButtonTest$$anon$1 = {
      ButtonTest$$anon$1.super.this();
      ButtonTest$$anon$1.this.text_=("Click me");
      ()
    }
  }
}

 

 通过输出的语法树信息,可以很清晰的看出来:

1、new Button{} 方式 生成了匿名类, {} 块成了构造函数体

2、name = "xxx" 被转换成this.text_=("Click me"), 即调用在Button类定义的name_=方法

 

 

我们还可以做多点尝试:

 

        val button = new Button {
            text = "Click me"
            val more = "reflect this"
        }
        println(button.text)
        println(button.more)

 通过scalac -Xprint:cleanup ,可以知道对more的访问是通过反射做到的(略输出结果)

 如果限定button变量的类型为val button:Button = new Button{ ...}

那么"button.more"将会编译无法通过。 可见在“匿名类”的支持上,Scala跟Java是保持一致的,只不过编译时做了一些魔法。

 

Global site tag (gtag.js) - Google Analytics