随笔-46  评论-64  文章-2  trackbacks-0
 
new & valueof & 直接赋值的区别
首先来看下面这段代码
public static void main(String[] args) {
  String s1 = "s1";
  String s2 = new String("s2");
  String s3 = String.valueOf(12345);
}
 
编译成class文件之后,使用eclipse class file viewer查看
 
  // Method descriptor #15 ([Ljava/lang/String;)V
  // Stack: 3, Locals: 4
  public static void main(java.lang.String[] args);
     0  ldc <String "s1"> [16]
     2  astore_1 [s1]

     3  new java.lang.String [18]
     6  dup
     7  ldc <String "s2"> [20]
     9  invokespecial java.lang.String(java.lang.String) [22]
    12  astore_2 [s2]
    13  sipush 12345
    16  invokestatic java.lang.String.valueOf(int) : java.lang.String [25]
    19  astore_3 [s3]

    20  return
      Line numbers:
        [pc: 0, line: 12]
        [pc: 3, line: 13]
        [pc: 13, line: 14]
        [pc: 20, line: 20]
      Local variable table:
        [pc: 0, pc: 21] local: args index: 0 type: java.lang.String[]
        [pc: 3, pc: 21] local: s1 index: 1 type: java.lang.String
        [pc: 13, pc: 21] local: s2 index: 2 type: java.lang.String
        [pc: 20, pc: 21] local: s3 index: 3 type: java.lang.String
}
 
对于第一行代码 String s1 = "s1"; 编译成字节码之后,对应两条指令,
  1. ldc指令从运行时常量池push一个值到Frame的操作数栈上面,这个值在这里就是"s1"字符串的引用,
  2. astore指令将objectref存储到局部变量,这里也就是存储到局部变量s1。
 
对于第二行代码   String s2 = new String("s2");编译成字节码之后,对于的指令也用高亮标注出来了,这里把操作数栈的情况画了出来,希望能帮助理解。橙色标注的为栈顶元素。
  1. new指令会在堆上创建对象,操作数栈里压入创建的objectref,
     
    objectref
    ...
  2. dup指令复制操作数栈顶的元素, 
    objectref
    objectref
    ...
  3. ldc指令依然是从常量池push一个值到Frame的操作数栈上,这个值是"s2"字符串的引用。 
    "s2"_ref
    objectref
    objectref
    ...
  4. invokespecial 指令调用一个方法,这里就是调用String的构造函数,调用完成之后栈上还有一个objectref 
    objectref
    ...
  5. astore指令将objectref存储到局部变量,这里也就是存储到局部变量s2。 
                
    ...
 
对于第三行代码  String s3 = String.valueOf(12345); 编译成字节码之后对应的指令,
  1. sipush 将 12345 压栈
  2. invokestatic 调用 String.valueof(int) 方法
  3. astore 将栈顶的对象引用存储到本地变量s3 (这里不再深究这个栈顶元素是怎么来的了)
 
PMD检查代码的时候,有这样的warning: Avoid instantiating String objects.Call String.valueOf() instead. PMD给出的原因是In JDK 1.5, calling new String() causes memory allocation. String.valueOf() is more memory friendly.
 
经过上面的分解,我们应该知道原因了,以后写代码的时候,初始化一个字符串,  String s1 = "s1"; 这样的代码肯定比  String s2 = new String("s2");代码强,将其他类型的值转换成String的时候,valueof方法比new方法效率也高。

 
备注:
A frame is used to store data and partial results(局部变量,操作数栈), as well as to perform dynamic linking , return values for methods, and dispatch exceptions.
 
ldc指令的操作数栈: ...->...,value (value是int,float 或者 string 类型的引用)
astore的操作数栈: ...,objectref->...
new指令的操作数栈: ...->...,objectref
dup指令的操作数栈: ...,value->...,value,value
invokespecial的操作数栈: ...,objectref, [agr1,[arg2...]]->...
invloestatic的操作数栈:..., [arg1, [arg2...]] -> ...

 
如果要理解的更透彻建议阅读以下参考资料:
posted @ 2008-07-28 14:27 jht 阅读(1698) | 评论 (1)编辑 收藏

java.awt.Component.requestFocusInWindow

posted @ 2008-07-22 14:34 jht 阅读(380) | 评论 (1)编辑 收藏
http://www.blogjava.net/Files/jht/MyScreenSnap_2.0.zip

截图程序,设计目标:简单易用

支持全屏截图和选择截图,运行需要JRE1.5以上版本

在1.0版http://www.blogjava.net/Files/jht/MyScreenSnap.zip的基础上,

   * 修改了一下主界面,增加图片保存为BMP,GIF,JPG,PNG格式的功能

   * 参考了千里冰封的代码,加上了调整选择区域的功能

Source Code已经包含在压缩包里面了,有兴趣的可以down下来改改。

下面是1.0版本和2.0版本的两个界面。

1.0vs2.0.png
posted @ 2008-07-02 09:17 jht 阅读(327) | 评论 (1)编辑 收藏
其实是个简单的小问题,仅在此做个记录。

遇到这个问题的不妨读一下这篇文章先:Access查询和过滤条件 http://www.fontstuff.com/access/acctut06.htm

我遇到的报错语句如下:

update monitor_table set logoffTime ='2008-04-06 16:58:54', keyClickCount ='17' where userName ='abcd' and logonTime ='2008-04-06 16:56:36' 

读了上面的文章,知道 MS Access的时间分隔符号为 # ,而 MS SQL Server的时间分隔符为 '

所以正确的语句应该是:

update monitor_table set logoffTime ='2008-04-06 16:58:54', keyClickCount ='17' where userName ='abcd' and logonTime =#2008-04-06 16:56:36

posted @ 2008-05-19 15:39 jht 阅读(1905) | 评论 (1)编辑 收藏
http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96616/arxml24.htm
posted @ 2008-05-19 15:38 jht 阅读(186) | 评论 (0)编辑 收藏
如题,有人真的遇到过这个问题,开始被问到的时候还真觉得奇怪,心想不会啊,从JDK5开始就支持这个枚举类型了啊,为什么呢?

开始还怀疑他的JDK版本太低导致的,但是一看是JDK1.6的,迷惑了几秒。。。

然后我打开了Eclipse的Java编译选项,发现原来遇到这个问题的人的Java编译级别设置的是1.4,如下图,当然就会出问题了。

compile_setting.png

呵呵,虽然,这是个小问题,但是如果遇到了还真够新手郁闷一阵的。
posted @ 2008-04-02 20:56 jht 阅读(890) | 评论 (2)编辑 收藏

作者简介

徐皓,北京航空航天大学计算机系本科生,你可以通过ertri@163.com与他联系。

正文

不灵敏的图形用户界面会降低应用程序的可用性。当以下现象出现的时候,我们通常说这个用户界面反应不灵敏。

  1. 不响应事件的现象;
  2. 没有更新的现象
[@more@]

这些现象在很大程度上与事件的处理方法相关,而在编写Swing应用程序的时候,我们几乎必然要编写方法去响应鼠标点击按钮,键盘回车等事件。在这些方法中我们要编写一些代码,在运行时去触发一些动作。常见动作包括查找,更新数据库等。在这篇文章中通过对一个实例的分析,介绍了一些基本概念,常见的错误以及提出了一个解决方案。

event-dispatching thread

我们一定要记住,事件响应方法的代码都是在event-dispatching thread中执行的,除非你启用另一个线程。

那么,什么是event-dispatching thread呢?在《Java Tutorial》[1]中,作者给出了一条单一线程规则:一旦一个Swing组件被实现(realized),所有的有可能影响或依赖于这个组件的状态的代码都应该在event-dispatching thread中被执行。而实现一个组件有两种方式:

  1. 对顶层组件调用show(), pack(), 或者setVisible(true);
  2. 将一个组件加到一个已经被实现的容器中。

单一线程规则的根源是由于Swing组件库的大部分方法是对多线程不安全的,尽管存在一些例外。这些例外的情况可以在《Java Tutorial》[1]的相关章节找到,这里不再展开。

为了支持单一线程模型,Swing组件库提供了一个专门来完成这些与Swing组件相关的操作的线程,而这一线程就是event-dispatching thread。我们的事件响应方法通常都是由这一线程调用的,除非你自己编写代码来调用这些事件响应方法。在这里初学者经常犯的一个错误就是在事件响应方法中完成过多的与修改组件没有直接联系的代码。其最有可能的效果就是导致组件反应缓慢。比如以下响应按钮事件的代码:

String str = null;
this.textArea.setText("Please wait...");
try {
//do something that is really time consuming
str = "Hello, world!";
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.textArea.setText(str);    

执行之后的效果就是按钮似乎定住了一段时间,直到Done.出现之后才弹起来。原因就是Swing组件的更新和事件的响应都是在event-dispatching thread中完成的,而事件响应的时候,event-dispatching thread被事件响应方法占据,所以组件不会被更新。而直到事件响应方法退出时才有可能去更新Swing组件。

为了解决这个问题,有人也许会试图通过调用repaint()方法来更新组件:

final String[] str = new String[1];
this.jTextArea1.setText("Please wait...");
this.repaint();

try {
Thread.sleep(1000L);
}catch(InterruptedException e) {
e.printStackTrace();
}
str[0] = "Done.";

jTextArea1.setText(str[0]);

但是这一个方法没有起到预期的作用,按钮仍然定住一段时间,在察看了repaint()方法的源代码之后就知道原因了。

PaintEvent e = new PaintEvent(this, PaintEvent.UPDATE,
new Rectangle(x, y, width, height));
Toolkit.getEventQueue().postEvent(e);        

repaint()方法实际上是在事件队列里加了一个UPDATE的事件,而没有直接去重画组件,而且这一个事件只能等待当前的事件响应方法结束之后才能被分配。因此只有绕过分配机制直接调用paint方法才能达到目的。

final String[] str = new String[1];
this.jTextArea1.setText("Please wait...");
this.paint(this.getGraphics());

try {
Thread.sleep(1000L);
}catch(InterruptedException e) {
e.printStackTrace();
}
str[0] = "Done.";

jTextArea1.setText(str[0]);

这样却是实现了更新,但是还存在着以下的问题。虽然从感觉上,按钮已经弹起来了,但是在Done.出现之前,我们却无法按下这个按钮。可以说按钮还是定住了,只不过定在了弹起的状态。调用重绘方法无法从根本上解决问题,因此我们需要寻求其他的方法。

使用多线程

有效的解决方法是使用多线程。首先看一看一个更好的解决方案,这一方案是在参考《Rethinking Swing Threading》[3]的一个程序片段完成的:

final String[] str = new String[1];
this.jTextArea1.setText("Please wait...");
this.repaint();

new Thread() {
public void run() {
try {
Thread.sleep(1000L);
}catch(InterruptedException e) {
e.printStackTrace();
}
str[0] = "Done.";
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
jTextArea1.setText(str[0]);
}
});
}
}.start();

在这个程序中,要花费大量时间的操作被放到另一个线程当中,从而使事件响应方法能快速返回,event-dispatching thread就可以更新UI和响应其它事件了。注意到这个程序使用了invokeLater()方法。invokeLater()方法的作用是让event-dispatching thread去运行制定的代码。当然也可以不使用invokeLater()方法,但是这样就违背了单一线程原则,同时带来了一定程度的相对多线程的不安全性。到现在,解决方案似乎是完美的了,但是我们看一看在原来的程序添加下面的代码,尽管我们通常不这样做。

public void paint(java.awt.Graphics g) {
super.paint(g);
g.drawRect(1, 1, 100, 100);
}

我们会发现以前画的矩形被覆盖了一部分,原因是由于我们没用重画这一个矩形,因此在结尾加上对repaint()方法的调用。

final String[] str = new String[1];
this.jTextArea1.setText("Please wait...");
this.repaint();

new Thread() {
public void run() {
try {
Thread.sleep(1000L);
}catch(InterruptedException e) {
e.printStackTrace();
}
str[0] = "Done.";
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
jTextArea1.setText(str[0]);
repaint();
}
});
}
}.start();

如果你认为这段代码过于缺乏可读性,通过在《Java Tutorial》[1]里面介绍的SwingWorker来简化编程的方法。可以通过实现一个construct()方法来实现花费大量时间的操作和重写finished()方法来完成组件更新的工作。

this.jTextArea1.setText("Please wait...");

final SwingWorker worker = new SwingWorker() {
public Object construct() {
try {
Thread.sleep(1000L);
}catch(InterruptedException e) {
e.printStackTrace();
}
return "Done.";
}
public void finished() {
jTextArea1.setText(getValue().toString());
repaint();
}
};
worker.start();

在《Rethinking Swing Threading》[3],作者将以上的编程方式称为同步方式。另外作者提出了一个通过消息机制来实现相同功能的更清晰,但是需要编写更多代码的"异步"的方法。

结论

总之,我们在编写使用Swing组件的程序是要记住以下几点:

1、不要过多地占用event-dispatching thread;

2、与更新组件相关的代码要使用event-dispatching thread去执行;

3、要更新组件。

编写反应灵敏的图形用户界面还需要考虑很多问题,以上只是最基本的一部分。欢迎有兴趣的读者来信进行讨论。

posted @ 2008-03-13 17:53 jht 阅读(565) | 评论 (0)编辑 收藏

打开注册表编辑器,进入主键[HKEY_CURRENT_USER\Software\Microsoft\Command Processor],将“CompletionChar”键值设置为9。  

posted @ 2008-01-30 16:40 jht 阅读(704) | 评论 (0)编辑 收藏
在Struts中我们用html:errors标签在JSP页面上输出验证过程中产生的错误信息,错误信息一般来自于消息资源文件(xxx.properties文件,一般位于classes目录下,文本文件),当然错误信息也可以是不是资源文件中的文本消息,而是自定义的文本。接下来将详细讲述。

  先来看一个简单例子

1、资源文件错误信息来源(其格式为 key = value )
   
   error.test = this is a test error.

2、JSP页面中用于显示错误信息标签
  
   <html:errors property="testerror"/>

3、ActionFormBean的validate()方法中产生错误信息

   ActionErrors error = new ActionErrors();

   error.add("testerror",new ActionMessage("error.test"))
  
   return error;

 

  这个例子的功能就是在ActionForm Bean的validate()方法中产生一条名为:testerror的错误信息,错误信息息是资源文件中key为error.test的值。然后在页面上用html:errors标签输出testerror这条错误信息。

  这是最常用的一种功能,所有的错误信息都在资源文件里面。

  有人会问,错误信息只能存放在资源文件中吗,其实不是这样。不需要资源文件也可以产生错误信息

  我们再来看一下ActionMessage的另一种构造方法:

  ActionMessage(String key,boolean isresource)

  如果isresource值为true,则表示key是资源文件中的key,产生的消息就是与key相对应的消息
  如果isresource值为false,则表示key为一条普通的消息。

  如果上面的error.add改为error.add("testerror",new ActonMessage("这是一条自定义消息",false",));那么页面上显示的将是:这是一条自定义消息.


  另外还可以用ActionMessage产生复合消息,比如我们要输出:xxx不能用作用户名,其中xxx是一个变量。

  首先我们在资源文件中加一个条复合消息

  testmsg = {0}不能用作用户名。这里{0}是要被替换的参数。

  我们再来看一下ActionMessage的另一中构造方法
  ActionMessage(String key,Object value0);

  也就是说用value0的值来替换{0}

  我们修改error.add为error.add("testerror",new ActonMessage("testmsg","毛泽东"))

  那么JSP页面上将显示:毛泽东不能用作用户名。


  当然在一条复合消息中也可带多个参数,参数依次为{0},{1},{2}或更多
  例如:loginUser = 用户名:{0} 姓名:{1} 登录次数:{2}.....
  那么在产生错误消息时就用new ActionMessage(String key,Object value0,Object value1,Object  value2.....)或者使用对象数组new ActionMessage(String key,Object[] values)
  

  String[] detail = {"Admin","王晶","12"};
  error.add("testerror",new ActionMessage("loginUser",detail))


Note:

Cannot find message resources under key org.apache.struts.action.MESSAGE  错误的原因是没有配置资源文件

解决办法: 在struts-config.xml 中加入如下的一段

<message-resources parameter="application" null="false"></message-resources>


posted @ 2008-01-14 22:20 jht 阅读(1140) | 评论 (1)编辑 收藏

备忘:

> sqlplus ( < username > [/ < password > ][@ < connect_identifier > ] | /) [AS SYSDBA | AS SYSOPER] | /NOLOG
 SQL  >     desc   user_source;
 Name                                       
Null  ?    Type
  
--  --------------------------------------- -------- ---------------------------- 
  NAME                                                 VARCHAR2  (  30  )
 TYPE                                                
VARCHAR2  (  12  )
 LINE                                                
NUMBER  
  
TEXT                                                   VARCHAR2  (  4000  )

SQL 
>     select     TEXT     from   user_source   where   TYPE  =   '  PROCEDURE  '     and   NAME  =   '  Your_Procedure_name  '  ;

no rows selected

SQL 
>    var  out_var  number
exec  Your_Procedure_name ( '' , '' , '' ,:out_var)
print  out_var

posted @ 2007-11-28 14:00 jht 阅读(2730) | 评论 (0)编辑 收藏
仅列出标题
共5页: 上一页 1 2 3 4 5 下一页