??xml version="1.0" encoding="utf-8" standalone="yes"?>
再徏完这个文件的时候再建立工作文g
jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(os));
如果q个文g已经存在,那么我们可以在这个文仉面加入一个sheetZ和以前的数据q行分开;
jxl.write.WritableSheet ws = wwb.createSheet("Test Sheet 1", 0);
在createSheetҎ(gu)里前面的参数是sheet名,后面是要操作的sheet?
接下来就可以往q个文g里面写入数据?
写入数据的时候注意的格式
Q?Q添加的字体样式
jxl.write.WritableFont wf = new jxl.write.WritableFont(WritableFont.TIMES, 18, WritableFont.BOLD, true);
WritableFont()Ҏ(gu)里参数说明:(x)
q个Ҏ(gu)是一个容器,可以放进d多属?
W一? TIMES是字体大,他写的是18
W二? BOLD是判断是否ؓ(f)斜体,选择true时ؓ(f)斜体
W三? ARIAL
W四? UnderlineStyle.NO_UNDERLINE 下划U?
W五? jxl.format.Colour.RED 字体颜色是红色的
jxl.write.WritableCellFormat wcfF = new jxl.write.WritableCellFormat(wf);
jxl.write.Label labelC = new jxl.write.Label(0, 0, "This is a Label cell"QwcfF);
ws.addCell(labelC);
在Label()Ҏ(gu)里面有三个参?
W一个是代表列数,
W二是代表行敎ͼ
W三个代表要写入的内?
W四个是可选项Q是输入q个label里面的样?
然后通过写sheet的方法addCellQ)把内容写qsheet里面?
Q?Q添加带有formatting的Number对象
jxl.write.NumberFormat nf = new jxl.write.NumberFormat("#.##");
Q?Q添加Number对象
Q?.1Q显Cnumber对象数据的格?
jxl.write.NumberFormat nf = new jxl.write.NumberFormat("#.##");
jxl.write.WritableCellFormat wcfN = new jxl.write.WritableCellFormat(nf);
jxl.write.Number labelNF = new jxl.write.Number(1, 1, 3.1415926, wcfN);
ws.addCell(labelNF);
Number()Ҏ(gu)参数说明:
前两上表C入的位置
W三个表C入的内容
Q?Q添加Boolean对象
jxl.write.Boolean labelB = new jxl.write.Boolean(0, 2, false);
ws.addCell(labelB);
Q?Q添加DateTime对象
jxl.write.DateTime labelDT = new jxl.write.DateTime(0, 3, new java.util.Date());
ws.addCell(labelDT);
DateTime()Ҏ(gu)的参数说?
前两个表C入的位置
W三个表C入的当前旉
Q?Q添加带有formatting的DateFormat对象
q个昄当前旉的所有信息,包括q月日小时分U?
jxl.write.DateFormat df = new jxl.write.DateFormat("dd MM yyyy hh:mm:ss");
jxl.write.WritableCellFormat wcfDF = new jxl.write.WritableCellFormat(df);
jxl.write.DateTime labelDTF = new jxl.write.DateTime(1, 3, new java.util.Date(), wcfDF);
ws.addCell(labelDTF);
Q?Q添加带有字体颜色Formatting的对?
jxl.write.WritableFont wfc = new jxl.write.WritableFont(WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false,UnderlineStyle.NO_UNDERLINE, jxl.format.Colour.RED);
jxl.write.WritableCellFormat wcfFC = new jxl.write.WritableCellFormat(wfc);
import="jxl.format.*
jxl.write.WritableFont wfc = new jxl.write.WritableFont(WritableFont.ARIAL,20,WritableFont.BOLD,false,UnderlineStyle.NO_UNDERLINE,jxl.format.Colour.GREEN);
Q?Q设|单元格样式
jxl.write.WritableCellFormat wcfFC = new jxl.write.WritableCellFormat(wfc);
wcfFC.setBackGround(jxl.format.Colour.RED);//讄单元格的颜色为红?
wcfFC = new jxl.write.Label(6,0,"i love china",wcfFC);
FROM: http://forum.javaeye.com/viewtopic.php?t=4157&postdays=0&postorder=asc&start=0
]]>
Java Excel API既可以从本地文gpȝ的一个文?.xls)Q也可以从输入流中读取Excel数据表。读取Excel数据表的W一步是创徏Workbook(术语Q工作薄)Q下面的代码片段举例说明了应该如何操作:(x)(完整代码见ExcelReading.java)
|
一旦创ZWorkbookQ我们就可以通过它来讉KExcel Sheet(术语Q工作表)。参考下面的代码片段Q?/p>
|
我们既可能通过Sheet的名U来讉K它,也可以通过下标来访问它。如果通过下标来访问的话,要注意的一Ҏ(gu)下标?开始,像数组一栗?/p>
一旦得CSheetQ我们就可以通过它来讉KExcel Cell(术语Q单元格)。参考下面的代码片段Q?/p>
|
如果仅仅是取得Cell的|我们可以方便地通过getContents()Ҏ(gu)Q它可以Q何类型的Cell值都作ؓ(f)一个字W串q回。示例代码中Cell(0, 0)是文本型QCell(1, 0)是数字型QCell(1,1)是日期型Q通过getContents()Q三U类型的q回值都是字W型?/p>
如果有需要知道Cell内容的确切类型,API也提供了一pd的方法。参考下面的代码片段Q?/p>
|
在得到Cell对象后,通过getType()Ҏ(gu)可以获得该单元格的类型,然后与API提供的基本类型相匚wQ强制{换成相应的类型,最后调用相应的取值方法getXXX()Q就可以得到定cd的倹{API提供了以下基本类型,与Excel的数据格式相对应Q如下图所C:(x)
每种cd的具体意义,请参见Java Excel API Document?/p>
当你完成对Excel?sh)子表格数据的处理后Q一定要使用close()Ҏ(gu)来关闭先前创建的对象Q以释放d数据表的q程中所占用的内存空_(d)在读取大量数据时昑־ؓ(f)重要。参考如下代码片D:(x)
|
Java Excel API提供了许多访问Excel数据表的Ҏ(gu)Q在q里我只要地介绍几个常用的方法,其它的方法请参考附录中的Java Excel API Document?/p>
WorkbookcL供的Ҏ(gu)
1. int getNumberOfSheets()
获得工作薄(WorkbookQ中工作表(SheetQ的个数Q示例:(x)
|
2. Sheet[] getSheets()
q回工作薄(WorkbookQ中工作表(SheetQ对象数l,CZQ?
|
3. String getVersion()
q回正在使用的API的版本号Q好像是没什么太大的作用?
|
Sheet接口提供的方?/b>
1) String getName()
获取Sheet的名UͼCZQ?
|
2) int getColumns()
获取Sheet表中所包含的d敎ͼCZQ?
|
3) Cell[] getColumn(int column)
获取某一列的所有单元格Q返回的是单元格对象数组Q示例:(x)
|
4) int getRows()
获取Sheet表中所包含的总行敎ͼCZQ?
|
5) Cell[] getRow(int row)
获取某一行的所有单元格Q返回的是单元格对象数组Q示例子Q?
|
6) Cell getCell(int column, int row)
获取指定单元格的对象引用Q需要注意的是它的两个参敎ͼW一个是列数Q第二个是行敎ͼq与通常的行、列l合有些不同?
|
下面的代码主要是向大家介l如何生成简单的Excel工作表,在这里单元格的内Ҏ(gu)不带M修饰?如:(x)字体Q颜色等{?Q所有的内容都作为字W串写入?完整代码见ExcelWriting.java)
与读取Excel工作表相|首先要用Workbookcȝ工厂Ҏ(gu)创徏一个可写入的工作薄(Workbook)对象Q这里要注意的是Q只能通过API提供的工厂方法来创徏WorkbookQ而不能用WritableWorkbook的构造函敎ͼ因ؓ(f)cWritableWorkbook的构造函Cؓ(f)protectedcd。示例代码片D如下:(x)
|
API提供了两U方式来处理可写入的输出,一U是直接生成本地文gQ如果文件名不带全\径的话,~省的文件会(x)定位在当前目录,如果文g名带有全路径的话Q则生成的Excel文g则会(x)定位在相应的目录Q另外一U是Excel对象直接写入到输出流Q例如:(x)用户通过览器来讉KWeb服务器,如果HTTP头设|正的话,览器自动调用客L(fng)的Excel应用E序Q来昄动态生成的Excel?sh)子表格?/p>
接下来就是要创徏工作表,创徏工作表的Ҏ(gu)与创建工作薄的方法几乎一P同样是通过工厂模式Ҏ(gu)获得相应的对象,该方法需要两个参敎ͼ一个是工作表的名称Q另一个是工作表在工作薄中的位|,参考下面的代码片段Q?/p>
|
"q锅也支好了Q材料也准备齐全了,可以开始下锅了Q?Q现在要做的只是实例化API所提供的Excel基本数据cdQƈ它们添加到工作表中可以了Q参考下面的代码片段Q?/p>
|
q里有两点大家要引v大家的注意。第一点,在构造单元格Ӟ单元格在工作表中的位|就已经定了。一旦创建后Q单元格的位|是不能够变更的Q尽单元格的内Ҏ(gu)可以改变的。第二点Q单元格的定位是按照下面q样的规?column, row)Q而且下标都是?开始,例如QA1被存储在(0, 0)QB1被存储在(1, 0)?/p>
最后,不要忘记关闭打开的Excel工作薄对象,以释攑֍用的内存Q参见下面的代码片段Q?/p>
|
q可能与dExcel文g的操作有少不同Q在关闭Excel对象之前Q你必须要先调用write()Ҏ(gu)Q因为先前的操作都是存储在缓存中的,所以要通过该方法将操作的内容保存在文g中。如果你先关闭了Excel对象Q那么只能得C张空的工作薄了?/p>
接下来简要介l一下如何更C个已l存在的工作薄,主要是下面二步操作,W一步是构造只ȝExcel工作薄,W二步是利用已经创徏的Excel工作薄创建新的可写入的Excel工作薄,参考下面的代码片段Q?完整代码见ExcelModifying.java)
|
之所以用这U方式构建Excel对象Q完全是因ؓ(f)效率的原因,因ؓ(f)上面的示例才是API的主要应用。ؓ(f)了提高性能Q在d工作表时Q与数据相关的一些输Z息,所有的格式信息Q如Q字体、颜色等{,是不被处理的Q因为我们的目的是获得行数据的|既没有了修饎ͼ也不?x)对行数据的g生什么媄响。唯一的不利之处就是,在内存中?x)同时保存两个同L(fng)工作表,q样当工作表体积比较大时Q会(x)占用相当大的内存Q但现在好像内存的大ƈ不是什么关键因素了?/p>
一旦获得了可写入的工作表对象,我们可以对单元格对象进行更新的操作了,在这里我们不必调用API提供的add()Ҏ(gu)Q因为单元格已经于工作表当中Q所以我们只需要调用相应的setXXX()Ҏ(gu)Q就可以完成更新的操作了?/p>
单元格原有的格式化修饰是不能去掉的Q我们还是可以将新的单元g饰加上去Q以使单元格的内容以不同的Ş式表现?/p>
新生成的工作表对象是可写入的Q我们除了更新原有的单元格外Q还可以d新的单元格到工作表中Q这与示?的操作是完全一L(fng)?/p>
最后,不要忘记调用write()Ҏ(gu)Q将更新的内容写入到文g中,然后关闭工作薄对象,q里有两个工作薄对象要关闭,一个是只读的,另外一个是可写入的?br />
FROM: http://www-128.ibm.com/developerworks/cn/java/l-javaExcel/index.html
@Override
public String toSting() { // 注意Ҏ(gu)名拼写错?br /> return "[" + super.toString() + "]";
}
下面是一D用@Deprecated的代码:(x)
/**
* q里是javadoc的@deprecated声明.
* @deprecated No one has players for this format any more. Use VHS instead.
*/
@Deprecated public class Betamax { ... }
@SuppressWarnings(value={"unchecked","fallthrough"})
public void lintTrap() { /* sloppy method body omitted */ }
@SuppressWarnings({"unchecked","fallthrough"})
@SuppressWarnings("unchecked")
@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")
})
@UncheckedExceptions({
IllegalArgumentException.class, StringIndexOutOfBoundsException.class
})
/**
* This package holds my custom annotation types.
*/
@com.davidflanagan.annotations.Author("David Flanagan")
package com.davidflanagan.annotations;
import java.lang.reflect.*;
Class c = WhizzBangClass.class;
Method m = c.getMethod("whizzy", int.class, int.class);
boolean unstable = m.isAnnotationPresent(Unstable.class);
AnnotatedElement target = WhizzBangClass.class; //获得被查询的AnnotatedElement
// 查询AnnotatedElement的@Reviews annotation信息
Reviews annotation = target.getAnnotation(Reviews.class);
// 因ؓ(f)@Reviews annotationcd的成员ؓ(f)@Review annotationcd的数l,
// 所以下面声明了Review[] reviews保存@Reviews annotationcd的value成员倹{?br />Review[] reviews = annotation.value();
// 查询每个@Review annotation的成员信?br />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);
}
package com.davidflanagan.annotations;
import java.lang.annotation.*;
/**
* 使用annotation来描q那些被标注的成员是不稳定的Q需要更?br />*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Unstable {}
/**
* 使用Authorq个annotation定义在程序中指出代码的作?br /> */
public @interface Author {
/** q回作者名 */
String value();
}
import java.lang.annotation.*;
/**
* Reviews annotationcd只有一个成员,
* 但是q个成员的类型是复杂的:(x)由Review annotationl成的数l?br /> */
@Retention(RetentionPolicy.RUNTIME)
public @interface Reviews {
Review[] value();
}
/**
* Review annotationcd?个成员:(x)
* 枚Dcd成员grade?br /> * 表示Review名称的字W串cd成员Reviewer?br /> * h默认值的字符串类型成员Comment?br /> */
public @interface Review {
// 内嵌的枚丄?br /> public static enum Grade { EXCELLENT, SATISFACTORY, UNSATISFACTORY };
// 下面的方法定义了annotation的成?br /> Grade grade();
String reviewer();
String comment() default "";
}
public @interface UncheckedExceptions {
Class<? extends RuntimeException>[] value();
}
未增强的ForQ? int sum = 0; Integer[] numbers = computeNumbers(); for (int i=0; i < numbers.length ; i++) sum += numbers[i]; 增强后的ForQ? int sum = 0; for ( int number: computeNumbers() ) sum += number;局限?/b>
for (int i=0; i < numbers.length ; i++) { if (i != 0) System.out.print(","); System.out.print(numbers[i]); }
我们希望数l中的值打Cؓ(f)一个用逗号分隔的清单。我们需要知道目前是否是W一,以便定是否应该打印逗号。用增强的for循环是无法获知这U信息的。我们需要自׃留一个下标或一个布?yu)(dng)值来指示是否l过了第一V? q是另一个例子:(x)
for (Iterator<integer> it = n.iterator() ; it.hasNext() ; ) if (it.next() < 0) it.remove();
在此例中Q我们想从整数集合中删除负数Vؓ(f)此,需要对q代器调用一个方法,但是当用增强的for 循环Ӟq代器对我们来说是看不到的。因此,我们只能使用Java 5之前版本的P代方法? Z说一下,q里需要注意的是,׃Iterator是泛型,所以其声明是Iterator<Integer>。许多h都忘Cq一点而用了Iterator的原始格式?
注释Suppress Warnings
该注释关闭了cLҎ(gu)U别的编译器警告。有时候?zhn)比编译器更清楚地知道Q代码必M用一个被否决的方法或执行一些无法静态确定是否类型安全的动作Q而用:(x)
@SuppressWarnings("deprecation") public static void selfDestruct() { Thread.currentThread().stop(); }
q可能是内置注释最有用的地斏V遗憄是,1.5.0_04的javac不支持它。但?.6支持它,q且Sun正在努力其向后UL?.5中?
Eclipse 3.1中支持该注释Q其他IDE也可能支持它。这允许(zhn)把代码dC警告中解脱出来。如果在~译时出现警告,可以定是?zhn)刚刚把它dq来——以帮助查看那些可能不安全的代码。随着泛型的添加,它用v来将更趁手?
Deprecated
遗憾的是QDeprecated没那么有用。它本来旨在替换@deprecated javadoc标签Q但是由于它不包含Q何字D,所以也没有方法来deprecatedcLҎ(gu)的用户应该用什么做为替代品。大多数用法都同旉要javadoc标签和这个注释?
Override
Override表示Q它所注释的方法应该重写超cMh相同{的方法:(x)
@Override public int hashCode() { ... }
看上面的例子Q如果没有在hashCode中将“C”大写,在编译时不会(x)出现错误Q但是在q行时将无法像期望的那样调用该方法。通过dOverride标签Q编译器?x)提C它是否真正地执行了重写?
在超cd生改变的情况中,q也很有帮助。如果向该方法中d一个新参数Q而且Ҏ(gu)本n也被重命名了Q那么子cdH然不能~译Q因为它不再重写类的Q何东ѝ?
其它注释
注释在其他场景中非常有用。当不是直接修改行ؓ(f)而是增强行ؓ(f)Ӟ特别是在dh代码的情况下Q注释在诸如EJB?a target="_blank">Web servicesq样的框架中q行得非常好?
注释不能用做预处理器。Sun的设计特别预防了完全因ؓ(f)注释而修改类的字节码。这样可以正地理解该语a的成果,而且IDE之类的工具也可以执行深入的代码分析和重构之类的功能?
注释不是银弹。第一ơ遇到的时候,Z试图试各种技巧。请看下面这个从别h那里获得的徏议:(x)
public class Foo { @Property private int bar; }
其思想是ؓ(f)U有字段bar自动创徏getter和setterҎ(gu)。遗憄是,q个x有两个失败之处:(x)1)它不能运行,2)它代码难以阅读和处理? 它是无法实现的,因ؓ(f)前面已经提到了,Sun特别L了对出现注释的类q行修改?
即是可能的Q它也不是一个好LQ因为它使代码可L差。第一ơ看到这D代码的Z(x)不知道该注释创徏了方法。此外,如果来(zhn)需要在q些Ҏ(gu)内部执行一些操作,注释也是没用的? MQ不要试囄注释d那些常规代码可以完成的事情?
枚D
enum非常像public static final int声明Q后者作为枚丑ր已l用了很多q。对int所做的最大也是最明显的改q是cd安全——?zhn)不能错误地用枚D的一U类型代替另一U类型,q一点和int不同Q所有的int对编译器来说都是一L(fng)。除L数例外的情况,通常都应该用enum实例替换全部的枚N格的intl构?
枚D提供了一些附加的Ҏ(gu)。EnumMap和EnumSetq两个实用类是专门ؓ(f)枚D优化的标准集合实现。如果知道集合只包含枚DcdQ那么应该用这些专门的集合来代替HashMap或HashSet?
大部分情况下Q可以用enum对代码中的所有public static final int做插入替换。它们是可比的,q且可以静态导入,所以对它们的引用看h是等同的Q即使是对于内部c(或内部枚丄型)。注意,比较枚Dcd的时候,声明它们的指令表明了它们的顺序倹{?
“隐藏的”静态方?
两个静态方法出现在所有枚丄型声明中。因为它们是枚D子类上的静态方法,而不是Enum本n的方法,所以它们在java.lang.Enum的javadoc中没有出现?
W一个是values()Q返回一个枚丄型所有可能值的数组?
W二个是valueOf()Qؓ(f)提供的字W串q回一个枚丄型,该枚丄型必ȝ地匚w源代码声明?
Ҏ(gu)
关于枚DcdQ我们最喜欢的一个方面是它可以有Ҏ(gu)。过L可能需要编写一些代码,对public static final intq行转换Q把它从数据库类型{换ؓ(f)JDBC URL。而现在则可以让枚丄型本w带一个整理代码的Ҏ(gu)。下面就是一个例子,包括DatabaseType枚Dcd的抽象方法以?qing)每个枚丑֮例中提供的实玎ͼ?x)
public enum DatabaseType { ORACLE { public String getJdbcUrl() {...} }, MYSQL { public String getJdbcUrl() {...} }; public abstract String getJdbcUrl(); }现在枚Dcd可以直接提供它的实用Ҏ(gu)。例如:(x)
可变参数(Vararg)
正确C用可变参数确实可以清理一些垃圾代码。典型的例子是一个带有可变的String参数个数的logҎ(gu)Q?
Log.log(String code) Log.log(String code, String arg) Log.log(String code, String arg1, String arg2) Log.log(String code, String[] args)当讨论可变参数时Q比较有的是,如果用新的可变参数替换前四个例子Q将是兼容的Q?
Log.log(Object... objects) { String message = (String)objects[0]; if (objects.length > 1) { Exception e = (Exception)objects[1]; // Do something with the exception } }Ҏ(gu){应该如下所C,相应的可变参数分别用String和Exception声明Q?
public interface Zoo { public Animal getAnimal(); } public class ZooImpl implements Zoo { public Animal getAnimal(){ return new AnimalImpl(); } }协变q回的用替换了三个反模式:(x)
ZooImpl._animal
((AnimalImpl)ZooImpl.getAnimal()).implMethod();
ZooImpl._getAnimal();
q三U模式都有它们的问题和局限性。要么是不够整洁Q要么就是暴露了不必要的实现l节?
协变
协变q回模式比较整z、安全ƈ且易于维护,它也不需要类型强制{换或特定的方法或字段Q?
public AnimalImpl getAnimal(){
return new AnimalImpl();
}
使用l果Q?
ZooImpl.getAnimal().implMethod();
使用泛型
我们从两个角度来了解泛型:(x)使用泛型和构造泛型。我们不讨论List、Set和Map的显而易见的用法。知道泛型集合是强大的ƈ且应该经怋用就_了?
我们讨论泛型方法的使用以及(qing)~译器推断类型的Ҏ(gu)。通常q些都不?x)出问题Q但是当出问题时Q错误信息会(x)非常令h费解Q所以需要了解如何修复这些问题?
static <T> List<T> Collections.singletonList(T o) CZ用法Q? public List<Integer> getListOfOne() { return Collections.singletonList(1); }
在示例用法中Q我们传入了一个int。所以方法的q回cd是List<Integer>。编译器把T推断为Integer。这和泛型类型是不同的,因ؓ(f)(zhn)通常不需要显式地指定cd参数?
q也昄了自动装和泛型的相互作用。类型参数必L引用cdQ这是Z么我们得到的是List<Integer>而不是List<int>?
static <T> List<T> Collections.emptyList() CZ用法Q? public List<Integer> getNoIntegers() { return Collections.emptyList(); }
与先前的例子不同Q这个方法没有参敎ͼ那么~译器如何推断T的类型呢Q基本上Q它?yu)尝试用一ơ参数。如果没有v作用Q它再次试使用q回或赋值类型。在本例中,q回的是List<Integer>Q所以T被推断ؓ(f)Integer?
如果在返回语句或赋D句之外的位置调用泛型Ҏ(gu)?x)怎么样呢Q那么编译器无法执行类型推断的W二ơ传送。在下面q个例子中,emptyList()是从条gq算W内部调用的Q?
public List<Integer> getNoIntegers() { return x ? Collections.emptyList() : null; }
因ؓ(f)~译器看不到q回上下文,也不能推断TQ所以它攑ּq用Object。?zhn)看C个错误消息,比如Q“无法将List<Object>转换为List<Integer>。?
Z修复q个错误Q应昑ּ地向Ҏ(gu)调用传递类型参数。这P~译器就不会(x)试图推断cd参数Q就可以获得正确的结果:(x)
return x ? Collections.<Integer>emptyList() : null;
q种情况l常发生的另一个地Ҏ(gu)在方法调用中。如果一个方法带一个List<String>参数Qƈ且需要ؓ(f)那个参数调用q个传递的emptyList()Q那么也需要用这个语法?
集合之外Integer[] ia = new Integer[5]; Number[] na = ia; na[0] = 0.5; // compiles, but fails at runtime 如果试图把该例直接{换成泛型Q那么会(x)在编译时p|Q因值是不被允许的:(x) List<Integer> iList = new ArrayList<Integer>(); List<Number> nList = iList; // not allowed nList.add(0.5);
如果使用泛型Q只要代码在~译时没有出现警告,׃?x)遇到运行时ClassCastException?
上限通配W?/b>
我们惌的是一个确切元素类型未知的列表Q这一点与数组是不同的?
List<Number>是一个列表,其元素类型是具体cdNumber?
List<? extends Number>是一个确切元素类型未知的列表。它是Number或其子类型?
上限
如果我们更新初始的例子,q赋值给List<? extends Number>Q那么现在赋值就?x)成功了Q?
List<Integer> iList = new ArrayList<Integer>(); List<? extends Number> nList = iList; Number n = nList.get(0); nList.add(0.5); // Not allowed
我们可以从列表中得到NumberQ因为无论列表的切元素cd是什么(F(tun)loat、Integer或NumberQ,我们都可以把它赋值给Number?
我们仍然不能把Q点类型插入列表中。这?x)在~译时失败,因ؓ(f)我们不能证明q是安全的。如果我们想要向列表中添加Q点类型,它将破坏iList的初始类型安全——它只存储Integer?
通配W给了我们比数组更多的表达能力?
public class CustomerFactory { private Set<CustomerImpl> _customers; public Set<? extends Customer> getCustomers() { return _customers; } }
通配W和协变q回
通配W的另一U常见用法是和协变返回一起用。与赋值相同的规则可以应用到协变返回上。如果希望在重写的方法中q回一个更具体的泛型类型,声明的方法必M用通配W:(x)
public interface NumberGenerator { public List<? extends Number> generate(); } public class FibonacciGenerator extends NumberGenerator { public List<Integer> generate() { ... } }
如果要用数l,接口可以q回Number[]Q而实现可以返回Integer[]?
下限
我们所谈的主要是关于上限通配W的。还有一个下限通配W。List<? super Number>是一个确切“元素类型”未知的列表Q但是可能是MnumberQ或者Number的超cd。所以它可能是一个List<Number>或一个List<Object>?
下限通配W远没有上限通配W那样常见,但是当需要它们的时候,它们是必需的?
List<? extends Number> readList = new ArrayList<Integer>(); Number n = readList.get(0); List<? super Number> writeList = new ArrayList<Object>(); writeList.add(new Integer(5));
W一个是可以从中L的列表?
W二个是可以向其写数的列表?
无界通配W?/b>
最后,List<?>列表的内容可以是McdQ而且它与List<? extends Object>几乎相同。可以随时读取ObjectQ但是不能向列表中写入内宏V?
公共API中的通配W?
MQ正如前面所_(d)通配W在向调用程序隐藏实现细节方面是非常重要的,但即使下限通配W看h是提供只读访问,׃remove(int position)之类的非泛型Ҏ(gu)Q它们也q如此。如果?zhn)惌一个真正不变的集合Q可以用java.util.Collection上的Ҏ(gu)Q比如unmodifiableList()?
~写API的时候要记得通配W。通常Q在传递泛型类型时Q应该尝试用通配W。它使更多的调用E序可以讉KAPI?
通过接收List<? extends Number>而不是List<Number>Q下面的Ҏ(gu)可以p多不同类型的列表调用Q?
void removeNegatives(List<? extends Number> list);
构造泛型类?/b>
现在我们讨论构造自q泛型cd。我们将展示一些例子,其中通过使用泛型可以提高cd安全性,我们q将讨论一些实现泛型类型时的常见问题?/p>
集合风格(Collection-like)的函?/b>
W一个泛型类的例子是一个集合风格的例子。Pair有两个类型参敎ͼ而且字段是类型的实例Q?
public final class Pair<A,B> { public final A first; public final B second; public Pair(A first, B second) { this.first = first; this.second = second; } }
q从方法返回两个项而无需为每个两U类型的l合~写专用的类成ؓ(f)可能。另一U方法是q回Object[]Q而这hcd不安全或者不整洁的?
在下面的用法中,我们从方法返回一个File和一个Boolean。方法的客户端可以直接用字D而无需cd强制转换Q?
public Pair<File,Boolean> getFileAndWriteStatus(String path){ // create file and status return new Pair<File,Boolean>(file, status); } Pair<File,Boolean> result = getFileAndWriteStatus("..."); File f = result.first; boolean writeable = result.second;
集合之外
在下面这个例子中Q泛型被用于附加的编译时安全性。通过把DBFactorycd数化为所创徏的PeercdQ?zhn)实际上是在强制Factory子类q回一个Peer的特定子cdQ?
public abstract class DBFactory<T extends DBPeer> { protected abstract T createEmptyPeer(); public List<T> get(String constraint) { List<T> peers = new ArrayList<T>(); // database magic return peers; } } 通过实现DBFactory<Customer>QCustomerFactory必须从createEmptyPeer()q回一个CustomerQ? public class CustomerFactory extends DBFactory<Customer>{ public Customer createEmptyPeer() { return new Customer(); } }
泛型Ҏ(gu)
不管惌对参C间还是参Cq回cd之间的泛型类型施加约束,都可以用泛型方法:(x)
例如Q如果编写的反{函数是在位置上反转,那么可能不需要泛型方法。然而,如果希望反{q回一个新的ListQ那么可能会(x)希望新List的元素类型与传入的List的类型相同。在q种情况下,需要一个泛型方法:(x)
具体?br /> 当实C个泛型类Ӟ(zhn)可能想要构造一个数lT[]。因为泛型是通过擦除(erasure)实现的,所以这是不允许的?
(zhn)可以尝试把Object[]强制转换为T[]。但q是不安全的?
public class ArrayExample<T> { private Class<T> clazz; public ArrayExample(Class<T> clazz) { this.clazz = clazz; } public T[] getArray(int size) { return (T[])Array.newInstance(clazz, size); } }
Z构造ArrayExample<String>Q客L(fng)必须把String.class传递给构造函敎ͼ因ؓ(f)String.class的类型是Class<String>?
拥有cd象构造一个具有正元素类型的数组成ؓ(f)可能?
引用 http://dev2dev.bea.com.cn/techdoc/20060105718.html
String filename="test.jpg";
String dirName=application.getRealPath("/WEB-INF/upload");
java.io.File ff=null;
String dd=dirName+System.getProperties().getProperty("file.separator")+filename;
try{
ff=new java.io.File(dd);
}
catch(Exception e){
e.printStackTrace();
}
if (ff!=null&&ff.exists()&&ff.isFile())
{
long filelength = ff.length();
InputStream inStream=new FileInputStream(dd);
//讄输出的格?
response.reset();
response.setContentType("application/x-msdownload");
response.setContentLength((int)filelength);
response.addHeader("Content-Disposition","attachment; filename=\"" + toUtf8String(filename) + "\"");
//循环取出中的数?
byte[] b = new byte[100];
int len;
while((len=inStream.read(b)) >0)
response.getOutputStream().write(b,0,len);
inStream.close();
}
%>
W??基础知识
1.1. 单钥密码体制
单钥密码体制是一U传l的加密法Q是指信息的发送方和接收方共同使用同一把密钥进行加解密?/p>
通常,使用的加密算?比较侉K?密钥短,加解密速度快,破译极其困难。但是加密的安全性依靠密钥保的安全?在公开的计机|络上安全地传送和保管密钥是一个严ȝ问题Qƈ且如果在多用L(fng)情况下密钥的保管安全性也是一个问题?/p>
单钥密码体制的代表是国的DES
1.2. 消息摘要
一个消息摘要就是一个数据块的数字指UV即对一个Q意长度的一个数据块q行计算Q生一个唯一指印Q对于SHA1是生一?0字节的二q制数组Q?/p>
消息摘要有两个基本属性:(x)
两个不同的报文难以生成相同的摘要
难以Ҏ(gu)定的摘要生成一个报文,而由该报文反推算指定的摘?br />代表Q美国国家标准技术研I所的SHA1和麻省理工学院Ronald Rivest提出的MD5
1.3. Diffie-Hellman密钥一致协?
密钥一致协议是由公开密钥密码体制的奠ZhDiffie和Hellman所提出的一U思想?/p>
先决条g,允许两名用户在公开媒体上交换信息以生成"一??可以׃n的密?/p>
代表Q指数密钥一致协?Exponential Key Agreement Protocol)
1.4. 非对U算法与公钥体系
1976q_(d)Dittie和Hellman军_钥管理问题,在他们的奠基性的工作"密码学的新方?一文中Q提ZU密钥交换协议,允许在不安全的媒体上通过通讯双方交换信息Q安全地传送秘密密钥。在此新思想的基上,很快出现了非对称密钥密码体制Q即公钥密码体制。在公钥体制中,加密密钥不同于解密密钥,加密密钥公之于众Q谁都可以用;解密密钥只有解密q道。它们分别称为公开密钥QPublic keyQ和U密密钥QPrivate keyQ?
q今为止的所有公钥密码体pMQRSApȝ是最著名、最多用的一U。RSA公开密钥密码pȝ是由R.Rivest、A.Shamir和L.Adleman俊教授于1977q提出的。RSA的取名就是来自于q三位发明者的姓的W一个字?/p>
1.5. 数字{
所谓数字签名就是信息发送者用其私钥对从所传报文中提取出的特征数据Q或U数字指U)q行RSA法操作Q以保证发信人无法抵赖曾发过该信息(即不可抵赖性)Q同时也保信息报文在经{后末被篡改(卛_整性)。当信息接收者收到报文后Q就可以用发送者的公钥Ҏ(gu)字签名进行验证。
在数字签名中有重要作用的数字指纹是通过一cȝD的散列函数QHASH函数Q生成的Q对q些HASH函数的特D要求是Q?
接受的输入报文数据没有长度限Ӟ
对Q何输入报文数据生成固定长度的摘要Q数字指U)输出
从报文能方便地算出摘要;
难以Ҏ(gu)定的摘要生成一个报文,而由该报文反推算指定的摘要;
两个不同的报文难以生成相同的摘要
代表QDSA
W??在JAVA中的实现
2.1. 相关
Diffie-Hellman密钥一致协议和DESE序需要JCE工具库的支持,可以?http://java.sun.com/security/index.html 下蝲JCE,q进行安装。简易安装把 jce1.2.1\lib 下的所有内容复制到 %java_home%\lib\ext?如果没有ext目录自行建立,再把jce1_2_1.jar和sunjce_provider.jard到CLASSPATH?更详l说明请看相应用h?/p>
2.2. 消息摘要MD5和SHA的?
使用Ҏ(gu):
首先用生成一个MessageDigestc?定计算Ҏ(gu)
java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1");
d要进行计摘要的信息
alga.update(myinfo.getBytes());
计算出摘?/p>
byte[] digesta=alga.digest();
发送给其他Z的信息和摘要
其他人用相同的方法初始化,d信息,最后进行比较摘要是否相?/p>
algb.isEqual(digesta,algb.digest())
相关AIP
java.security.MessageDigest c?/p>
static getInstance(String algorithm)
q回一个MessageDigest对象,它实现指定的法
参数:法??SHA-1 或MD5
void update (byte input)
void update (byte[] input)
void update(byte[] input, int offset, int len)
d要进行计摘要的信息
byte[] digest()
完成计算,q回计算得到的摘?对于MD5?6?SHA?0?
void reset()
复位
static boolean isEqual(byte[] digesta, byte[] digestb)
比效两个摘要是否相同
代码Q?
import java.security.*;
public class myDigest {
public static void main(String[] args) {
myDigest my=new myDigest();
my.testDigest();
}
public void testDigest()
{
try {
String myinfo="我的试信息";
//java.security.MessageDigest alg=java.security.MessageDigest.getInstance("MD5");
java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1");
alga.update(myinfo.getBytes());
byte[] digesta=alga.digest();
System.out.println("本信息摘要是:"+byte2hex(digesta));
//通过某中方式传给其他Z的信?myinfo)和摘?digesta) Ҏ(gu)可以判断是否更改或传输正?br />java.security.MessageDigest algb=java.security.MessageDigest.getInstance("SHA-1");
algb.update(myinfo.getBytes());
if (algb.isEqual(digesta,algb.digest())) {
System.out.println("信息查正?);
}
else
{
System.out.println("摘要不相?);
}
}
catch (java.security.NoSuchAlgorithmException ex) {
System.out.println("非法摘要法");
}
}
public String byte2hex(byte[] b) //二行制{字符?br />{
String hs="";
String stmp="";
for (int n=0;n {
stmp=(java.lang.Integer.toHexString(b[n] & 0XFF));
if (stmp.length()==1) hs=hs+"0"+stmp;
else hs=hs+stmp;
if (n }
return hs.toUpperCase();
}
}
2.3. 数字{DSA
对于一个用h讲首先要生成他的密钥?q且分别保存
生成一个KeyPairGenerator实例
java.security.KeyPairGenerator keygen=java.security.KeyPairGenerator.getInstance("DSA");
如果讑֮随机产生器就用如总码初始化
SecureRandom secrand=new SecureRandom();
secrand.setSeed("tttt".getBytes()); //初始化随Z生器
keygen.initialize(512,secrand); //初始化密钥生成器
否则
keygen.initialize(512);
生成密钥公钥pubkey和私钥prikey
KeyPair keys=keygen.generateKeyPair(); //生成密钥l?br />PublicKey pubkey=keys.getPublic();
PrivateKey prikey=keys.getPrivate();
分别保存在myprikey.dat和mypubkey.dat?以便下次不在生成
(生成密钥对的旉比较?br />java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myprikey.dat"));
out.writeObject(prikey);
out.close();
out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("mypubkey.dat"));
out.writeObject(pubkey);
out.close();
用他Uh密钥(prikey)对他所认的信?info)q行数字{产生一个签名数l?
从文件中dUh密钥(prikey)
java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("myprikey.dat"));
PrivateKey myprikey=(PrivateKey)in.readObject();
in.close();
初始一个Signature对象,q用U钥对信息签?br />java.security.Signature signet=java.security.Signature.getInstance("DSA");
signet.initSign(myprikey);
signet.update(myinfo.getBytes());
byte[] signed=signet.sign();
把信息和{保存在一个文件中(myinfo.dat)
java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myinfo.dat"));
out.writeObject(myinfo);
out.writeObject(signed);
out.close();
把他的公钥的信息?qing)签名发l其它用?/p>
其他用户用他的公共密?pubkey)和签?signed)和信?info)q行验证是否׃{的信?
d公钥
java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("mypubkey.dat"));
PublicKey pubkey=(PublicKey)in.readObject();
in.close();
d{和信?br />in=new java.io.ObjectInputStream(new java.io.FileInputStream("myinfo.dat"));
String info=(String)in.readObject();
byte[] signed=(byte[])in.readObject();
in.close();
初始一个Signature对象,q用公钥和签名进行验?br />java.security.Signature signetcheck=java.security.Signature.getInstance("DSA");
signetcheck.initVerify(pubkey);
signetcheck.update(info.getBytes());
if (signetcheck.verify(signed)) { System.out.println("{正常");}
对于密钥的保存本文是用对象流的方式保存和传送的,也可可以用编码的方式保存.注意?br />import java.security.spec.*
import java.security.*
具休说明如下
public key是用X.509~码?例码如下:
byte[] bobEncodedPubKey=mypublic.getEncoded(); //生成~码
//传送二q制~码
//以下代码转换~码为相应key对象
X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);
对于Private key是用PKCS#8~码,例码如下:
byte[] bPKCS=myprikey.getEncoded();
//传送二q制~码
//以下代码转换~码为相应key对象
PKCS8EncodedKeySpec priPKCS8=new PKCS8EncodedKeySpec(bPKCS);
KeyFactory keyf=KeyFactory.getInstance("DSA");
PrivateKey otherprikey=keyf.generatePrivate(priPKCS8);
常用API
java.security.KeyPairGenerator 密钥生成器类
public static KeyPairGenerator getInstance(String algorithm) throws NoSuchAlgorithmException
以指定的法q回一个KeyPairGenerator 对象
参数: algorithm 法??"DSA","RSA"
public void initialize(int keysize)
以指定的长度初始化KeyPairGenerator对象,如果没有初始化系l以1024长度默认讄
参数:keysize 法位长.其范围必d 512 ?1024 之间Q且必须?64 的倍数
public void initialize(int keysize, SecureRandom random)
以指定的长度初始化和随机发生器初始化KeyPairGenerator对象
参数:keysize 法位长.其范围必d 512 ?1024 之间Q且必须?64 的倍数
random 一个随Z的来?对于initialize(int keysize)使用了默认随机器
public abstract KeyPair generateKeyPair()
产生新密钥对
java.security.KeyPair 密钥对类
public PrivateKey getPrivate()
q回U钥
public PublicKey getPublic()
q回公钥
java.security.Signature {c?br />public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException
q回一个指定算法的Signature对象
参数 algorithm ?"DSA"
public final void initSign(PrivateKey privateKey)
throws InvalidKeyException
用指定的U钥初始?br />参数rivateKey 所q行{时用的私?/p>
public final void update(byte data)
throws SignatureException
public final void update(byte[] data)
throws SignatureException
public final void update(byte[] data, int off, int len)
throws SignatureException
d要签名的信息
public final byte[] sign()
throws SignatureException
q回{的数l?前提是initSign和update
public final void initVerify(PublicKey publicKey)
throws InvalidKeyException
用指定的公钥初始?br />参数ublicKey 验证时用的公?/p>
public final boolean verify(byte[] signature)
throws SignatureException
验证{是否有效,前提是已linitVerify初始?br />参数: signature {数组
*/
import java.security.*;
import java.security.spec.*;
public class testdsa {
public static void main(String[] args) throws java.security.NoSuchAlgorithmException,java.lang.Exception {
testdsa my=new testdsa();
my.run();
}
public void run()
{
//数字{生成密钥
//W一步生成密钥对,如果已经生成q?本过E就可以跌,对用h讲myprikey.dat要保存在本地
//而mypubkey.datl发布给其它用户
if ((new java.io.File("myprikey.dat")).exists()==false) {
if (generatekey()==false) {
System.out.println("生成密钥对|");
return;
};
}
//W二?此用?br />//从文件中dU钥,对一个字W串q行{后保存在一个文?myinfo.dat)?br />//q且再把myinfo.dat发送出?br />//Z方便数字{也放q了myifno.dat文g?当然也可分别发?br />try {
java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("myprikey.dat"));
PrivateKey myprikey=(PrivateKey)in.readObject();
in.close();
// java.security.spec.X509EncodedKeySpec pubX509=new java.security.spec.X509EncodedKeySpec(bX509);
//java.security.spec.X509EncodedKeySpec pubkeyEncode=java.security.spec.X509EncodedKeySpec
String myinfo="q是我的信息"; //要签名的信息
//用私钥对信息生成数字{
java.security.Signature signet=java.security.Signature.getInstance("DSA");
signet.initSign(myprikey);
signet.update(myinfo.getBytes());
byte[] signed=signet.sign(); //对信息的数字{
System.out.println("signed({内容)="+byte2hex(signed));
//把信息和数字{保存在一个文件中
java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myinfo.dat"));
out.writeObject(myinfo);
out.writeObject(signed);
out.close();
System.out.println("{q生成文件成?);
}
catch (java.lang.Exception e) {
e.printStackTrace();
System.out.println("{q生成文件失?);
};
//W三?br />//其他人通过公共方式得到此户的公钥和文g
//其他人用此户的公?Ҏ(gu)件进行检?如果成功说明是此用户发布的信?
//
try {
java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("mypubkey.dat"));
PublicKey pubkey=(PublicKey)in.readObject();
in.close();
System.out.println(pubkey.getFormat());
in=new java.io.ObjectInputStream(new java.io.FileInputStream("myinfo.dat"));
String info=(String)in.readObject();
byte[] signed=(byte[])in.readObject();
in.close();
java.security.Signature signetcheck=java.security.Signature.getInstance("DSA");
signetcheck.initVerify(pubkey);
signetcheck.update(info.getBytes());
if (signetcheck.verify(signed)) {
System.out.println("info="+info);
System.out.println("{正常");
}
else System.out.println("非签名正?);
}
catch (java.lang.Exception e) {e.printStackTrace();};
}
//生成一Ҏ(gu)件myprikey.dat和mypubkey.dat---U钥和公?
//公钥要用户发?文g,|络{方?l其它用?U钥保存在本?br />public boolean generatekey()
{
try {
java.security.KeyPairGenerator keygen=java.security.KeyPairGenerator.getInstance("DSA");
// SecureRandom secrand=new SecureRandom();
// secrand.setSeed("tttt".getBytes()); //初始化随Z生器
// keygen.initialize(576,secrand); //初始化密钥生成器
keygen.initialize(512);
KeyPair keys=keygen.genKeyPair();
// KeyPair keys=keygen.generateKeyPair(); //生成密钥l?br />PublicKey pubkey=keys.getPublic();
PrivateKey prikey=keys.getPrivate();
java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myprikey.dat"));
out.writeObject(prikey);
out.close();
System.out.println("写入对象 prikeys ok");
out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("mypubkey.dat"));
out.writeObject(pubkey);
out.close();
System.out.println("写入对象 pubkeys ok");
System.out.println("生成密钥Ҏ(gu)?);
return true;
}
catch (java.lang.Exception e) {
e.printStackTrace();
System.out.println("生成密钥对失?);
return false;
};
}
public String byte2hex(byte[] b)
{
String hs="";
String stmp="";
for (int n=0;n {
stmp=(java.lang.Integer.toHexString(b[n] & 0XFF));
if (stmp.length()==1) hs=hs+"0"+stmp;
else hs=hs+stmp;
if (n }
return hs.toUpperCase();
}
}
2.4. DESede/DES对称法
首先生成密钥,q保?q里q没的保存的代码,可参考DSA中的Ҏ(gu))
KeyGenerator keygen = KeyGenerator.getInstance(Algorithm);
SecretKey deskey = keygen.generateKey();
用密钥加密明?myinfo),生成密文(cipherByte)
Cipher c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.ENCRYPT_MODE,deskey);
byte[] cipherByte=c1.doFinal(myinfo.getBytes());
传送密文和密钥,本文没有相应代码可参考DSA
.............
用密钥解密密?/p>
c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.DECRYPT_MODE,deskey);
byte[] clearByte=c1.doFinal(cipherByte);
相对来说对称密钥的用是很简单的,对于JCE来讲支技DES,DESede,Blowfish三种加密?/p>
对于密钥的保存各传送可使用对象或者用二进制编?相关参考代码如?
SecretKey deskey = keygen.generateKey();
byte[] desEncode=deskey.getEncoded();
javax.crypto.spec.SecretKeySpec destmp=new javax.crypto.spec.SecretKeySpec(desEncode,Algorithm);
SecretKey mydeskey=destmp;
相关API
KeyGenerator 在DSA中已l说?在添加JCE后在instanceq可以如下参?/p>
DES,DESede,Blowfish,HmacMD5,HmacSHA1
javax.crypto.Cipher ?解密?public static final Cipher getInstance(java.lang.String transformation)
throws java.security.NoSuchAlgorithmException,
NoSuchPaddingException
q回一个指定方法的Cipher对象
参数:transformation Ҏ(gu)?可用 DES,DESede,Blowfish)
public final void init(int opmode, java.security.Key key)
throws java.security.InvalidKeyException
用指定的密钥和模式初始化Cipher对象
参数pmode 方式(ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE,UNWRAP_MODE)
key 密钥
public final byte[] doFinal(byte[] input)
throws java.lang.IllegalStateException,
IllegalBlockSizeException,
BadPaddingException
对input内的?q行~码处理,q回处理后二q制?是返回解密文q是加解文由init时的opmode军_
注意:本方法的执行前如果有update,是对updat和本ơinput全部处理,否则是本inout的内?/p>
/*
安全E序 DESede/DES试
*/
import java.security.*;
import javax.crypto.*;
public class testdes {
public static void main(String[] args){
testdes my=new testdes();
my.run();
}
public void run() {
//d新安全算?如果用JCEp把它dq去
Security.addProvider(new com.sun.crypto.provider.SunJCE());
String Algorithm="DES"; //定义 加密法,可用 DES,DESede,Blowfish
String myinfo="要加密的信息";
try {
//生成密钥
KeyGenerator keygen = KeyGenerator.getInstance(Algorithm);
SecretKey deskey = keygen.generateKey();
//加密
System.out.println("加密前的二进?"+byte2hex(myinfo.getBytes()));
System.out.println("加密前的信息:"+myinfo);
Cipher c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.ENCRYPT_MODE,deskey);
byte[] cipherByte=c1.doFinal(myinfo.getBytes());
System.out.println("加密后的二进?"+byte2hex(cipherByte));
//解密
c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.DECRYPT_MODE,deskey);
byte[] clearByte=c1.doFinal(cipherByte);
System.out.println("解密后的二进?"+byte2hex(clearByte));
System.out.println("解密后的信息:"+(new String(clearByte)));
}
catch (java.security.NoSuchAlgorithmException e1) {e1.printStackTrace();}
catch (javax.crypto.NoSuchPaddingException e2) {e2.printStackTrace();}
catch (java.lang.Exception e3) {e3.printStackTrace();}
}
public String byte2hex(byte[] b) //二行制{字符?br />{
String hs="";
String stmp="";
for (int n=0;n {
stmp=(java.lang.Integer.toHexString(b[n] & 0XFF));
if (stmp.length()==1) hs=hs+"0"+stmp;
else hs=hs+stmp;
if (n }
return hs.toUpperCase();
}
}
2.5. Diffie-Hellman密钥一致协?
公开密钥密码体制的奠ZhDiffie和Hellman所提出?"指数密钥一致协?(Exponential Key Agreement Protocol),该协议不要求别的安全?先决条g,允许两名用户在公开媒体上交换信息以生成"一??可以׃n的密钥。在JCE的中实现用户alice生成DHcd的密钥对,如果长度?024生成的时间请,推荐W一ơ生成后保存DHParameterSpec,以便下次使用直接初始?使其速度加快
System.out.println("ALICE: 产生 DH ?...");
KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH");
aliceKpairGen.initialize(512);
KeyPair aliceKpair = aliceKpairGen.generateKeyPair();
alice生成公钥发送组bob byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();
bob从alice发送来的公钥中dDH密钥对的初始参数生成bob的DH密钥?/p>
注意q一步一定要?要保证每个用L(fng)相同的初始参数生成的
DHParameterSpec dhParamSpec = ((DHPublicKey)alicePubKey).getParams();
KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH");
bobKpairGen.initialize(dhParamSpec);
KeyPair bobKpair = bobKpairGen.generateKeyPair();
bobҎ(gu)a(chn)lice的公钥生成本地的DES密钥
KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");
bobKeyAgree.init(bobKpair.getPrivate());
bobKeyAgree.doPhase(alicePubKey, true);
SecretKey bobDesKey = bobKeyAgree.generateSecret("DES");
bob已经生成了他的DES密钥,他现把他的公钥发lalice,
byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();
aliceҎ(gu)bob的公钥生成本地的DES密钥
,,,,,,解码
KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
aliceKeyAgree.init(aliceKpair.getPrivate());
aliceKeyAgree.doPhase(bobPubKey, true);
SecretKey aliceDesKey = aliceKeyAgree.generateSecret("DES");
bob和alice能过q个q程q成了相同的DES密钥,在这U基可q行安全能信
常用API
java.security.KeyPairGenerator 密钥生成器类
public static KeyPairGenerator getInstance(String algorithm)
throws NoSuchAlgorithmException
以指定的法q回一个KeyPairGenerator 对象
参数: algorithm 法??原来是DSA,现在d?DiffieHellman(DH)
public void initialize(int keysize)
以指定的长度初始化KeyPairGenerator对象,如果没有初始化系l以1024长度默认讄
参数:keysize 法位长.其范围必d 512 ?1024 之间Q且必须?64 的倍数
注意:如果?024生长的时间很?最好生成一ơ后׃?下次׃用生成了
public void initialize(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException
以指定参数初始化
javax.crypto.interfaces.DHPublicKey
public DHParameterSpec getParams()
q回
java.security.KeyFactory
public static KeyFactory getInstance(String algorithm)
throws NoSuchAlgorithmException
以指定的法q回一个KeyFactory
参数: algorithm 法名SH,DH
public final PublicKey generatePublic(KeySpec keySpec)
throws InvalidKeySpecException
Ҏ(gu)指定的key说明,q回一个PublicKey对象
java.security.spec.X509EncodedKeySpec
public X509EncodedKeySpec(byte[] encodedKey)
Ҏ(gu)指定的二q制~码的字串生成一个key的说?br />参数:encodedKey 二进制编码的字串(一般能qPublicKey.getEncoded()生成)
javax.crypto.KeyAgreement 密码一至类
public static final KeyAgreement getInstance(java.lang.String algorithm)
throws java.security.NoSuchAlgorithmException
q回一个指定算法的KeyAgreement对象
参数:algorithm 法?现在只能是DiffieHellman(DH)
public final void init(java.security.Key key)
throws java.security.InvalidKeyException
用指定的U钥初始?br />参数:key 一个私?/p>
public final java.security.Key doPhase(java.security.Key key,
boolean lastPhase)
throws java.security.InvalidKeyException,
java.lang.IllegalStateException
用指定的公钥q行定位,lastPhase定q是否是最后一个公?对于两个用户?br />情况下就可以多次定次,最后确?br />参数:key 公钥
lastPhase 是否最后公?/p>
public final SecretKey generateSecret(java.lang.String algorithm)
throws java.lang.IllegalStateException,
java.security.NoSuchAlgorithmException,
java.security.InvalidKeyException
Ҏ(gu)指定的算法生成密?br />参数:algorithm 加密法(可用 DES,DESede,Blowfish)
*/
import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.*;
import java.security.interfaces.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.crypto.interfaces.*;
import com.sun.crypto.provider.SunJCE;
public class testDHKey {
public static void main(String argv[]) {
try {
testDHKey my= new testDHKey();
my.run();
} catch (Exception e) {
System.err.println(e);
}
}
private void run() throws Exception {
Security.addProvider(new com.sun.crypto.provider.SunJCE());
System.out.println("ALICE: 产生 DH ?...");
KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH");
aliceKpairGen.initialize(512);
KeyPair aliceKpair = aliceKpairGen.generateKeyPair(); //生成旉?
// 张三(Alice)生成公共密钥 alicePubKeyEnc q发送给李四(Bob) ,
//比如用文件方?socket.....
byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();
//bob接收到alice的编码后的公?其解码
KeyFactory bobKeyFac = KeyFactory.getInstance("DH");
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec (alicePubKeyEnc);
PublicKey alicePubKey = bobKeyFac.generatePublic(x509KeySpec);
System.out.println("alice公钥bob解码成功");
// bob必须用相同的参数初始化的他的DH KEY?所以要从Alice发给他的公开密钥,
//中读出参?再用q个参数初始化他?DH key?/p>
//从alicePubKye中取alice初始化时用的参数
DHParameterSpec dhParamSpec = ((DHPublicKey)alicePubKey).getParams();
KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH");
bobKpairGen.initialize(dhParamSpec);
KeyPair bobKpair = bobKpairGen.generateKeyPair();
System.out.println("BOB: 生成 DH key Ҏ(gu)?);
KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");
bobKeyAgree.init(bobKpair.getPrivate());
System.out.println("BOB: 初始化本地key成功");
//李四(bob) 生成本地的密?bobDesKey
bobKeyAgree.doPhase(alicePubKey, true);
SecretKey bobDesKey = bobKeyAgree.generateSecret("DES");
System.out.println("BOB: 用alice的公钥定位本地key,生成本地DES密钥成功");
// Bob生成公共密钥 bobPubKeyEnc q发送给Alice,
//比如用文件方?socket.....,使其生成本地密钥
byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();
System.out.println("BOB向ALICE发送公?);
// alice接收?bobPubKeyEnc后生成bobPubKey
// 再进行定?使aliceKeyAgree定位在bobPubKey
KeyFactory aliceKeyFac = KeyFactory.getInstance("DH");
x509KeySpec = new X509EncodedKeySpec(bobPubKeyEnc);
PublicKey bobPubKey = aliceKeyFac.generatePublic(x509KeySpec);
System.out.println("ALICE接收BOB公钥q解码成?);
;
KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
aliceKeyAgree.init(aliceKpair.getPrivate());
System.out.println("ALICE: 初始化本地key成功");
aliceKeyAgree.doPhase(bobPubKey, true);
// 张三(alice) 生成本地的密?aliceDesKey
SecretKey aliceDesKey = aliceKeyAgree.generateSecret("DES");
System.out.println("ALICE: 用bob的公钥定位本地key,q生成本地DES密钥");
if (aliceDesKey.equals(bobDesKey)) System.out.println("张三和李四的密钥相同");
//现在张三和李四的本地的deskey是相同的所?完全可以q行发送加?接收后解?辑ֈ
//安全通道的的目的
/*
* bob用bobDesKey密钥加密信息
*/
Cipher bobCipher = Cipher.getInstance("DES");
bobCipher.init(Cipher.ENCRYPT_MODE, bobDesKey);
String bobinfo= "q是李四的机密信?;
System.out.println("李四加密前原?"+bobinfo);
byte[] cleartext =bobinfo.getBytes();
byte[] ciphertext = bobCipher.doFinal(cleartext);
/*
* alice用aliceDesKey密钥解密
*/
Cipher aliceCipher = Cipher.getInstance("DES");
aliceCipher.init(Cipher.DECRYPT_MODE, aliceDesKey);
byte[] recovered = aliceCipher.doFinal(ciphertext);
System.out.println("alice解密bob的信?"+(new String(recovered)));
if (!java.util.Arrays.equals(cleartext, recovered))
throw new Exception("解密后与原文信息不同");
System.out.println("解密后相?);
}
}
W??结
在加密术中生成密钥对Ӟ密钥对的当然是越长越好,但费时也多Q请从中从实际出发选取合适的长度Q大部分例码中的密钥是每ơ运行就从新生成Q在实际的情况中是生成后在一D|间保存在文g中,再次q行直接从文件中dQ从而加快速度。当然定时更新和加强密钥保管的安全性也是必ȝ?br />