2008年6月26日木曜日

GIF解码和编码操作库源码

GIF解码和编码操作库源码,共有四个类文件(请下载):
1.AnimatedGifEncoder.java2.GifDecoder.java3.LZWEncoder.java4.NeuQuant.java简单应用: import javax.imageio.ImageIO;
import java.io.*;
import java.awt.image.*;
public class Testgif{
public static void main(String args[]){
try{
BufferedImage src = ImageIO.read(new File("c:/work/1.jpg")); // 读入文件
BufferedImage src1 = ImageIO.read(new File("c:/work/2.jpg")); // 读入文件
BufferedImage src2 = ImageIO.read(new File("c:/work/3.jpg")); // 读入文件
AnimatedGifEncoder e = new AnimatedGifEncoder();
e.setRepeat(0);
e.start("c:/work/laoma.gif");
e.setDelay(3000); // 1 frame per sec
e.addFrame(src);
e.setDelay(1000);
e.addFrame(src1);
e.setDelay(100);
e.addFrame(src2);
e.finish();
}catch(IOException e){
e.printStackTrace();
}
}
}
下面的例子来自:http://blog.csdn.net/ideas/archive/2006/08/25/1116198.aspx作者: ideas
1 多张jpg图合成gif动画
/** *//** * 把多张jpg图片合成一张 * @param pic String[] 多个jpg文件名 包含路径 * @param newPic String 生成的gif文件名 包含路径 */
private synchronized void jpgToGif(String pic[], String newPic) ...{ try ...{ AnimatedGifEncoder e = new AnimatedGifEncoder(); e.setRepeat(0); e.start(newPic); BufferedImage src[] = new BufferedImage[pic.length]; for (int i = 0; i < src.length; i++) ...{ e.setDelay(200); //设置播放的延迟时间 src[i] = ImageIO.read(new File(pic[i])); // 读入需要播放的jpg文件 e.addFrame(src[i]); //添加到帧中 } e.finish(); } catch (Exception e) ...{ System.out.println( "jpgToGif Failed:"); e.printStackTrace(); } }
2 gif动画分解成多张jpg
/** *//** * 把gif图片按帧拆分成jpg图片 * @param gifName String 小gif图片(路径+名称) * @param path String 生成小jpg图片的路径 * @return String[] 返回生成小jpg图片的名称 */ private synchronized String[] splitGif(String gifName,String path) ...{ try ...{ GifDecoder decoder = new GifDecoder(); decoder.read(gifName); int n = decoder.getFrameCount(); //得到frame的个数 String[] subPic = new String[n]; String tag = this.getTag(); for (int i = 0; i < n; i++) ...{ BufferedImage frame = decoder.getFrame(i); //得到帧 //int delay = decoder.getDelay(i); //得到延迟时间 //生成小的JPG文件 subPic[i] = path + String.value(i)+ ".jpg"; FileOutputStream out = new FileOutputStream(subPic[i]); ImageIO.write(frame, "jpeg", out); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); encoder.encode(frame); //存盘 out.flush(); out.close(); } return subPic; } catch (Exception e) ...{ System.out.println( "splitGif Failed!"); e.printStackTrace(); return null; } }
3 根据提供的文字生成jpg图片
/** *//** * 根据提供的文字生成jpg图片 * @param s String 文字 * @param smallWidth int 每个字的宽度和高度是一样的 * @param bgcolor Color 背景色 * @param fontcolor Color 字色 * @param fontPath String 字体文件 * @param jpgname String jpg图片名 * @return */ private String createJpgByFont(String s, int smallWidth,Color bgcolor,Color fontcolor,String fontPath,String jpgname) ...{ try ...{ BufferedImage bimage = new BufferedImage(s.length()*smallWidth, smallWidth,BufferedImage.TYPE_INT_RGB); Graphics2D g = bimage.createGraphics(); g.setColor(bgcolor); //背景色 g.fillRect(0, 0, smallWidth, smallWidth); //画一个矩形 //去除锯齿(当设置的字体过大的时候,会出现锯齿) g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); g.setColor(fontcolor); //字的颜色 File file = new File(fontPath); //字体文件 //根据字体文件所在位置,创建新的字体对象(此语句在jdk1.5下面才支持) Font font = Font.createFont(Font.TRUETYPE_FONT, file); //font.deriveFont(float f)复制当前 Font 对象并应用新设置字体的大小 g.setFont(font.deriveFont((float) smallWidth)); g.drawString(s,0, smallWidth); //在指定坐标除添加文字 g.dispose(); FileOutputStream out = new FileOutputStream(jpgname); //指定输出文件 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bimage); param.setQuality(50f, true); encoder.encode(bimage, param); //存盘 out.flush(); out.close(); } catch (Exception e) ...{ System.out.println( "createJpgByFont Failed!"); e.printStackTrace(); } }
4 多张小jpg图合成一张大JPG图,在这里对大图只作宽度限制,不做高度限制
/** *//** * 将多个小图片合成一张大jpg图 (小的jpg图片按照行列顺序平铺) * @param smallJPG ArrayList 一组小的jpg图片 * @param bigWidth int 大图宽度 * @param smallWidth int 单个文字生成的小图的宽度和高度是一致的 * @return */ private void createBigJPG(ArrayList smallJPG, int bigWidth, int smallHeigh,Color bgColor ,String picName) ...{ try ...{ if (bigWidth < smallWidth) //如果大图片的高度比小图片的高度还小 直接返回 return; int colCount = bigWidth / smallWidth; //每行放置的字数 int leftMargin = (int) ((bigWidth - colCount * smallWidth) / 2f); //左边距 int rowCount = smallJPG.size(); //小图行数 int setWidth = bigWidth; //每列中间不留空隙,只留左右边距 int setHeight = smallWidth * rowCount ; //按照大图片宽高绘制一个背景图片 BufferedImage bufImage = new BufferedImage(setWidth, setHeight, BufferedImage.TYPE_INT_RGB); Graphics2D g = bufImage.createGraphics(); g.setColor(bgColor); //背景的颜色 g.fillRect(0, 0, setWidth, setHeight); int y = 0; //纵坐标 for (int i = 0; i < rowCount; i++) ...{ //遍历每行 ArrayList col = (ArrayList) (smallJPG.get(i)); int x = leftMargin; //横坐标 可能会出现左边距 for (int j = 0; j < col.size(); j++) ...{ String jpgname = (String) (col.get(j)); ImageIcon icon = new ImageIcon(jpgname); Image img = icon.getImage(); int imgWidth = img.getHeight(null); g.drawImage(img, x, y, null); x += imgWidth; } y += (smallWidth); } g.dispose(); FileOutputStream out = new FileOutputStream(picName); //指定输出文件 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); //设置文件格式 JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bufImage); //从图片缓冲中读取 param.setQuality(50f, true); encoder.encode(bufImage, param); //存盘 out.flush(); out.close(); } catch (Exception e) ...{ System.out.println( "createBigJPG Failed!"); e.printStackTrace(); } }

eucJP-ms

eucJP-ms



TOG/JVC
(オープン・グループ / 日本ベンダ協議会) CDE/Motif 技術検討 WG が定めたコードセット名です。UI-OSF共通日本語EUC にユーザー定義文字とIBM拡張文字、NEC特殊文字を追加した 日本語EUC (eucJP-open) と Unicode (UCS) との間のコード変換規則に Microsoft Windows NT 3.51 の式の変換規則を用いる場合に、このコードセット名を用います。



Unicode 経由で Windows-31J で使用できる全文字 (コードポイント) の相互変換が可能となるように変換規則が定められています。



変換規則



eucJP-ms の変換規則の概要は次の通りです。




EUC コードセット0 (ASCII)



  • ASCII (ISO/IEC 646 IRV) とみなして Unicode に変換する。




EUC コードセット1 (JIS X 0208 + NEC特殊文字 + ユーザー定義文字)



  • 1区~84区は Microsoft Windows NT 3.51 での 1区~84区の変換と同様の変換をする。

  • 85区~94区 (ユーザー定義文字領域) は、U+E000~U+E3AB (私用領域) に変換する。




EUC コードセット2 (JIS X 0201 片仮名)



  • U+FF61~U+FF9F (HALFWIDTH KATKANA) に変換する。




EUC コードセット3 (JIS X 0212 + JIS X 0208/0212 に無いIBM拡張文字 + ユーザー定義文字)



  • JIS X 0212 補助漢字は、それぞれ対応する Unicode のコードポイントに変換する。

  • 83区~84区 (JIS X 0208/0212 に無いIBM拡張文字) は、それぞれ対応する Unicode のコードポイントに変換する。

  • 85区~94区 (ユーザー定義文字領域)は、U+E3AC~U+E757 (私用領域) に変換する。





TOG/JVC CDE/Motif 技術検討 WG の資料では、NEC特殊文字についての記述がありませんが、同WG の資料「Unicode とユーザ定義文字・ベンダ定義文字に関する問題点と解決策」では eucJP-ms について「Windows の動作するコンピュータとの間のデータ交換 に使われることを想定している」とあるので、それに必要な変換規則を補ってあります。



eucJP-ms の変換表は、このページの最後に掲げる「参考文献・資料等」の「オープン・グループ」の Web ページから入手可能です。



各文字セットの eucJP-ms でのコード割り当て



eucJP-ms での NEC特殊文字、IBM拡張文字、ユーザー定義文字のコード割り当てを簡単に説明します。




NEC特殊文字 (13区)

Windows-31J で 13区に定義されている NEC特殊文字は、EUC コードセット 1 (JIS X 0208) の 13区にそのまま割り当てられています。


次の文字コード表の水色のコードポイントに割り当てられている文字は、JIS X 0208:1997 の 2区にも定義されている文字で、Unicode 経由で文字コードの変換を行うと、これらのコードポイントは、JIS のコードポイントに変換されます。また、灰色のコードポイントは、IBM特殊文字でも定義されています。重複符号化されている文字の変換については後で説明します。


13区の文字コード表



IBM拡張文字 (Windows-31J:115区~119区)

Windows-31J では、一部の記号文字を除いて89区~92区と115区~119区の両方でで重複して割り当てがなされていますが、eucJP-ms では、大文字のローマ数字を含む後者の文字セットが EUC コードセット3 に割り当てられています。詳細は次の通りです。



IBM拡張文字のうち、JIS X 0208, JIS X 0212 に対応する文字があるものについては、JIS のコードポイントを用います。


それ以外の文字については、コードセット3 の 84区94点から逆方向に割り当てられています。次の文字コード表に、その割り当てを示しておきます。灰色のコードポイントについては、NEC特殊文字の方にもあります。重複符号化されている文字の変換については後で説明します。


eucJP-ms コードセット3 83区の文字コード表


eucJP-ms コードセット3 84区の文字コード表


ユーザー定義文字 (95区~114区)

Windows-31J のユーザー定義文字領域 95区~114区は、次の2個所に分割して割り当てられています。



Windows31-J の 95区~104区

EUC コードセット0 の 85区~94区

Windows31-J の 105区~114区

EUC コードセット3 の 85区~94区




重複符号化されている文字



TOG/JVC CDE/Motif 技術検討 WG が配っている eucJP-ms の変換表では表1の文字が重複符号化されています。



ほとんどの文字は、Windows での Windows-31J と Unicode との変換の規則をそのまま適用可能ですが、次の文字に関しては JIS X 0212 補助漢字の文字と重複符号化されているため検討が必要です。




  1. U+2116 NUMERO SIGN

  2. U+FF5E FULLWIDTH TILDE



U+FF5E FULLWIDTH TILDE は、本来であれば、JIS X 0212 の2区23点 (EUCでは 0x8FA2B7) に対応させるべきですが、マイクソロソフトの Windows では、 JIS X 0208 の 1区33点 (WAVE DASH, EUC では 0xA1C1) を U+FF5E FULLWIDTH TILDE と対応付けている為、JIS X 0212 と組み合わせて使う場合に問題が生じます。



eucJP-ms は、Windows の動作するコンピュータとの間のデータ交換 に使われることを想定しているため、Windows-31J のコードポイントが正しく変換できるようにする必要があります。その事から、U+FF5E FULLWIDTH TILDE は、JIS X 0208 の1区33点 (0xA1C1) と対応付けるのが妥当と思われます。U+2116 NUMERO SIGN に関しても Windows-31J との文字コード変換を優先されるのが妥当と思われます。



以上のことを踏まえて、eucJP-ms で重複符号化されている文字は次のように変換するのが妥当と思われます。




  • Unicode → eucJP-ms の変換は、Unicode → Windows-31J と同じ規則を適用し表1 の○印の付いているコードポイントに変換する。

  • eucJP-ms → Unicode の変換は、多対1 の変換とする。































表1 eucJP-ms で重複符号化されている文字
文字UnicodeJIS X 0208NEC特殊文字JIS X 0212IBM拡張文字文字名称(Unicode)
№(No.) U+2116 0xADE2 ○ 0x8FA2F1 0x8FF4AC NUMERO SIGN
℡(TEL) U+2121 0xADE4 ○ 0x8FF4AD TELEPHONE SIGN
Ⅰ( I ) U+2160 0xADB5 ○ 0x8FF3FD ROMAN NUMERAL ONE
Ⅱ( II ) U+2161 0xADB6 ○ 0x8FF3FE ROMAN NUMERAL TWO
Ⅲ( III ) U+2162 0xADB7 ○ 0x8FF4A1 ROMAN NUMERAL THREE
Ⅳ( IV ) U+2163 0xADB8 ○ 0x8FF4A2 ROMAN NUMERAL FOUR
Ⅴ( V ) U+2164 0xADB9 ○ 0x8FF4A3 ROMAN NUMERAL FIVE
Ⅵ( VI ) U+2165 0xADBA ○ 0x8FF4A4 ROMAN NUMERAL SIX
Ⅶ( VII ) U+2166 0xADBB ○ 0x8FF4A5 ROMAN NUMERAL SEVEN
Ⅷ( VIII ) U+2167 0xADBC ○ 0x8FF4A6 ROMAN NUMERAL EIGHT
Ⅸ( IX ) U+2168 0xADBD ○ 0x8FF4A7 ROMAN NUMERAL NINE
Ⅹ( X ) U+2169 0xADBE ○ 0x8FF4A8 ROMAN NUMERAL TEN
U+221A 0xA2E5 ○ 0xADF5 SQUARE ROOT
U+2220 0xA2DC ○ 0xADF7 ANGLE
U+2229 0xA2C1 ○ 0xADFB INTERSECTION
U+222A 0xA2C0 ○ 0xADFC UNION
U+222B 0xA2E9 ○ 0xADF2 INTEGRAL
U+2235 0xA2E8 ○ 0xADFA BECAUSE
U+2252 0xA2E2 ○ 0xADF0 APPROXIMATELY EQUAL TO OR THE IMAGE OF
U+2261 0xA2E1 ○ 0xADF1 IDENTICAL TO
U+22A5 0xA2DD ○ 0xADF6 UP TACK
㈱((株)) U+3231 0xADEA ○ 0x8FF4AB PARENTHESIZED IDEOGRAPH STOCK
U+FF5E 0xA1C1 ○ 0x8FA2B7 FULLWIDTH TILDE


eucJP-ms を使用する上での注意点



以下のような問題があるため、eucJP-ms は、Windows-31J との相互変換のみに用い、なおかつ使用する文字は、Windows-31J と同等の文字に限定して使うのが望ましいと思われます。



Windows-31J と共通する注意点



  • 次の文字が、Unicode への変換が Unicodeコンソーシアムの JIS0208.TXT や、JIS X 0208:1997 の文字名称を元にした変換と異なるので注意が必要です。












    文字EUCeucJP-msJIS0208.TXTJIS X 0208:1997
    UnicodeUnicodeUnicode
    0xA1BDU+2015U+2015U+2014 EM DASH
    0xA1C1U+FF5EU+301CU+301C WAVE DASH
    0xA1C2U+2225U+2016U+2016 DOUBLE VERTICAL LINE
    0xA1DDU+FF0DU+2212U+2212 MINUS SIGN
    0xA1F1U+FFE0U+00A2U+00A2 CENT SIGN
    0xA1F2U+2225U+00A3U+00A3 POUND SIGN
    0xA2CCU+FFE2U+00ACU+00AC NOT SIGN




JIS X 0212 に関する注意点




  • Windows-31J に変換する時には、IBM拡張文字にある文字のみが変換可能です。


  • JIS X 0212 の次の区-点 位置の文字は、eucJP-ms → Unicode → eucJP-ms の変換で、次のように変換されます。






    JIS X 0212 区-点eucJP-msUnicodeeucJP-ms
    2-23 (TILDE)0x8FA2B7U+FF5E (FULLWIDTH TILDE)0xA1C1 (~)
    2-81 (NUMERO SIGN)0x8FA2F1U+2116 (NUMERO SIGN)0xADE2 (No.)


Unicode ⇔ UTF-8

Unicode ⇔ UTF-8
/**********************************************************************
*
* Unicode ⇔ UTF-8
*
* Copyright (c) 2005 AOK
*
**********************************************************************/
function _to_utf8(s) {
var c, d = "";
for (var i = 0; i < s.length; i++) {
c = s.charCodeAt(i);
if (c <= 0x7f) {
d += s.charAt(i);
} else if (c >= 0x80 && c <= 0x7ff) {
d += String.fromCharCode(((c >> 6) & 0x1f) 0xc0);
d += String.fromCharCode((c & 0x3f) 0x80);
} else {
d += String.fromCharCode((c >> 12) 0xe0);
d += String.fromCharCode(((c >> 6) & 0x3f) 0x80);
d += String.fromCharCode((c & 0x3f) 0x80);
}
}
return d;
}
function _from_utf8(s) {
var c, d = "", flag = 0, tmp;
for (var i = 0; i < s.length; i++) {
c = s.charCodeAt(i);
if (flag == 0) {
if ((c & 0xe0) == 0xe0) {
flag = 2;
tmp = (c & 0x0f) << 12;
} else if ((c & 0xc0) == 0xc0) {
flag = 1;
tmp = (c & 0x1f) << 6;
} else if ((c & 0x80) == 0) {
d += s.charAt(i);
} else {
flag = 0;
}
} else if (flag == 1) {
flag = 0;
d += String.fromCharCode(tmp (c & 0x3f));
} else if (flag == 2) {
flag = 3;
tmp = (c & 0x3f) << 6;
} else if (flag == 3) {
flag = 0;
d += String.fromCharCode(tmp (c & 0x3f));
} else {
flag = 0;
}
}
return d;
}

2008年6月5日木曜日

iRepotのPDF合併の実現

JasperPrint print1 = JasperFillManager.fillReport(report1, mp,
jrdsMain);
List jasperPrints = new ArrayList();
jasperPrints.add(print1);
jasperPrints.add(print1);
JRPdfExporter rtfExporter = new JRPdfExporter();
rtfExporter.setParameter(JRExporterParameter.JASPER_PRINT_LIST,
jasperPrints);
rtfExporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME,
jasperpdfFile);
try {
OutputStream os = response.getOutputStream();
rtfExporter.setParameter(JRExporterParameter.OUTPUT_STREAM, os);
rtfExporter.exportReport();
} catch (JRException e) {
e.printStackTrace();
}

2008年5月28日水曜日

java annotation使用手册

阅读提示:文中提到的程序成员或者程序元素是一个概念,指组成程序代码的单元:如类、方法、成员变量。

一、Annotation究竟是什么?

Annotation提供了一条与程序元素关联任何信息或者任何元数据(metadata)的途径。从某些方面看,annotation就像修饰符一样被使用,并应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中。这些信息被存储在annotation的“name=value”结构对中。annotation类型是一种接口,能够通过java反射API的方式提供对其信息的访问。

annotation能被用来为某个程序元素(类、方法、成员变量等)关联任何的信息。需要注意的是,这里存在着一个基本的潜规则:annotaion不能影响程序代码的执行,无论增加、删除annotation,代码都始终如一的执行。另外,尽管一些annotation通过java的反射api方法在运行时被访问,而java语言解释器在工作时忽略了这些annotation。
正是由于java虚拟机忽略了annotation,导致了annotation类型在代码中是“不起作用”的;只有通过某种配套的工具才会对annotation类型中的信息进行访问和处理。本文中将涵盖标准的annotation和meta-annotation类型,陪伴这些annotation类型的工具是java编译器(当然要以某种特殊的方式处理它们)。

由于上述原因,annotation在使用时十分简便。一个本地变量可以被一个以NonNull命名的annotation类型所标注,来作为对这个本地变量不能被赋予null值的断言。而我们可以编写与之配套的一个annotation代码分析工具,使用它来对具有前面变量的代码进行解析,并且尝试验证这个断言。当然这些代码并不必自己编写。在JDK安装后,在JDK/bin目录中可以找到名为“apt”的工具,它提供了处理annotation的框架:它启动后扫描源代码中的annotation,并调用我们定义好的annotation处理器完成我们所要完成的工作(比如验证前面例子中的断言)。说到这里,annotation的强大功能似乎可以替代XDoclet这类的工具了,随着我们的深入,大家会更加坚信这一点。

注:详细描述请参看jsr250规范:
http://www.jcp.org/aboutJava/communityprocess/pfd/jsr250/

二、Annotation的定义:

这段文字开始介绍annotation相关技术。在此大家将看到java5.0的标准annotation类型,这种标准类型就是前文中所说的“内建”类型,它们可以直接被javac支持。可喜的是,在java6.0beta版中的javac已经加入了对自定义annotation的支持。

1。Annotation的概念和语法:

首先,关键的概念是理解annotation是与一个程序元素相关联信息或者元数据的标注。它从不影响java程序的执行,但是对例如编译器警告或者像文档生成器等辅助工具产生影响。

下面是常用的annotation列表,我们应该注意在annotation和annotation类型之间的不同:

A.annotation:
annotation使用了在java5.0所带来的新语法,它的行为十分类似public、final这样的修饰符。每个annotation具有一个名字和成员个数>=0。每个annotation的成员具有被称为name=value对的名字和值(就像javabean一样),name=value装载了annotation的信息。

B.annotation类型:
annotation类型定义了annotation的名字、类型、成员默认值。一个annotation类型可以说是一个特殊的java接口,它的成员变量是受限制的,而声明annotation类型时需要使用新语法。当我们通过java反射api访问annotation时,返回值将是一个实现了该annotation类型接口的对象,通过访问这个对象我们能方便的访问到其annotation成员。后面的章节将提到在java5.0的java.lang包里包含的3个标准annotation类型。

C.annotation成员:
annotation的成员在annotation类型中以无参数的方法的形式被声明。其方法名和返回值定义了该成员的名字和类型。在此有一个特定的默认语法:允许声明任何annotation成员的默认值:一个annotation可以将name=value对作为没有定义默认值的annotation成员的值,当然也可以使用name=value对来覆盖其它成员默认值。这一点有些近似类的继承特性,父类的构造函数可以作为子类的默认构造函数,但是也可以被子类覆盖。

D.marker annotation类型:
一个没有成员定义的annotation类型被称为marker annotation。这种annotation类型仅使用自身的存在与否来为我们提供信息。如后面要说的Override。

E.meta-annotation:
meta-annotation也称为元annotation,它是被用来声明annotation类型的annotation。Java5.0提供了一些标准的元-annotation类型。下面介绍的target、retention就是meta-annotation。

F.target:
annotation的target是一个被标注的程序元素。target说明了annotation所修饰的对象范围:annotation可被用于packages、types(类、接口、枚举、annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在annotation类型的声明中使用了target可更加明晰其修饰的目标。

G.retention:
annotation的retention定义了该annotation被保留的时间长短:某些annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为annotation与class在使用上是被分离的)。使用这个meta-annotation可以对annotation的“生命周期”限制。

H.metadata:
由于metadata被广泛使用于各种计算机开发过程中,所以当我们在这里谈论的metadata即元数据通常指被annotation装载的信息或者annotation本身。

2。使用标准Annotation:
java5.0在java.lang包中定义了3种标准的annotation类型:

A.Override:
java.lang.Override是一个marker annotation类型,它被用作标注方法。它说明了被标注的方法重载了父类的方法,起到了断言的作用。如果我们使用了这种annotation在一个没有覆盖父类方法的方法时,java编译器将以一个编译错误来警示。
这个annotaton常常在我们试图覆盖父类方法而确又写错了方法名时发挥威力。

使用方法极其简单:在使用此annotation时只要在被修饰的方法前面加上@Override。
下面的代码是一个使用@Override修饰一个企图重载父类的toString方法,而又存在拼写错误的sample:
清单1:

@Overridepublic String toSting() { // 注意方法名拼写错了 return "[" + super.toString() + "]";}
B.Deprecated:
同样Deprecated也是一个marker annotation。当一个类型或者类型成员使用@Deprecated修饰的话,编译器将不鼓励使用这个被标注的程序元素。而且这种修饰具有一定的“延续性”:如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为@Deprecated,但编译器仍然要报警。

值得注意,@Deprecated这个annotation类型和javadoc中的@deprecated这个tag是有区别的:前者是java编译器识别的,而后者是被javadoc工具所识别用来生成文档(包含程序成员为什么已经过时、它应当如何被禁止或者替代的描述)。
在java5.0,java编译器仍然象其从前版本那样寻找@deprecated这个javadoc tag,并使用它们产生警告信息。但是这种状况将在后续版本中改变,我们应在现在就开始使用@Deprecated来修饰过时的方法而不是@deprecated javadoc tag。
清单2:

下面是一段使用@Deprecated的代码:/** * 这里是javadoc的@deprecated声明. * @deprecated No one has players for this format any more. Use VHS instead. */@Deprecated public class Betamax { ... }
C.SuppressWarnings:
@SuppressWarnings被用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告。在java5.0,sun提供的javac编译器为我们提供了-Xlint选项来使编译器对合法的程序代码提出警告,此种警告从某种程度上代表了程序错误。例如当我们使用一个generic collection类而又没有提供它的类型时,编译器将提示出"unchecked warning"的警告。

通常当这种情况发生时,我们就需要查找引起警告的代码。如果它真的表示错误,我们就需要纠正它。例如如果警告信息表明我们代码中的switch语句没有覆盖所有可能的case,那么我们就应增加一个默认的case来避免这种警告。

相仿,有时我们无法避免这种警告,例如,我们使用必须和非generic的旧代码交互的generic collection类时,我们不能避免这个unchecked warning。此时@SuppressWarning就要派上用场了,在调用的方法前增加@SuppressWarnings修饰,告诉编译器停止对此方法的警告。

SuppressWarning不是一个marker annotation。它有一个类型为String[]的成员,这个成员的值为被禁止的警告名。对于javac编译器来讲,被-Xlint选项有效的警告名也同样对@SuppressWarings有效,同时编译器忽略掉无法识别的警告名。

annotation语法允许在annotation名后跟括号,括号中是使用逗号分割的name=value对用于为annotation的成员赋值:
清单3:

@SuppressWarnings(value={"unchecked","fallthrough"})
public void lintTrap() { /* sloppy method body omitted */ }


在这个例子中SuppressWarnings annotation类型只定义了一个单一的成员,所以只有一个简单的value={...}作为name=value对。又由于成员值是一个数组,故使用大括号来声明数组值。

注意:我们可以在下面的情况中缩写annotation:当annotation只有单一成员,并成员命名为"value="。这时可以省去"value="。比如将上面的SuppressWarnings annotation进行缩写:
清单4:

@SuppressWarnings({"unchecked","fallthrough"})
如果SuppressWarnings所声明的被禁止警告个数为一个时,可以省去大括号:

@SuppressWarnings("unchecked")


3。Annotation语法:

在上一个章节中,我们看到书写marker annotation和单一成员annotation的语法。下面本人来介绍一下完整的语法:

annotation由“@+annotation类型名称+(..逗号分割的name-value对...)”组成。其中成员可以按照任何的顺序。如果annotation类型定义了某个成员的默认值,则这个成员可以被省略。成员值必须为编译时常量、内嵌的annotation或者数组。

下面我们将定义一个annotation类型名为Reviews,它有一个由@Review annotation数组构成的成员。这个@Review annotation类型有三个成员:"reviewer"是一个字符串,"comment" 是一个具有默认值的可选的字符串,"grade"是一个Review.Grade枚举类型值。
清单5:

@Reviews({ // Single-value annotation, so "value=" is omitted here @Review(grade=Review.Grade.EXCELLENT, reviewer="df"), @Review(grade=Review.Grade.UNSATISFACTORY, reviewer="eg", comment="This method needs an @Override annotation")})
annotation语法的另一个重要规则是没有程序成员可以有多于一个的同一annotation实例。例如在一个类中简单的放置多个@Review annotation。这也是在上面代码中定义@Reviews annotation类型数组的原因。

4。Annotation成员类型和值:

annotation成员必须是非空的编译时常量表达式。可用的成员类型为:primitive类型、, String, Class, enumerated类型, annotation类型, 和前面类型的数组。

下面我们定义了一个名为UncheckedExceptions 的annotation类型,它的成员是一个扩展了RuntimeException类的类数组。
清单6:

@UncheckedExceptions({
IllegalArgumentException.class, StringIndexOutOfBoundsException.class
})


5。Annotation的目标:

annotation通常被放在类型定义和成员定义的前面。然而它也出现在package、方法参数、本地变量的前面。下面,我们来讨论一下这些不大常用的写法:

package annotation出现在package声明的前面。
下面的例子package-info.java中不包含任何的公共类型定义,却包含一个可选的javadoc注释。
清单7:

/** * This package holds my custom annotation types. */@com.davidflanagan.annotations.Author("David Flanagan")package com.davidflanagan.annotations;

当package-info.java文件被编译时,它将产生名为包含annotation(特殊的接口)声明的package-info.class的类。这个接口没有成员,它的名字package-info不是一个合法的java标识,所以它不能用在java源代码中。这个接口的存在只是简单的被看作一个为package annotation准备的占位符。

用于修饰方法参数、catch参数、本地变量的annotation只是简单的出现在这些程序成员的修饰符位置。java类文件格式没有为本地变量或者catch参数存储annotation作准备,所以这些annotation总是保留在源代码级别(source retention);方法参数annotation能够保存在类文件中,也可以在保留到运行时。

最后,请注意,枚举类型定义中不允许任何的修饰符修饰其枚举值。

6。Annotation和默认值:
在Annotation中,没有默认值的成员必须有一个成员值。而如何理解默认值是如何被处理就是一个很重要的细节:annotation类型所定义的成员默认值被存储在class文件中,不被编译到annotation里面。如果我们修改一个annotation类型使其成员的默认值发生了改变,这个改变对于所有此类型的annotation中没有明确提供成员值的成员产生影响(即修改了该成员的成员值)。即使在annotation类型使其成员的默认值被改变后annotation从没被重新编译过,该类型的annotation(改变前已经被编译的)也受到影响。

三、Annotation工作原理:

Annotation与反射
在java5.0中Java.lang.reflect提供的反射API被扩充了读取运行时annotation的能力。让我们回顾一下前面所讲的:一个annotation类型被定义为runtime retention后,它才是在运行时可见,当class文件被装载时被保存在class文件中的annotation才会被虚拟机读取。那么reflect是如何帮助我们访问class中的annotation呢?

下文将在java.lang.reflect用于annotation的新特性,其中java.lang.reflect.AnnotatedElement是重要的接口,它代表了提供查询annotation能力的程序成员。这个接口被java.lang.Package、java.lang.Class实现,并间接地被Method类、Constructor类、java.lang.reflect的Field类实现。而annotation中的方法参数可以通过Method类、Constructor类的getParameterAnnotations()方法获得。

下面的代码使用了AnnotatedElement类的isAnnotationPresent()方法判断某个方法是否具有@Unstable annotation,从而断言此方法是否稳定:
清单8:

import java.lang.reflect.*;Class c = WhizzBangClass.class; Method m = c.getMethod("whizzy", int.class, int.class); boolean unstable = m.isAnnotationPresent(Unstable.class);

isAnnotationPresent()方法对于检查marker annotation是十分有用的,因为marker annotation没有成员变量,所以我们只要知道class的方法是否使用了annotation修饰就可以了。而当处理具有成员的annotation时,我们通过使用getAnnotation()方法来获得annotation的成员信息(成员名称、成员值)。这里我们看到了一套优美的java annotation系统:如果annotation存在,那么实现了相应的annotation类型接口的对象将被getAnnotation()方法返回,接着调用定义在annotation类型中的成员方法可以方便地获得任何成员值。

回想一下,前面介绍的@Reviews annotation,如果这个annotation类型被声明为runtime retention的话,我们通过下面的代码来访问@Reviews annotation的成员值:
清单9:

Class target = WhizzBangClass.class;

Reviews annotation = (Reviews)target.getAnnotation(Reviews.class);
// 因为@Reviews annotation类型的成员为@Review annotation类型的数组,
// 所以下面声明了Review[] reviews保存@Reviews annotation类型的value成员值。
Review[] reviews = annotation.value();
// 查询每个@Review annotation的成员信息
for(Review r : reviews) {
Review.Grade grade = r.grade();
String reviewer = r.reviewer();
String comment = r.comment();
System.out.printf("%s assigned a grade of %s and comment '%s'%n",
reviewer, grade, comment);
}


四、如何自定义Annotation?

1.详解annotation与接口的异同:
因为annotation类型是一个非凡的接口,所以两者之间存在着某些差异:

A.Annotation类型使用关键字@interface而不是interface。
这个关键字声明隐含了一个信息:它是继承了java.lang.annotation.Annotation接口,并非声明了一个interface。

B.Annotation类型、方法定义是独特的、受限制的。
Annotation类型的方法必须声明为无参数、无异常抛出的。这些方法定义了annotation的成员:方法名成为了成员名,而方法返回值成为了成员的类型。而方法返回值类型必须为primitive类型、Class类型、枚举类型、annotation类型或者由前面类型之一作为元素的一维数组。方法的后面可以使用default和一个默认数值来声明成员的默认值,null不能作为成员默认值,这与我们在非annotation类型中定义方法有很大不同。
Annotation类型和它的方法不能使用annotation类型的参数、成员不能是generic。只有返回值类型是Class的方法可以在annotation类型中使用generic,因为此方法能够用类转换将各种类型转换为Class。

C.Annotation类型又与接口有着近似之处。
它们可以定义常量、静态成员类型(比如枚举类型定义)。Annotation类型也可以如接口一般被实现或者继承。

2.实例:
下面,我们将看到如何定义annotation类型的example。它展示了annotation类型声明以及@interface与interface之间的不同:
清单10:

package com.davidflanagan.annotations;
import java.lang.annotation.*;

/**
* 使用annotation来描述那些被标注的成员是不稳定的,需要更改
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Unstable {}


下面的另一个example只定义了一个成员。并通过将这个成员命名为value,使我们可以方便的使用这种annotation的快捷声明方式:
清单11:

/** * 使用Author这个annotation定义在程序中指出代码的作者 */public @interface Author { /** 返回作者名 */ String value();}
以下的example更加复杂。Reviews annotation类型只有一个成员,但是这个成员的类型是复杂的:由Review annotation组成的数组。Review annotation类型有3个成员:枚举类型成员grade、表示Review名称的字符串类型成员Reviewer、具有默认值的字符串类型成员Comment。
清单12:

import java.lang.annotation.*;

/**
* Reviews annotation类型只有一个成员,
* 但是这个成员的类型是复杂的:由Review annotation组成的数组
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Reviews {
Review[] value();
}

/**
* Review annotation类型有3个成员:
* 枚举类型成员grade、
* 表示Review名称的字符串类型成员Reviewer、
* 具有默认值的字符串类型成员Comment。
*/
public @interface Review {
// 内嵌的枚举类型
public static enum Grade { EXCELLENT, SATISFACTORY, UNSATISFACTORY };

// 下面的方法定义了annotation的成员
Grade grade();
String reviewer();
String comment() default "";
}


最后,我们来定义一个annotation方法用于罗列出类运行中所有的unchecked异常(上文已经提到这种情况不一定是错误)。这个annotation类型将一个数组作为了唯一的成员。数组中的每个元素都是异常类。为了加强对未检查的异常(此类异常都是在运行时抛出)进行报告,我们可以在代码中对异常的类型进行限制:
清单13:

public @interface UncheckedExceptions { Class[] value();}
五、Meta-Annotation

Annotation类型可以被它们自己所标注。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它annotation类型作说明。这些类型和它们所支持的类在java.lang.annotation包中可以找到。如果需要更详细的信息可以参考jdk5.0手册。

1.再谈Target
作为meta-annotation类型的Target,它描述了annotation所修饰的程序成员的类型。当一个annotation类型没有Target时,它将被作为普通的annotation看待。当将它修饰一个特定的程序成员时,它将发挥其应用的作用,例如:Override用于修饰方法时,增加了@Target这个meta-annotation就使编译器对annotation作检查,从而去掉修饰错误类型的Override。

Target meta-annotation类型有唯一的value作为成员。这个成员的类型是java.lang.annotation.ElementType[]类型的,ElementType类型是可以被标注的程序成员的枚举类型。

2.Retention的用法
我们在文章的开头曾经提到过Retention,但是没有详细讲解。Retention描述了annotation是否被编译器丢弃或者保留在class文件;如果保留在class文件中,是否在class文件被装载时被虚拟机读取。默认情况下,annotation被保存在class文件中,但在运行时并不能被反射访问。Retention具有三个取值:source、class、runtime,这些取值来自java.lang.annotation.RetentionPolicy的枚举类型值。

Retention meta-annotation类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。

3.Documented
Documented是一个meta-annotation类型,用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。

Documented是一个marker annotation,没有成员。

4.Inherited
@Inherited meta-annotation也是一个marker annotation,它阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

值得思考的是,当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

六、总结:

本文几乎覆盖了所有的Annotation的概念和知识点,从annotation的定义、语法到工作原理、如何自定义annotation,直至meta-annotation。其中也具有一些配套的代码片断可参考,虽然不是很多,但是可谓言简意赅、着其重点

2008年2月15日金曜日

単語

2/13
容疑 ようぎ 海兵 かいへい 付き纏う つきまとう 降雪 こうせつ 徐行 じょこう
病根 びょうこん 隣接 りんせつ 駐米 ちゅうべい 馬術 ばじゅつ 孤島 ことう
皇帝 こうてい 死因 しいん 毛髪 もうはつ 人間 じんかん 主眼 しゅがん
解析 かいせき 争奪 そうだつ 背景 はいけい 埋蔵 まいぞう 金融 きんゆう
進展 しんてん 筆舌 ひつぜつ 平野 ひらの 隔てる へだてる 鎖 くさり 免状 めんじょう
苔 こけ そもそも 枚挙 まいきょ 講じる こうじる 根本 こんぽん 梱包 こんぽう
荷 に 荷が重過ぎるんですが デメリット 目処(目途) めど 目まぐるしい
バイヤー 照れ屋 てれや

2008年2月7日木曜日

敬語

規則形のパターン

1.尊敬語
  お(連用形)になります 
  謙譲語
  お(連用形)します
  丁寧な謙譲語
  お(連用形)いたします
2.お(連用形)ください
  ~していただけないでしょうか
  ~していただけましたら幸いです
3.不規則形
  標準形         →        尊敬語      →      謙譲語
  行きます・来ます          いらしゃいます           まいります・うかがいます
  食べます・飲みます         召し上がります           いただきます
  います               いらしゃいます           おります
  見ます               ご覧になります           拝見します
  言います              おっしゃいます            申します
  もらいます              -                いただきます
  あげます               -                差し上げます
  知っています            ご存知です             存じ上げています
  します               なさいます              いたします
  会います              お会いになります         お目にかかります
  帰ります              お帰りになります          失礼します
4.上級編
  してもらいます     していただきます
  させてもらいます   させていただきます

2008年2月6日水曜日

口语表现句型

口语 普通语 例句

たって/だって  ても/でも 明日だっていい

なきゃ/なけりゃ  なければ 言わなけりゃいいさ

ちゃ/じゃ  ては/では 遅刻しちゃいけない(てはいけない)

んじゃない  のではない 少し高いんじゃないか

んだ  のだ どうしたんですか(のですか)

じゃ  では じゃ、また明日

って  と/という/というのは 僕は劉って言います

てる/でる  ている/でいる あそこに座ってる人、誰?

とく/どく  ておく/でおく 私に任せといてください

ちゃう/じゃう てしまう/でしまう もう読んじゃったよ

かなぁ/かしら  だろうか 明日晴れるかなぁ
(~かなぁは男女兼用、~かしらは女用)

単語:
さぼる 学校をさぼって海見に行ったこともあった。
鈍感 それはお前が鈍感だから
蔑む さげすむ 蔑むよな目付けて人を見る
とげ パジャマ つまみ 暖まる 一昨日 走馬灯(そうまとう)
慰める(なぐさめる) 癒える(いえる) 癒す(いやす) しつこい
溺れる 収拾(しゅうしゅう) 
免れる(まぬがれる) 責任を免れる ぶらんこ
すくい 金魚すくいやったり
口笛 (くちぶえ)