• 26
  • 2月

昨天被老师叫去给一个系统擦屁股,看到了一段实在是让我很无语的程序。不批一下难解我心头之不爽。

其实就是一个非常简单的功能:从数据库中读出一段时间内的流水,起始时间:(ayear, amonth, aday),结束时间:(byear, bmonth, bday)——变量的命名已经反映了这段程序的质量。

因为要从两张表里读数据,此仁兄居然写出了如此“高技术含量”的代码,大体如下:

for(int i=ayear;i< =byear;i++)
{
	if(i-ayear>0)
	{
	amonth=1;
	}
	for(int j=amonth;j< =12;j++)
	{
		if((i-byear==0)&&j>bmonth)
		break;
		for(day=1;day< =31;day++)
		{
			sql="select * from lxd where jzrq ='"+String.valueOf(i)+"-"+String.valueOf(j)+"-"+String.valueOf(day)+"' and qymc='"+qymc+"' and qyzh='"+qyzh+"' and xhflag is null";
			// 略去中间输出用代码

			sql="select * from dwls where sj = '"+String.valueOf(i)+"-"+String.valueOf(j)+"-"+String.valueOf(day)+"' and dwmc='"+qymc+"' and qyzh='"+qyzh+"' and del is null "+order;
			// 略去中间输出用代码
		}
	}
}

真不知此仁兄的数据库原理一课是怎么学的,为了把两张表的数据凑在一起居然写出了这么一陀代码。试问有哪本讲SQL的书中会不教联合查询。上面这陀东西不就是实现了这么点功能吗?

select * from lxd inner join dwls on lxd.jzrq=dwls.sj where lxd.jzrq between A and B

一个是查N天的数据生成2*N条SQL语句,另一个则不管查多少天一条搞定。

早就听说过一个说法,一个好的程序员和一个差的程序员写出来的代码效率会有上千倍的差距。此话果然不假。

  • 17
  • 12月

刚刚在Ubuntu8.10下安装了Eclipse,结果在其中运行之前写的那些swing程序一运行就假死在那。所有界面元素都不响应,只能点窗口的关闭按钮强制退出。但自己在终端里用java命令运行则正常。

研究了半天算是找到了问题所在——虚拟机版本。Ubuntu源里默认安装的Eclipse使用的是java-1.5.0-gcj的虚拟机运行java程序。在Eclipse中选择Window-Preferences,在左侧找到Java-Installed JREs,点右侧Search按钮,定位到/usr/lib/jvm即可让Eclipse找到系统中安装的其他JRE,在选择java-6-sun后问题解决。

  • 19
  • 2月

实现Java中TextField或JTextField输入内容后按回车进行处理,只需在TextField或JTextField上简单地绑定一个ActionListener:

JTextField testField=new JTextField();
testField.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent event){
        // 处理焦点在文本框中按回车键的事件
    }
});
  • 19
  • 2月

Java对String的操作提供了两个类StringBuffer和StringBuilder(我是说操作,如果你直接用String对象进行大量的字符串操作,我只能说声佩服)。为什么要提供这样两个类呢?

查阅JDK得知:StringBuilder是在java1.5中新加的类,在使用上与StringBuffer主要的区别只是StringBuilder不是线程安全的,在编写非多线程程序时使用StringBuilder速度能快一些。

与此类似的还有Vector和ArrayList,同样前者是线程安全的,后者是在JDK较新的版本中加入的非线程安全的实现(java1.2时加入的)。

其实只要不是在太大规模和程序上使用,是否线程安全对运行的影响是很难看出来的。而且如果你根本不知线程为何物的话,选择非线程安全的类一般不会有任何问题:)

参考:

  1. 是 String,StringBuffer还是StringBuilder?
  2. 精辟的String与StringBuffer(StringBuilder)的区别
  • 16
  • 1月

上周我们进行了最后一周的课程:操作系统课程设计。

这个名字听起来挺吓人,不过实际上比期中的那个系统软件分析与设计简单多了。老师出的题目不过是让实现一个多线程的演示程序。由于只是个演示用途,也没有限制开发环境。但有一点特殊的是这次课程是分组做的,老师按照学生名单每相邻三个人分为一组,完成同一个任务。我被分到和班里学习最好的两个女生一起完成第一道题:演示对两个缓冲区的put、move、get操作。

说实话,不过是一个简单的演示程序。后面用Java的Lock和Condition实现一个buffer的model,用swing做一个图形界面,再写个controller就可以了。上学期编的那个连连看才花了我四天时间。但现在我要和两个女生合作,这个难度可就高了一个数量级。不过毕竟是团队嘛,如果我什么都不管,自己单干的话确实也不是很好(我一哥们选择了这条路,自己单独完成一道题)。

一周的课设下来,大概花了一半的时间解释和讨论程序的思路和实现方法,一半的时间用在编码上。总算在让大家都基本明白程序是怎么回事的基础上完成了设计。而且体会到了给别人讲解确确实实是提升自己理解能力的非常好的方法。

以下是我自己写的缓冲区类,存放自定义的数据类型Data,这个类型里只包括一个整型的id和Color型的随机颜色信息:

package model;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author riqe
 * buffer
 */
public class SynchBuffer {

	private Data[] buffers;
	private int head;
	private int rear;
	private Lock bufferLock;
	private Condition puttable;
	private Condition takable;
	public Statistic statistic;

	public SynchBuffer(int size){
		buffers=new Data[size+1];
		head=0;
		rear=0;
		bufferLock=new ReentrantLock();
		puttable=bufferLock.newCondition();
		takable=bufferLock.newCondition();
		statistic=new Statistic();
	}

	/**
	 * Put data into the buffer.
	 * It will cause the calling thread blocked
	 *  when the buffer is being operated or full.
	 * @param value data to put into the buffer.
	 * @param delay millisecond to delay after put the data in.
	 */
	public void put(Data value,int delay){
		bufferLock.lock();
		try{
			while((head-rear+buffers.length)%buffers.length==1)
				puttable.await();
			buffers[rear]=value;
			rear=(rear+1)%buffers.length;
			statistic.addPutCount();
			takable.signalAll();
			Thread.sleep(delay);
		}catch (InterruptedException e) {

		}finally{
			bufferLock.unlock();
		}
	}

	/**
	 * Take data out of the buffer.
	 * It will cause the calling thread blocked
	 *  when the buffer is being operated or empty.
	 * @param delay millisecond to delay after take the data out
	 * @return
	 */
	public Data take(int delay){
		Data getValue=null;
		bufferLock.lock();
		try{
			while((buffers.length+head-rear)%buffers.length==0)
				takable.await();

			getValue=buffers[head];
			head=(head+1)%buffers.length;
			statistic.addTakeCount();
			puttable.signalAll();
			Thread.sleep(delay);
		}catch (InterruptedException e) {

		}finally{
			bufferLock.unlock();
		}
		return getValue;
	}

	/**
	 * clear up the buffer.
	 */
	public void sweep(){
		bufferLock.lock();
		rear=head;
		bufferLock.unlock();
	}
}

附上这次的成果,jar文件,安装Java Runtime Environment双击即可运行。
双缓冲操作显示

  • 10
  • 11月

在中文Windows平台下,Java读取文本文件是以ANSI编码的,这样在打开utf-8编码的中文文件时会乱码,解决方案参考以下文章:

搜斧SearchFull – Java读取UTF-8/UNICODE等字符编码格式的文本文件

其核心为InputStreamReader 类,它负责Java输入中的编码转换。JDK里对其说明为:“It reads bytes and decodes them into characters using a specified charset.

在遇到输入中文乱码问题的时候,只需要把它套在原有的Reader里,设置好输入源的编码即可正确输入。

  • 19
  • 9月

用了一个多月的工厂模式,但一直不过是在用Java中它来做数据库链接的生成,一个“ConnectionFactory.getConnection();”就可以搞定一个Connection,用到链接的时候就不用写那一大堆加载数据库驱动程序、写数据库链接字符串等的操作了。修改数据库链接时也会容易得多。原以为工厂模式不过就这些作用了。

最近从图书馆借了本《WebWork in Action》,恶补WebWork的基础知识(以前就靠从网上找来的几个Doc文件指导,都已经用了半个多月了……),确实理清了WebWork的工作机理。同时,也更了解的一些设计模式的作用。

实际上工厂类的最大作用是实现了类和其所用资源的解耦。这样类中就可以用接口类型的变量来接收工厂生成的对象,而不是自己去实列化一个硬编码、完全确定类型的对象。这样类所接收的资源类型就是可变化的了。最明显的应用就是在代码的测试过程中,你可以让工厂返回一个模拟对象,而不是真实对象来实现方便的测试。

总之一句话:工厂模式给了我们为类提供所需资源的主动权。我们可以根据需要设置工厂,让其返回适当类型的资源,而不需要改动资源使用者的代码。

  • 14
  • 8月

最近在用netbeans研究Webwork开发,在被折腾死去活来,差点被气得把电脑从窗口扔出去后,终于用utf-8统一编码,搞定了中文乱码问题。

先声明一下自己使用的环境:WindowsXP + netbeans5.5.1中文版 + Webwork插件 + java1.6 + mysql5.0。使用netbeans内置Tomcat。

中文乱码的问题主要表现在

  • jsp中使用webwork的tag,Label中使用中文无法通过编译。提示“编码GBK的不可映射字符”。
  • 将中文写入mysql数据库中时,全部变成“??”

页面之间传参没有乱码。Action的结果页面可以正常接收并显示。

经过一番查找,找到了问题所在:

  • netbeans模板生成的jsp默认为utf-8编码
  • java源文件编码与本地系统一致,在Windows下应该是GB2312。
  • mysql的JDBC驱动默认使用ISO8859_1
  • mysql新建数据库字符型数据默认编码为Latin1

其中最后两项基本是兼容的,其他的之间就会兼容性问题了。乱码及变“?”就是在这些不同编码之间传递或组合之中出现的。

解决的原则很简单:统一编码。

我现在使用的是统一为utf-8,优点是确保在不同系统上的兼容性(目前几乎所有系统都能良好支持utf-8),缺点是中文一个字在utf-8编码中会占用3个字节,比gbk多占用一半的空间。

1)jsp文件无需改变。只需确认jsp头部有

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>

html头部有以下声明:

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

2)Java源文件

在netbeans中打开“工具”-“选项”,在打开的选项卡中点击左下角的“高级选项”,在左侧的树中找到“编辑”-“Java源代码”,在“缺省编码”中输入“utf-8”

3)数据库连接

连接数据库时的url中加入编码选择:

jdbc:mysql://localhost/regtest?user=root&password=root&useUnicode=true&characterEncoding=UTF8

4)数据库编码

在mysql中建库时将数据库的编码设为“utf8_general_ci”。

OK,在我的系统上完成这些后乱码再也没出现过。有空的话再研究一下gbk编码下的解决。

  • 07
  • 8月

决定玩一玩Jsp,于是要安装Tomcat。

前一阵子玩php时安装了一个EasyAPM的WAMP套件,所以现在机子上已经有Apache2.0.55了。且由于我SubVersion的服务器也是架设在它上面,所以不想把它停掉。遂决定采取Tomcat与Apache集成的方式安装。结果这一装居然用了我几个小时…

首先说明一下我的基本配置:WinXP professional sp2,EasyAPM中带的Apache2.0.55,JRE1.5.0

1、到http://tomcat.apache.org/下载了最新版的Tomcat6.0.13(注意是Windows Service Installer版的)和Tomcat Connectors(注意官方下载列表中文件名最后的那个版本是该Connector对应Apache的版本,不要图高,要与自己的Apache配套,我就因为第一次下载了对应2.2.4的版本,弄的Apache都引导不起来…)

2、Tomcat除安装路径被改为D盘之外,全部默认。此时在浏览器中打开localhost:8080应该可以看到Tomcat的欢迎页面了。

3、把下载到的Connector“mod_jk-apache-2.0.59.so”改名为“mod_jk.so”复制到Apache安装目录下的modules目录下。

4、建立mod_jk所需的配置文件workers.properties:

(其中的work1是可自定义的名字,但必需与下一步在httpd.conf中的名字相同)

# Define 1 real worker using ajp13
worker.list=worker1
# Set properties for worker1 (ajp13)
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=8009

将其保存到”D:Program FilesApache Software FoundationTomcat 6.0workers.properties”

5、修改Apatch的配置文件,将mod_jk加入Modules列表并设置将servlet目录转发给Tomcat处理

打开Apache安装目录下conf下的httpd.conf文件。

在LoadModule块中加入一行:

LoadModule jk_module MyModules/mod_jk.so

在该文件底部追加:

JkWorkersFile "D:Program FilesApache Software FoundationTomcat 6.0workers.properties"
JkMount /servlet/* worker1

即将/servlet下的所有文件都交给Tomcat处理。如果你要处理跟目录下的jsp文件,可以再加一句:

JkMount /*.jsp worker1

重启Apache。

现在打开浏览器,访问localhost/servlet,应该返回Tomcat的错误信息了。

6、修改Tomcat主目录

现在Apache的主目录和Tomcat的主目录还不一致,做的Jsp还必须放在Tomcat的主目录下的servlet内才能正常运行。我们可以把它改到与Apache主目录在同一个地方,以方便运行。

打开Tomcat安装目录下conf下的server.xml,在<host>与</host>间加入

<Context path="" docBase="E:MySite" debug="0"  reloadable="true" crossContext="true"/>

将”E:MySite”改为你Apache的主目录所在地就OK了。

重启Tomcat,现在只要把jsp放入”E:MySiteservlet”就可以直接在浏览器中使用localhost/serverlet/helloworld.jsp的方式访问了。

另外关于Tomcat主目录和虚拟目录介绍,可以参见这篇文章

  • 05
  • 7月

这两天请了两天假,专心复习了两天的Java,没有去奥体中心。

我这学期根本没有买Java的课本,只是从图书馆借来一本英文原版的Core Java 2当作课本用了。而且仗着寒假里那点从《C#入门经典》中悟出的面向对象的理论,再加上这学期主要是在玩PHP。两天复习,确实让我发现了自己还有很多没有弄明白的地方。

复习感觉收获最大的就是终于明白了类继承时的所谓“域的隐藏与方法的覆盖”:

一个类B继承类A时。如果B中有与A同名的域fieldC,则实例化B的对象b时,A和B的fieldC都会存在于该对象中。直接访问b.filedC将会得到B的fieldC的值。但只要将b转换为A类型,就可以访问到A的fieldC,就像这样((A)b).fieldC。这就是所谓的“隐藏”。

但如果B中有与A同名的方法methodD(),则实例化B的对象b时,该对象中只有一份filedD()的代码,不论是以b.methodD()访问还是((A)b).fieldD(),调用的都是B中的methodD()。这就是所谓的“覆盖”。

明后天继续到奥体去做志愿者,一周之内还得把我的Java课程设计“连连看”做出来。

加油!

所有标签:.net Ajax Java javascript Linux map MySQL RSS TD-SCDMA Ubuntu vim web Win7 乱码 基础知识 备份 奥运会 希望泉 性能 缓存 编程