Posts Tagged ‘java’

静态域的作用范围

August 25th, 2010

静态域的作用范围是在同一个类之内,类不仅有名称上的区别,还有classloader,即类加载器的问题,同一个class文件被不同的类加载器加载后,即便它们有相同的名称,但是它们并不是同一个类。因此在不同类加载器中同名类的静态变量是不共享的。下面做一个测试,来验证它。下面的Test类有一个静态域value,两个方法分别增加value的值和打印状态。

public class Test {
    private static int value = 1;
   
    public void increase() {
        value++;
    }
   
    public void print() {
        System.out.println("My Class Loader: "
            + this.getClass().getClassLoader() +  ", Value: " + value);
    }
}

下面的类StaticTest,运行时创建两个类加载器,分别载入同一个class文件,并通过反射依次调用print, increase,print方法。如果静态域在整个JVM内共享,那么value被加了两次,最后会输出3;否则应该输出2。由于类加载器会先向父类加载器请求类,找不到的时候才会自己加载,所以在运行这个测试时,一定不要把Test类先放到classpath中。

import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class StaticTest {
    public static void main(String[] args) throws Exception {
        URL[] classURLs = new URL[] {
            new URL("file:/home/sulong/tmp/")
        };
       
        URLClassLoader classLoader1 = new URLClassLoader(classURLs);
        URLClassLoader classLoader2 = new URLClassLoader(classURLs);
       
        test(classLoader1);
        System.out.println("--------------------");
        test(classLoader2);
    }
   
    private static void test(ClassLoader loader)
            throws Exception {
        Class clazz = loader.loadClass("Test");
        Object testObj = clazz.newInstance();
        invoke(clazz, testObj, "print");
        invoke(clazz, testObj, "increase");
        invoke(clazz, testObj, "print");
    }
   
    private static void invoke(Class clazz, Object obj, String name)
            throws Exception {
        Method method1 = clazz.getMethod(name, new Class[]{});
        method1.invoke(obj, new Object[]{});
    }
}

下面是我的机器上运行时的测试结果:

My Class Loader: java.net.URLClassLoader@7987aeca, Value: 1
My Class Loader: java.net.URLClassLoader@7987aeca, Value: 2
--------------------
My Class Loader: java.net.URLClassLoader@5d0385c1, Value: 1
My Class Loader: java.net.URLClassLoader@5d0385c1, Value: 2
  • Share/Bookmark

让JAXB生成序列化的类

November 20th, 2009

默认jaxb生成的类是没有序列化的,但是我们经常需要他们序列化。jaxb ri有生成序列化的类的这样的功能,但由于这不属于标准的功能,所以需要手动的开启。开启的方法是在用来生成java类的xml schema文件头添加如下内容:

<annotation>
    <appinfo>
        <jaxb:globalBindings generateIsSetMethod="true">
            <xjc:serializable uid="1"/>
        </jaxb:globalBindings>
    </appinfo>
</annotation>

另外,在使用jaxb的 xjc 编译器时,要加上 -extension 的参数。

  • Share/Bookmark

可恶的乱码问题

November 12th, 2009

在打印单据的时候,有两个汉字“玥”和“芃”,始终显示为“?”,这一问题困扰了业务人员一段时间了。以前没有空,就没有投入精力去查原因,上次得了空,终于把这个问题解决掉了。

这个乱码的汉字从哪里来的呢?首先是业务人员通过一个遗留的PHP应用,输入到一个mysql 4数据库中,然后我们的java程序从这个mysql 4中读取,再写入到新的mysql5的数据库中,最后通过java程序生成html在用户的浏览器里显示,结果就看到了这两个汉字乱码。那么这个问题如何解决呢?

只有两个汉字乱码,而不是所有的汉字都乱码,所以我们的程序一定使用了一种包含汉字较少的字符集,而这个出错的汉字恰好不在此字符集中,否则,就应当是大部分汉字乱码,而不仅仅是这两个了。很自然的就让人想到了 gb2312, gbk, gb18030, utf8等字符集之间的关系。其中gb2312中只有六千多个汉字,其它几个字符集支持的汉字数相差不多,我们程序一定是在该使用gbk, gb18030或utf8的地方使用了含有汉字较少的gb2312。

经查阅相关文档,果然发现那两个汉字都不在gb2312里,而在gbk, utf8字符集里。我们的mysql5使用的utf8字符集,生成的html也是utf8编码,如果mysql5中的汉字是正确的话,那么就应该能正常显示,因此,数据进入mysql5的时候就应该出错了。java程序在连接mysql5的时候,在jdbc连接中设置了utf8,所以如果从mysql4数据库中读取出来的是正确的,就不应该写入出问题,因此数据在mysql4中可能就错了,也可能是从mysql4中读取的时候出错了。php的兄弟们说mysql的数据库是gb2312字符集的,mysql的配置文件里也是这么配置的。如果果真如此,那么这个两个汉字在mysql4的数据库中就应该不正常了,所有的程序读出之后都应该是乱码,可是php的录入程序那边确实是能正常显示的。我断定这个数据库里放的实际上是gbk字符集的汉字。选用和mysql4相对应的mysql j connector 3.14,并在jdbc连接url里设置了characterEncoding=gbk,读出来的仍旧不正确!查阅了mysql j connector的文档,原来3 版本的mysql connector根本就不支持characterEncoding这个选项。看来只能修改mysql的配置文件了。修改之后,果然这两个汉字可以正常显示了。

如果计算机是中国人发明的,那么计算机也许一开始就得支持汉字,就再也没有乱码的问题。如果世界上只有一种汉字的编码方案,也不会有乱码的问题,可惜汉字偏偏有很多中编码方案。所以在我们的程序中,一定得搞清楚,我们的汉字数据来自于哪里,使用的哪种编码,每个环节都得配置得当,否则就会有乱码问题。

对于一般的web应用来说,需要关心编码的地方有:
1,数据库以什么编码存储数据
2,程序使用什么字符集连接数据库
3,程序内部运行时使用什么字符集
4,程序源码使用什么字符集
5,生成的html文件是什么字符集
6,程序告知浏览器的字符集
如果以上这些地方的字符集有配置不正确的地方,往往就会乱码。

如果可以的话,最好在所有的地方都使用一种编码,比如对于java应用来说,在所有的地方都使用utf8编码,就可以解决问题。需要注意的是,在windows环境下,默认的文件编码是gb18030的,而不是utf8。

另外,极端鄙视故意使用生僻字火星文的脑残族!!

  • Share/Bookmark

漫谈PHP和Java

September 27th, 2009

我为公司内部交流而写的PPT,谈论PHP和JAVA相关的话题。在这里查看:

漫谈PHP和Java

  • Share/Bookmark