关于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是保持一致的,只不过编译时做了一些魔法。
|