设计模式学习方法

设计模式学习方法

广义的设计模式是指一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且提高代码可靠性。

狭义的设计模式是指GoF在《设计模式:可复用面向对象的基础》一书中所介绍的23种经典设计模式。我们无论是在开发工作中,还是在面试笔试中,一般谈起设计模式就是指狭义的设计模式。

当然设计模式不知这23种,任何按照设计模式六大原则进行的设计,或在23种经典设计模式基础上的变种、组合应该都算设计“模式”,模式加引号是因为有些设计应用场景非常狭窄,可能是为了解决一个特定问题所产生的,也并不被大众所熟知。另外,还有一些为大家所熟知的,但是不在23种经典设计模式之中的设计,比如MVC设计模式。

阅读更多

Java中文编解码研究

先说编码(encode)

所谓的汉字编码,就是将一个个汉字,翻译成一个个字节(byte),进一步讲,是将一个字符串(String、char),转换成字节数组(byte[])。字节数组其实在各种编程语言中,用的地方还挺多,主要用在I/O方面。我们常说的二进制数据,在Java中,基本上可以等同于字节数组。所以,不论是序列化、文件操作、网络传输二进制流、输入输出二进制流,都会用到字节数组。

再通俗一点讲,汉字编码就是将一个汉字字符翻译成机器能识别的二进制数据。(非汉字同理)

主流的编码方式如下:

ASCII 码
学过计算机的人都知道 ASCII 码,总共有 128 个,用一个字节的低 7 位表示,0~31 是控制字符如换行回车删除等;32~126 是打印字符,可以通过键盘输入并且能够显示出来。

ISO-8859-1
128 个字符显然是不够用的,于是 ISO 组织在 ASCII 码基础上又制定了一些列标准用来扩展 ASCII 编码,它们是 ISO-8859-1~ISO-8859-15,其中 ISO-8859-1 涵盖了大多数西欧语言字符,所有应用的最广泛。ISO-8859-1 仍然是单字节编码,它总共能表示 256 个字符。

GB2312
它的全称是《信息交换用汉字编码字符集 基本集》,它是双字节编码,总的编码范围是 A1-F7,其中从 A1-A9 是符号区,总共包含 682 个符号,从 B0-F7 是汉字区,包含 6763 个汉字。

GBK
全称叫《汉字内码扩展规范》,是国家技术监督局为 windows95 所制定的新的汉字内码规范,它的出现是为了扩展 GB2312,加入更多的汉字,它的编码范围是 8140~FEFE(去掉 XX7F)总共有 23940 个码位,它能表示 21003 个汉字,它的编码是和 GB2312 兼容的,也就是说用 GB2312 编码的汉字可以用 GBK 来解码,并且不会有乱码。

GB18030
全称是《信息交换用汉字编码字符集》,是我国的强制标准,它可能是单字节、双字节或者四字节编码,它的编码与 GB2312 编码兼容,这个虽然是国家标准,但是实际应用系统中使用的并不广泛。

UTF-16
说到 UTF 必须要提到 Unicode(Universal Code 统一码),ISO 试图想创建一个全新的超语言字典,世界上所有的语言都可以通过这本字典来相互翻译。可想而知这个字典是多么的复杂,关于 Unicode 的详细规范可以参考相应文档。Unicode 是 Java 和 XML 的基础,下面详细介绍 Unicode 在计算机中的存储形式。

UTF-16 具体定义了 Unicode 字符在计算机中存取方法。UTF-16 用两个字节来表示 Unicode 转化格式,这个是定长的表示方法,不论什么字符都可以用两个字节表示,两个字节是 16 个 bit,所以叫 UTF-16。UTF-16 表示字符非常方便,每两个字节表示一个字符,这个在字符串操作时就大大简化了操作,这也是 Java 以 UTF-16 作为内存的字符存储格式的一个很重要的原因。(只能说绝大多数情况下是这样,后面有说明)

UTF-8
UTF-16 统一采用两个字节表示一个字符,虽然在表示上非常简单方便,但是也有其缺点,有很大一部分字符用一个字节就可以表示的现在要两个字节表示,存储空间放大了一倍,在现在的网络带宽还非常有限的今天,这样会增大网络传输的流量,而且也没必要。而 UTF-8 采用了一种变长技术,每个编码区域有不同的字码长度。不同类型的字符可以是由 1~6 个字节组成。

UTF-8 有以下编码规则:

如果一个字节,最高位(第 8 位)为 0,表示这是一个 ASCII 字符(00 – 7F)。可见,所有 ASCII 编码已经是 UTF-8 了。
如果一个字节,以 11 开头,连续的 1 的个数暗示这个字符的字节数,例如:110xxxxx 代表它是双字节 UTF-8 字符的首字节。
如果一个字节,以 10 开始,表示它不是首字节,需要向前查找才能得到当前字符的首字节

要了解Unicode就要了解UCS-2/UCS-4,还要了解BOM(Byte Order Mark)和BE/LE(Big Endian/Little Endian)。详细内容可读(http://blog.charlee.li/unicode-intro/)我这里只说一下结论吧:Unicode和UCS-2/UCS-4只是规定了字符用那些字节表示。UTF-8/UTF-16以及BOM才决定了字符在内存中真正的存储方式,真正的用什么样的字节存储,当然真正存储的时候,是需要根据UCS-2或UCS-4计算出的。

严格来说:UTF-16和UTF-8都是变长的,UTF-32才是定长的,UTF-16并不总是两个字节表示一个字符,UTF-16还可以表示UCS-4标准的字符,那个时候占用4字节,但是这一点基本上在开发中被忽略了,基本也可以被忽略。UTF-32之所以是4字节定长,是因为它完全用来表示UCS-4。

小插曲:四个“龍”字以田字形布局组成的一个汉字大家都没见过吧,但是确实在Unicode中有这个字,他用UTF-16存储就是4个字节。

我们常用的汉字,UTF-8是三字节,常用的英文字符,UTF-8是一字节。我们常用的汉字和英文字符,UTF-16都是双字节。所以UTF-8不一定比UTF-16省空间和流量,UTF-8比UTF-16更适合于网络传输的原因是,当丢失单个字节时,不会引起连锁的解码错误,而UTF-16丢失一个字节后,丢失位之后的所有字节解码都会出错。但是UTF-16占用空间更少,易于处理,所以UTF-16一般作为内存存储的编码方式。

再讲解码(decode)

解码是编码的反操作。如果说编码是将地球文字翻译成太阳文字,解码就是将太阳文字翻译成地球文字。

实际上,解码是将字节数组(byte[])按照源编码格式,翻译成汉字,或者翻译成另外一种编码格式的过程。

1、在编辑器中,如果你正在写一个.java文件,你点了保存或者Ctrl+S,这个内存中的java文件就要落地到磁盘上,这时候,系统必须要以一种编码格式对这个.java文件中的所有字符进行编码,才能翻译成二进制保存到磁盘上。

咱们编程都是英文编的,一般用任何编码方式都没什么问题。但如果你有一个变量String s=”一段中文”,这四个中文字符的存在,对文件编码格式提出了要求,可能会引起乱码。

默认情况下,保存是以操作系统的默认编码保存,一般中文操作系统是GBK。

(像notepad,可以保存成UTF-8,但是一定要保存成无BOM格式。)

理论上,java源文件,可以保存成任何编码格式,当然,如果有中文,这种格式必须支持中文,比如保存成GB2312\GBK\UTF-8\UTF-16都没有问题。

2、编译的时候。

用javac编译,是将.java文件的内容取出来,编译成.class文件。所以编译的时候,编译器得知道我之前.java文件是用那种编码方式进行的编码,如果不知道,取(解码)的时候,可就乱套了。我们可以运行一下javac -help命令,其中有一个参数-encoding就是干这件事的,官方解释是:指定源文件使用的字符编码。

如果不指定,则默认使用操作系统编码,一般中文操作系统是GBK。现在我们一般编程的时候,都会指定源码为UTF-8格式,用javac直接编译就会报错,错误提示一般是“编码GBK不可映射字符”或者“未结束的字符串面值”。那为什么我们一般很少遇到这种情况的,因为eclipse中,编译时的编码格式与文件格式一致,所以不会出现问题。这就是IDE为我们做的工作。

按照指定的源字符编码对二进制数据进行解码,这里解码后,不是用来输出,是马上用Unicode编码进行编码。Java编译的字节码文件,也就是.class文件中,所有的字符都是Unicode编码(实际是UTF-8)。这样,所有字节码文件就有了统一的,可支持全球语言的文件。

3、内存中

JVM加载.class文件的时候,就以Unicode编码方式加载就好了,汉字在内存里也是unicode方式存储的。这里实际是用UTF-16,估计是因为Java中的char数据类型都是双字节的吧。

实际上,char数据类型,在JVM中的标准就是UTF-16(无BOM)。String类型的实际存储是UTF-16BE。

4、使用时

无论我们是读取磁盘上的文件,还是读取网络传过来的数据流,我们必须知道他们正确的格式。并给我们的程序指定具体的解码类型。比如我有一个GB2312保存的本地文件,我用JAVA程序去读取里面的内容,起码我就得知道我应该用GB2312去解码,然后JVM会将解码后的字符串,转换成Unicode(UTF-16)。

当我们不知道源文件或源字符编码格式时,最好不要手动解码再编码,很有可能这个过程再也不可逆了。乱码了再也退不回的情况,我们在保存文件的时候经常遇到。(撤销操作另外,这里指再保存回原来格式的文本文件,乱码依然存在或者更严重)

5、JavaWeb开发时

说了这么多基础的知识,真到JavaWeb开发的时候,用到的可能性不大,除非是真的解决不了的编码问题,可以思考原理。

JavaWeb开发中一般需要注意的地方有这么几个:

所有的Java、JSP、XML等源文件都用UTF-8格式保存。
XML文件头行设置< ?xml version="1.0" encoding="UTF-8">
JSP设置编码格式< %@page contentType="text\html; charset=UTF-8"%>
HTML中加入
用框架的话设置框架的编码方式为UTF-8
获取表单参数之前调用request.setCharacterEncoding(“UTF-8″)
设置中间件(如Tomcat)Connector的URIEncoding=”UTF-8”
一般设置前四项都不会有问题。

阅读更多

Struts2中action的result跳转到另一个action时用param传参乱码问题

一般情况下,我们访问一个Action,返回一个success,展示一个JSP页面。用的方法是:

/WEB-INF/pages/login.jsp

这里result标签的type属性默认是dispatcher。正如官网所说:

If a type attribute is not specified, the framework will use the default dispatcher type, which forwards to another web resource. If the resource is a JavaServer Page, then the container will render it, using its JSP engine.

其实标签有很多配置项可配置,如果我们想实现某个功能,或者解决某个问题,很有可能struts2已经想到了。

我有一个需求:一个Action当返回结果是error时,跳转到另一个Action(1、改变URL。2、为了SiteMesh对两个Action有不同的装饰需求),并且还传一个message进去。按照网友一般的办法,这样是极好的,并且没有乱码的:

login.action

${message}

但是不知道为啥,我的message接受过来,始终是乱码。后来经过一番查找和实验,发现Tomcat默认编码方式不是我的UTF-8,是ISO-8859-1。这样修改一下:

问题解决。

当然,常规的避免乱码的方式都得有。网上一大堆,就不介绍了。

阅读更多

事务中间件 CICS 原理及应用开发[转载]

1.1 什么是CTG
1.1.1 概述
CICS系统是IBM大型机上的重要的交易处理系统,并且由于大型机的特殊性,导致CICS的已有应用程序对分布式平台开放不够,难以重用以往的应用程序。因此,CICS与分布式系统的交互,即外界如何访问CICS传统应用,成为一个重要的课题。
而CTG(CICS Transaction gateway,以下简称为CTG),CICS交易网关,是分布式平台连接到CICS的首选工具,它具有高性能,高安全性,高可扩展性等特性。
CTG与CICS的连接属于直接相连的方式,几乎不用修改CICS的已有应用,即可被外界访问。Web Services 同样可以实现与CICS的连接,但是相比于Web Services,CTG有以下优势:
(1)没有复杂的标准,技术相对成熟。
(2)利用已有的应用程序接口,很少需要对CICS程序进行修改。
本文中实例所使用的CICS Transaction Gateway软件为V7.2 for Windows版本。

阅读更多

Struts2整合Spring后Action线程安全问题思考

Struts1是非线程安全的,因为Struts1 的 Action 是单例模式,所以开发者要实现数据的同步。我们在Struts1的Action中使用的基本都是局部变量,而“局部变量是线程安全的。因为每执行一个方法,都会在独立的空间创建局部变量,它不是共享的资源。局部变量包括方法的参数变量”。在Struts 1中,所有的变量都是定义在Action中我们要执行的方法里的(Action中的execute方法或DispatchAction中指定要执行的方法),我们用于封装客户端请求参数的ActionForm,也是作为一个参数传入,也属于局部变量,因此,线程安全问题也不是很突出。

Struts2是线程安全的。Struts 2框架在处理每一个用户请求的时候,都建立一个单独的线程进行处理。Struts 2 的 Action 对象为每一个请求产生一个实例,因此,虽然在Action中定义了很多全局变量,所以说是线程安全的。

Spring整合Struts2后,由Spring托管Action对象,而Spring默认对于对象的管理都是单例的(Singleton)这样又会产生线程安全问题。但是有人说Spring用了Threadlocal避免了Spring的线程安全问题。为了解决这个疑问,本人做了测试。

奈何测试的代码和结果都在办公本上,不能联网。先贴出测试结果吧:

测试结果:Spring与Struts2整合存在线程安全问题。Threadlocal猜测用在了DAO的管理方面。

但是Action中的属性如果开发人员用Threadlocal包装,则Action可以用单例模式。

如果Action中的属性没有用Threadlocal包装的话,还是设置为prototype把。

阅读更多

为什么很多程序示例常用foo和bar来做函数或者变量名称?

是不是看到过很多的简单的Demo代码,都用foo和bar来做函数或者变量名称?

例如:

// C++ code

#include
using namespace std;

int main()
{
char foo[] = “Hello,”;
char bar[] = “World!”;
cout << foo << " " << bar << endl; return 0; } 虽然知道这肯定是某种约定俗成的写法,也隐约觉得是从国外传过来的,但是终究好奇这种写法是怎么来的,为什么不用A/B/C,One/Two/Three呢。去互联网上搜索了一番,像我一样对这个小事情怀着这样好奇心的人是有的,他们早就提出了自己的疑问。这个习惯的产生和发展估计比较复杂,所以如果要找一个标准答案,恐怕不是那么容易。

阅读更多

  • © 2013 知研片语
  • 京ICP备16042882号