风之语

posts(201) comments(182) trackbacks(1)
  • BlogJava
  • 联系
  • RSS 2.0 Feed 聚合
  • 管理

常用链接

  • 我的随笔
  • 我的评论
  • 我的参与
  • 最新评论

留言簿

  • 给我留言
  • 查看公开留言
  • 查看私人留言

随笔分类

  • ajax(1)
  • android(1)
  • apache(1)
  • AppFuse(1)
  • BIRT(1)
  • iText(1)
  • JSF(8)
  • kettle(1)
  • linux(5)
  • mac(1)
  • maven(1)
  • MSTR(3)
  • Open XML(1)
  • Oracle(21)
  • RCP
  • Struts(2)
  • Struts2(2)
  • SybaseIQ(6)
  • tapestry
  • tomcat(2)
  • weblogic(1)
  • webservice(1)
  • weka(1)
  • 云计算(1)
  • 收藏(31)
  • 数据仓库(11)
  • 架构设计(3)
  • 生活(2)
  • 集群(1)
  • 项目管理(6)

随笔档案

  • 2012年12月 (4)
  • 2012年11月 (1)
  • 2012年7月 (2)
  • 2011年8月 (1)
  • 2011年7月 (1)
  • 2011年3月 (1)
  • 2010年12月 (2)
  • 2010年11月 (4)
  • 2010年10月 (3)
  • 2010年9月 (5)
  • 2010年8月 (1)
  • 2010年7月 (4)
  • 2010年3月 (1)
  • 2010年2月 (3)
  • 2009年12月 (3)
  • 2009年11月 (4)
  • 2009年9月 (3)
  • 2009年6月 (5)
  • 2009年5月 (3)
  • 2009年4月 (2)
  • 2009年3月 (5)
  • 2009年2月 (4)
  • 2009年1月 (2)
  • 2008年11月 (2)
  • 2008年9月 (1)
  • 2008年7月 (2)
  • 2008年6月 (4)
  • 2008年5月 (6)
  • 2008年4月 (1)
  • 2008年3月 (1)
  • 2007年12月 (2)
  • 2007年11月 (5)
  • 2007年10月 (2)
  • 2007年9月 (3)
  • 2007年8月 (3)
  • 2007年4月 (1)
  • 2007年3月 (2)
  • 2007年2月 (2)
  • 2007年1月 (2)
  • 2006年12月 (3)
  • 2006年8月 (2)
  • 2006年7月 (2)
  • 2006年6月 (2)
  • 2006年4月 (2)
  • 2006年3月 (1)
  • 2006年2月 (3)
  • 2006年1月 (6)
  • 2005年12月 (6)
  • 2005年11月 (4)
  • 2005年10月 (17)
  • 2005年9月 (25)
  • 2005年8月 (16)
  • 2005年7月 (8)

相册

  • 技术图片

收藏夹

  • java

link

My wife

  • My wife's blog

最新随笔

  • 1. apache修改最大连接并用ab网站压力测试
  • 2. Vm虚拟机访问本地硬盘文件
  • 3. NFS文件无法写入的权限问题
  • 4. weblogic设置上传文件访问权限
  • 5. 在android上动态实现ichartjs的3D柱形图
  • 6. 使用Oracle trunc 来指定精确的年月日时分秒
  • 7. Quartz 2.1.5 web应用配置
  • 8. LoginAny 使用笔记
  • 9. MyEclipse 无响应的几种解决办法
  • 10. java.sql.SQLException: No more data to read from socket

搜索

  •  

积分与排名

  • 积分 - 402311
  • 排名 - 139

最新评论

  • 1. re: 使用Oracle trunc 来指定精确的年月日时分秒[未登录]
  • 政治
  • --张三
  • 2. re: 干掉流氓软件vrvrf_c.exe,vrvedp_m.exe[未登录]
  • `
  • --1
  • 3. re: 无需刻录DMG光盘,教你在VMWare下安装MAC OS X Snow Leopard 10.6
  • 我走到了换DMG映像的时候,然后就没有反应了,这个是什么情况,是不是我的映像文件有问题,还是。。。。
  • --玉竹常青
  • 4. re: LoginAny 使用笔记
  • 怎么没一个人留言,现在来是不是在挖坟啊
  • --ellipse
  • 5. MSTR web应用的部署[未登录]
  • 请问,如何用oracle Application Server服务器部署mstr web应用?
  • --rocky

阅读排行榜

评论排行榜

[BI] 部分商业智能及报表工具一览

[BI] 部分商业智能及报表工具一览
一、 Microsoft Office Web Components

officeComponents.gif

Spreadsheets
excel.gif 

Charts
chart.gif

二、Open Source

1 、pentaho
Project Home Page:
http://www.pentaho.org/
de_logo.png

2、operni


Project Home Page:  http://openi.sourceforge.net/

openi-logo-with-tag[1].jpg

演示:   http://demo.openi.org/          用户:tomcat  密码:shallow
介绍: http://openi.sourceforge.net/open_source_BI-openi_story.PDF


3、JasperReports
Project Home Page: http://jasperreports.sourceforge.net/
jasperreports[1].png


4、Eclipse BIRT Project
Project Home Page: http://www.eclipse.org/birt

5、jfreechar
Project Home Page: http://www.jfree.org/jfreechar


其它相关 :生xsl ,pdf
jakarta poi    http://jakarta.apache.org/poi/
itext  http://www.lowagie.com/iText
FOP  http://xml.apache.org/fop/index.html

后注:本站将不定期发布相关的应用文章:)

posted @ 2005-08-23 10:19 风 阅读(271) | 评论 (1) | 编辑 收藏

MyEclipse4.0破解

MyEclispe4.0下载地址:http://216.114.78.154/downloads/products/eworkbench/4.0M2/EnterpriseWorkbenchInstaller_4.0M2_E3.1.exe
破解文件下载地址:
http://www.matrix.org.cn/resource/upload/content/2005_07_13_154811_vctVIsdnZt.rar
http://www.matrix.org.cn/resource/upload/content/2005_08_02_170115_ccVnsGZqGM.rar
http://www.matrix.org.cn/resource/upload/content/2005_08_10_172204_vhpHkOaHYI.rar(这个应该好用些)
注册码:
用户名 : FALLEN
注册码 : SL6789|838-66|545454|6133571955
本破解文件使用方法:
把哪个core.Jar文件复制到MyEclipse安装目录下面的MyEclipse\eclipse\plugins\com.genuitec.eclipse.core_3.9.210目录中,
覆盖原文件即可。

posted @ 2005-08-13 16:53 风 阅读(12245) | 评论 (10) | 编辑 收藏

jdk5.0新特性

您也许已经见过这样的报告,即一些新的 Java 语言变化包含易于开发性主题。这些变化包括泛型、元数据、autoboxing、增强的 for 循环、枚举类型、静态导入、C 风格的格式化 I/O、可变参数、并发实用程序以及更简单的 RMI 接口生成。

JSR 201 包括如下四个语言变化:增强的 for 循环、枚举类型、静态导入和 autoboxing;JSR 175 指定了新的元数据功能,而 JSR 14 则详细说明了泛型。

javac 编译器执行的默认语言规范是版本 1.4。这意味着要利用以下语言变化的任何好处,需要向 javac 命令传递参数 -source 1.5。

元数据
J2SE 1.5 中的元数据特性提供这样的能力,即向 Java 类、接口、方法和字段关联附加的数据。这些附加的数据或者注释,可以被 javac 编译器或其他工具读取,并且根据配置不同,可以被保存在类文件中,也可以在运行时使用 Java 反射 API 被发现。

向 Java 平台增加元数据的一个主要原因是,使得开发工具和运行工具有一个通用的基础结构,以减少开发和部署所需的成本。工具可以使用元数据信息生成附加的源代码,或者在调试时提供附加信息。

下面的例子用元数据工具创建了一个调试元数据注释,这些元数据注释然后又简单地在运行时显示出来。可以想像,大部分的元数据标签形成一个标准,即一个良好规范的集合。

import java.lang.annotation.*;
import java.lang.reflect.*;

@Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @interface debug {
boolean devbuild() default false;
int counter();
}

public class MetaTest {
final boolean production=true;

@debug(devbuild=production,counter=1) public void testMethod() {
}


public static void main(String[] args) {

MetaTest mt = new MetaTest();
try {
Annotation[] a = mt.getClass().getMethod("testMethod").getAnnotations();
for (int i=0; i<a.length ; i++) {
System.out.println("a["+i+"]="+a+" ");
}
} catch(NoSuchMethodException e) {
System.out.println(e);
}
}
}


利用一个元数据处理工具,许多重复的代码编写步骤可以减少成一个简练的元数据标签。例如,访问某个 JAX-RPC 服务实现时所需的远程接口可以实现为:

原来(J2SE 1.5 以前版本):

public interface PingIF extends Remote {
public void ping() throws RemoteException;
}

public class Ping implements PingIF {
public void ping() {
}
}


现在:

public class Ping {
public @remote void ping() {
}
}


范型
范型一直是 Java 社团所广泛期待的,现在已经是 J2SE 1.5 的一部分了。最先见到使用泛型的地方是在 Collections API 中。Collections API 提供可以被多个 Java 类型使用的公共功能性,比如 LinkedLists、ArrayLists 和 HashMaps。下一个例子使用 1.4.2 库和默认的 javac 编译模式。

ArrayList list = new ArrayList();
list.add(0, new Integer(42));
int total = ((Integer)list.get(0)).intValue();


最后一行中的 Integer 转换是泛型所要防止的强制类型转换问题的一个例子。这个问题在于,1.4.2 Collections API 使用 Object 类来存储 Collection 对象,这就意味着在编译的时候不能找出类型匹配。问题的第一个标志信息是在运行时抛出的 ClassCastException。

带有范型化 Collections 库的同一个例子可编写为:

ArrayList<Integer> list = new ArrayList<Integer>();
list.add(0, new Integer(42));
int total = list.get(0).intValue();


范型化 API 的用户必须使用 <> 符号简单地声明在编译类型中使用的类型。不需要任何类型转换,在本例中试图向一个 Integer 类型的集合中添加 String 对象将会在编译时被捕获。

因此,范型允许 API 设计者提供这样的公共功能性:可以与多种数据类型一起使用,也可以在编译时出于类型安全对它进行检查。

设计自己的 Generic API 比起只是使用它们来说要稍微复杂一些。请从查看 java.util.Collection 源代码和 API 指南开始。

原语类型的 Autoboxing 和 Auto-unboxing
像 int、boolean 以及它们的基于对象的对应物(比如 Integer 和 Boolean)这样的原语类型之间的转换需要大量不必要的额外编码, 尤其是当只是像 Collections API 这样的方法调用需要转换时更甚。

Java 原语类型的 autoboxing 和 auto-unboxing 产生更加精练并更加易于理解的代码。1.5 版本让所需要的转换转变成 Integer 并转换回编译器。

原来

ArrayList<Integer> list = new ArrayList<Integer>();
list.add(0, new Integer(42));
int total = (list.get(0)).intValue();


现在

ArrayList<Integer> list = new ArrayList<Integer>();
list.add(0, 42);
int total = list.get(0);


增强的 for 循环
Collections API 经常使用 Iterator 类。Iterator 类提供在 Collection 中顺序导航的机制。当像下面一样只是在 Collection 中遍历时,新的增强的 for 循环可取代 iterator。编译器生成必要的循环代码,因为利用范型,所以不需要额外的类型转换。

原来

ArrayList<Integer> list = new ArrayList<Integer>();
for (Iterator i = list.iterator(); i.hasNext();) {
Integer value=(Integer)i.next();
}


现在

ArrayList<Integer> list = new ArrayList<Integer>();
for (Integer i : list) { ... }


枚举类型
当使用 static final 型常量时,该类型提供枚举的类型。如果您以前在自己的应用程序中使用过标识符 enum,那么在利用 javac -source 1.5 编译时需要调整源代码。

public enum StopLight { red, amber, green };


静态导入
静态导入特性实现为“import static”,允许您从一个类引用静态常量,而不需要继承这个类。每次我们添加一个组件时,不必使用 BorderLayout.CENTER,只要引用 CENTER 就可以了。

import static java.awt.BorderLayout.*;

getContentPane().add(new JPanel(), CENTER);


格式化的输出
现在开发人员可以选择使用 printf type 功能性来生成格式化的输出。这将有助于迁移传统的 C 应用程序,作很少的更改或者不作更改就能保留相同的文本布局。

大多数公共 C printf 格式化程序是可用的,另外,一些 Java 类(比如 Date 和BigInteger)也具有格式化规则。更多信息请参见 java.util.Formatter 类。

System.out.printf("name count\n");
System.out.printf("%s %5d\n", user,total);


格式化的输入
Scanner API 为从系统控制台或任何数据流读取数据提供基本的输入功能性。下面的例子从标准输入读取一个 String 并期待下一个 int 值。

如果没有数据可用,像 next 和 nextInt 这样的 Scanner 方法将会阻塞。如果您需要处理更加复杂的输入,那么从 java.util.Formatter 类还可以得到模式匹配算法。

Scanner s=Scanner.create(System.in);
String param= s.next();
int value=s.nextInt();
s.close();


Varargs
varargs(可变参数)功能性允许多个参数传递作为方法的参数。它需要简单的 ... 符号,该符号用于接收参数列表的方法,并且它还被用于实现 printf 所需参数的灵活数量。

void argtest(Object ... args) {
for (int i=0;i <args.length; i++) {
}
}

argtest("test", "data");


并发实用程序
并发实用程序库由 Doug Lea 定义在 JSR-166 中,是 J2SE 1.5 平台中流行的并发软件包的一个特殊版本。它提供强大的、高级别的线程构造,包括 executors(这是一个线程任务框架)、线程安全队列、Timers、锁(包括原子锁)和其他同步原语。

著名的旗语(semaphore)是这样一个锁。旗语与现在使用的 wait 的使用方式相同,用于限制对一块代码的访问。旗语更加灵活,并且也允许许多并发的线程访问,同时允许您在获得一个锁之前对它进行测试。下面的例子使用刚好一个旗语,也叫做二进制旗语。更多信息请参见 java.util.concurrent 软件包。

final private Semaphore s= new Semaphore(1, true);

s.acquireUninterruptibly(); //for non-blocking version use s.acquire()

balance=balance+10; //protected value
s.release(); //return semaphore token


rmic —— rmi 编译器
您不再需要使用 rmic —— rmi 编译器工具——来生成最远程的接口存根。动态代理的引入意味着通常由存根提供的信息可以在运行时被发现。更多信息请参见 RMI 版本说明。

可扩展性和性能
1.5 版本承诺在可扩展性和性能方面的改进,新的重点在于启动时间和内存占用,使它更加易于以最大的速度部署应用程序。

最重大的一个更新是引入了 Hotspot JVM 中的类数据共享。该技术不仅在多个正在运行的 JVM 之间共享只读数据,而且改进了启动时间,因为核心的 JVM 类都是预先打包的。

性能工效是 J2SE 1.5 中的一个新特性,这意味着如果您一直使用的是以前版本中专门的 JVM 运行时选项, 那么可能值得不用选项或者用很少的选项重新验证您的性能。

监控和可管理性
监控和可管理性是 Java 平台中的 RAS (Reliability, Availability, Serviceability,即可*性、可用性、可服务性) 的一个关键组件。

JVM Monitoring & Management API (JSR-174) 指定一组全面的可以从正在运行的 JVM 进行监控的 JVM internals。 该信息可通过 JMX (JSR-003) MBeans 访问到,也可以使用 JMX 远程接口 (JSR-160) 和行业标准 SNMP 工具而远程访问得到。

最有用的一个特性是一个低内存检测程序。当超过阀值时,JMX MBeans 可以通知已注册的侦听程序。更多信息请参见 javax.management 和 java.lang.management。

为了了解新的 API 是多么容易使用,下面报告了 Hotspot JVM 中内存堆的详细使用情况。

import java.lang.management.*;
import java.util.*;
import javax.management.*;

public class MemTest {
public static void main(String args[]) {
List pools =ManagementFactory.getMemoryPoolMBeans();
for(ListIterator i = pools.listIterator(); i.hasNext();) {
MemoryPoolMBean p = (MemoryPoolMBean) i.next();
System.out.println("Memory type="+p.getType()+" Memory usage="+p.getUsage());
}
}
}


新的 JVM profiling API (JSR-163)
该版本还包含一个更强大的本机 profiling API,叫做 JVMTI。该 API 已经在 JSR 163 中指定了,并由对改善的 profiling 接口的需求所推动。但是,JVMTI 除了具有 profiling 功能之外,还想要涵盖全范围的本机内部过程工具访问,包括监控工具、调试工具以及潜在的各种各样的其他代码分析工具。

该实现包含一个用于字节码装置(instrumentation)——Java 编程语言装置服务(Java Programming Language Instrumentation Services,JPLIS)的机制。这使得分析工具只在需要的地方添加额外的配置信息(profiling)。该技术的优点是,它允许更加集中的分析,并且限制了正在运行的 JVM 上的 profiling 工具的引用。该装置甚至可以在运行时和类加载时动态地生成,并且可以作为类文件预先处理。

下面这个例子创建了一个装置钩(instrumentation hook),它可以从磁盘加载类文件的一个已修改的版本。要运行该测试,可利用 java -javaagent:myBCI BCITest 启动 JRE。


//File myBCI.java
import java.lang.instrument.Instrumentation;

public class myBCI {
private static Instrumentation instCopy;

public static void premain(String options, Instrumentation inst) {
instCopy = inst;
}
public static Instrumentation getInstrumentation() {
return instCopy;
}
}

//File BCITest.java

import java.nio.*;
import java.io.*;
import java.nio.channels.*;
import java.lang.instrument.*;

public class BCITest {
public static void main (String[] args) {
try {
OriginalClass mc = new OriginalClass();
mc.message();

FileChannel fc=new FileInputStream(new File("modified"+File.separator+"OriginalClass.class")).getChannel();
ByteBuffer buf = fc.map(FileChannel.MapMode.READ_ONLY, 0, (int)fc.size());
byte[] classBuffer = new byte[buf.capacity()];
buf.get(classBuffer, 0, classBuffer.length);
myBCI.getInstrumentation().redefineClasses(new ClassDefinition[] {new ClassDefinition(mc.getClass(), classBuffer)});
mc.message();
}catch (Exception e){}
}
}

//OriginalClass.java
//Compile in current directory
//Copy source to modified directory,change message and recompile

public class OriginalClass {
public void message() {
System.out.println("OriginalClass");
}
}



改进的诊断能力
如果没有控制台窗口可用,生成的 Stack 跟踪就很笨拙。两个新的 API —— getStackTrace 和 Thread.getAllStackTraces —— 以程序的方式提供该信息。

StackTraceElement e[]=Thread.currentThread().getStackTrace();
for (int i=0; i <e.length; i++) {
System.out.println(e);
}
System.out.println("\n"+Thread.getAllStackTraces());


Hotspot JVM 包含一个致命的错误处理程序(error hander),如果 JVM 异常中断,它可以运行用户提供的脚本。使用 Hotspot JVM 可服务性代理连接器,调试工具也可以连接到一个挂起的 JVM 或者核心文件。

-XX:OnError="command"

-XX:OnError="pmap %p"
-XX:OnError="gdb %p"

optional %p used as process id


桌面客户端
Java 桌面客户端保留有 Java 平台的一个关键组件,并且这一点成了 J2SE 1.5 中许多改进的焦点。

这个 Beta 版本包含启动时间和内存占用方面的一些早期改进。该版本不仅更快,并且 Swing 工具集采用了一个暂新的叫做 Ocean 的主题。

通过建立 J2SE 1.4.2 中的更新,GTK 和 Windows XP 外观方面有了更进一步的改进。


Windows XP
Click to Enlarge

Linux/Redhat
Click to Enlarge

具有最新 OpenGL 驱动程序并且选择了图形卡的 Linux 和 Solaris 用户,可以使用下面的运行时属性从 Java2D 获得本机硬件加速:

java -Dsun.java2d.opengl=true -jar Java2D.

Linux 版本也具有快速的 X11 Toolkit,叫做 XAWT,默认情况下是启用的。如果您需要与 motif 版本进行比较,可以使用下面的系统属性:

java -Dawt.toolkit=sun.awt.motif.MToolkit -jar Notepad.jar

(X11 Toolkit 叫做 sun.awt.X11.XToolkit)

X11 Toolkit 也使用 XDnD 协议,所以您可以在 Java 和其他应用(比如 StarOffice 或 Mozilla)之间拖放简单的组件。

其他特性
核心 XML 支持
J2SE 1.5 引入了核心 XML 平台的几个修订,包括 XML 1.1 和 Namespace、XML Schema、SAX 2.0.1、XSLT 和快速 XLSTC 编译器,以及最后的 DOM 第 3 层支持。

除了支持核心 XML 之外,未来版本的 Java Web Services Developer Pack 将交付最新的 Web 服务标准:JAX-RPC & SAAJ (WSDL/SOAP)、JAXB、XML Encryption and Digital Signature,以及用于注册的 JAXR。

辅助字符支持
32 位的辅助字符支持作为传输到 Unicode 4.0 支持的一部分,已经慎重地添加到该平台。辅助字符被编码为一对特殊的 UTF16 值,以生成一个不同的字符或者码点(codepoint)。一个代理对(surrogate pair)是一个高 UTF16 值和后面的一个低 UTF16 值的组合。这些高值和低值来自一个特殊范围的 UTF16 值。

一般来说,当使用 String 或者字符序列时,核心 API 库将透明地为您处理新的辅助字符。但是因为 Java "char" 仍然保留为 16 位,所以非常少的一些使用 char 作为参数的方法,现在有了足够的可以接受 int 值的方法,其中 int 值可以代表新的更大的值。特别是 Character 类,具有附加的方法来检索当前的字符和接下来的字符,以便检索辅助的码点值,如下所示:

String u="\uD840\uDC08";
System.out.println(u+"+ "+u.length());
System.out.println(Character.isHighSurrogate(u.charAt(0)));
System.out.println((int)u.charAt(1));
System.out.println((int)u.codePointAt(0));


更多信息请参见 Character 中的 Unicode 部分。

JDBC RowSets
JDBC 行集支持有两个主要的更新。CachedRowSet 包含从数据库检索的行的内存中的集合。但是它们也是不连接的,这意味着以后更新可以与数据库重新同步。

另一个组件是 WebRowSet,它使用数据库行通过 XML 来传输数据。

参考资料:
New Language Features for Ease of Development in the Java 2 Platform, Standard Edition 1.5: http://java.sun.com/features/2003/05/bloch_qa.html

Tiger Component JSRs
003 Java Management Extensions (JMX) Specification http://jcp.org/en/jsr/detail?id=3

013 Decimal Arithmetic Enhancement http://jcp.org/en/jsr/detail?id=13

014 Add Generic Types To The Java Programming Language http://jcp.org/en/jsr/detail?id=14

028 Java SASL Specification http://jcp.org/en/jsr/detail?id=28

114 JDBC Rowset Implementations http://jcp.org/en/jsr/detail?id=114

133 Java Memory Model and Thread Specification Revision http://jcp.org/en/jsr/detail?id=133

160 Java Management Extensions (JMX) Remote API 1.0 http://jcp.org/en/jsr/detail?id=160

163 Java Platform Profiling Architecture http://jcp.org/en/jsr/detail?id=163

166 Concurrency Utilities http://jcp.org/en/jsr/detail?id=166

174 Monitoring and Management Specification for the Java Virtual Machine http://jcp.org/en/jsr/detail?id=174

175 A Metadata Facility for the Java Programming Language http://jcp.org/en/jsr/detail?id=175

200 Network Transfer Format for Java Archives http://jcp.org/en/jsr/detail?id=200

201 Extending the Java Programming Language with Enumerations, Autoboxing, Enhanced for Loops and Static Import http://jcp.org/en/jsr/detail?id=201

204 Unicode Supplementary Character Support http://jcp.org/en/jsr/detail?id=204

206 Java API for XML Processing (JAXP) 1.3 http://jcp.org/en/jsr/detail?id=206

posted @ 2005-08-12 21:27 风 阅读(795) | 评论 (0) | 编辑 收藏

Jdk5.0新特性——Generic Types (泛型) (二)

六、与遗留代码的交互


到现在为止,我们所有的例子都是在一个假想的理想世界里面的,就是所有的
人都在使用Java语言支持泛型的最新版本。
唉,不过在现实中情况却不是那样。千百万行的代码都是用早期版本的语言
来编写的,不可能把它们全部在一夜之间就转换过来。
在后面的第10部分,我们将会解决把遗留代码转为用泛型这个问题。在这部分
我们要看的是比较简单的问题:遗留代码与泛型代码如何交互?这个问题分为两个
部分:在泛型代码中使用遗留代码和在遗留代码中使用泛型代码。


六-1 在泛型代码中使用遗留代码

[url=http://xoj.blogone.net][url]
当你在享受在代码中使用泛型带来的好处的时候,你怎么样使用遗留代码呢?
假设这样一个例子,你要使用com.Foodlibar.widgets这个包。Fooblibar.com
的人要销售一个库存控制系统,主要部分如下:

package com.Fooblibar.widgets;
public interface Part { ... }
public class Inventory {
/**
*Adds a new Assembly to the inventory databse.
*The assembly is given the name name, and consists of a set
*parts specified by parts. All elements of the collection parts
*must support the Part interface.
**/
public static void addAssembly(String name, Collection parts) {...}
public static Assembly getAssembly(String name) {...}
}
public interface Assembly{
Collection getParts();//Returns a collection of Parts
}

现在,你可以用上面的API来增加新的代码,它可以很好的保证你调用参数恰当
的addAssembly()方法,就是说传递的集合是一个Part类型的Collection对象,当
然,泛型是最适合做这个:

package com.mycompany.inventory;
import com.Fooblibar.widgets.*;
public class Blade implements Part{
...
}
public class Guillotine implements Part {
}
public class Main {
public static void main(Sring[] args) {
Collection<Part> c = new ArrayList<Part>();
c.add(new Guillotine());
c.add(new Blade());
Inventory.addAssembly("thingee", c);
Collection<Part> k = Inventory.getAssembly("thingee").getParts();
}
}

当我们调用addAssembly方法的时候,它想要的第二个参数是Collection类型的,
实参是Collection<Part>类型,但却可以,为什么呢?毕竟,大多数集合存储的都不是
Part对象,所以总的来说,编译器不会知道Collection存储的是什么类型的集合。
在正规的泛型代码里面,Collection都带有类型参数。当一个像Collection这样
的泛型不带类型参数使用的时候,称之为原生类型。
很多人的第一直觉是Collection就是指Collection<Object>,但从我们先前所
看到的可以知道,当需要的对象是Collection<Object>,而传递的却是Collection<Part>
对象的时候,是类型不安全的。确切点的说法是Collection类型表示一个未知类型的
集合,就像Collection<?>。
稍等一下,那样做也是不正确的!考虑一下调用getParts()方法,它返回一个
Collection对象,然后赋值给k,而k是Collection<Part>类型的;如果调用的结果
是返回一个Collection<?>的对象,这个赋值可能是错误的。
事实上,这个赋值是允许的,只是它会产生一个未检测警告。警告是需要的,因为
编译器不能保证赋值的正确性。我们没有办法通过检测遗留代码中的getAssembly()方法
来保证返回的集合的确是一个类型参数是Part的集合。程序里面的类型是Collection,
我们可以合法的对此集合插入任何对象。
所以,这不应该是错误的吗?理论上来说,答案是:是;但实际上如果是泛型代码
调用遗留代码的话,这又是允许的。对这个赋值是否可接受,得取决于程序员自己,在
这个例子中赋值是安全的,因为getAssembly()方法约定是返回以Part作为类型参数的
集合,尽管在类型标记中没有表明。
所以原生类型很像通配符类型,但它们没有那么严格的类型检测。这是有意设计成
这样的,从而可以允许泛型代码可以与之前已有的遗留代码交互。
在泛型代码中调用遗留代码固然是危险的,一旦把泛型代码和非泛型代码混合在一
起,泛型系统所提供的全部安全保证就都变得无效了。但这仍比根本不使用泛型要好,
最起码你知道你的代码是一致的。
泛型代码出现的今天,仍然有很多非泛型代码,二者混合同时使用是不可避免的。
如果一定要把遗留代码与泛型代码混合使用,请小心留意那些未检测警告。仔细的
想想如何才能判定引发警告的代码是安全的。
如果仍然出错,代码引发的警告实际不是类型安全的,那又怎么样呢?我们会看
那样的情况,接下来,我们将会部分的观察编译器的工作方式。


六-2 擦除和翻译


public String loophole(Integer x){
List<String> ys = new LinkedList<String>();
List xs = ys;
xs.add(x);//编译时未检测警告
return ys.iterator().next();
}

在这里我们定义了一个字符串类型的链表和一个一般的老式链表,我们先插入
一个Integer对象,然后试图取出一个String对象,很明显这是错误的。如果我们
忽略警告继续执行代码的话,程序将会在我们使用错误类型的地方出错。在运行时,
代码执行大致如下:

public String loophole(Integer x) {
List ys = new LinkedList;
List xs = ys;
xs.add(x);
return (String)ys.iterator().next();//运行时出错
}

当我们要从链表中取出一个元素,并把它当作是一个字符串对象而把它转换为
String类型的时候,我们将会得到一个ClassCastException类型转换异常。在
泛型版本的loophole()方法里面发生的就是这种情况。
出现这种情况的原因是,Java的泛型是通过一个前台转换“擦除”的编译器实现
的,你基本上可以认为它是一个源码对源码的翻译,这就是为何泛型版的loophole()
方法转变为非泛型版本的原因。
结果是,Java虚拟机的类型安全性和完整性永远不会有问题,就算出现未检测
的警告。
基本上,擦除会除去所有的泛型信息。尖括号里面的所有类型信息都会去掉,比
如,参数化类型的List<String>会转换为List。类型变量在之后使用时会被类型
变量的上界(通常是Object)所替换。当最后代码不是类型正确的时候,就会加入
一个适当的类型转换,就像loophole()方法的最后一行。
对“擦除”的完整描述不是本指南的范围内的内容,但前面我们所给的简单描述
也差不多是那样了。了解这点很有好处,特别是当你想做诸如把现有API转为使用
泛型(请看第10部分)这样复杂的东西,或者是想知道为什么它们会那样的时候。

六-3 在遗留代码中使用泛型



现在我们来看看相反的情况。假设Fooblibar.com把他们的API转换为泛型的,
但有些客户还没有转换。代码就会像下面的:

package com.Fooblibar.widgets;
public interface Part { ... }
publlic class Inventory {
/**
*Adds a new Assembly to the inventory database.
*The assembly is given the name name, and consists of a set
*parts specified by parts. All elements of the collection parts
*must support the Part interface.
**/
public static void addAssembly(String name, Collection<Part> parts) {...}
public static Assembly getAssembly(String name){ ... }
}
public interface Assembly {
Collection<Part> getParts();//Return a collection of Parts
}

客户代码如下:

package com.mycompany.inventory;
import com.Fooblibar.widgets.*;
public class Blade implements Part {
...
}
public class Guillotine implements Part {
...
}
public class Main {
public static void main(String[] args){
Collection c = new ArrayList();
c.add(new Guillotine());
c.add(new Blade());
Inventory.addAssembly("thingee", c);//1: unchecked warning
Collection k = Inventory.getAssembly("thingee").getParts();
}
}

客户代码是在引进泛型之前写下的,但是它使用了com.Fooblibar.widgets包和集
合库,两个现在都是在用泛型的。在客户代码里面使用的泛型全部都是原生类型。
第1行产生一个未检测警告,因为把一个原生Collection传递给了一个需要Part类型的
Collection的地方,编译器不能保证原生的Collection是一个Part类型的Collection。
不这样做的话,你也可以在编译客户代码的时候使用source 1.4这个标记来保证不
会产生警告。但是这样的话你就不能使用所有JDK 1.5引入的新的语言特性。

七、晦涩难懂的部分

七-1 泛型类为所有调用所共享
下面的代码段会打印出什么呢?

List<String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
System.out.println(l1.getClass() == l2.getClass());

你可能会说是false,但是你错了,打印的是true,因为所有泛型类的实例它们
的运行时的类(run-time class)都是一样的,不管它们实际类型参数如何。
泛型类之所以为泛型的,是因为它对所有可能的类型参数都有相同的行为,相同
的类可以看作是有很多不同的类型。
结果就是,一个类的静态的变量和方法也共享于所有的实例中,这就是为什么不
允许在静态方法或初始化部分、或者在静态变量的声明或初始化中引用类型参数。

七-2 强制类型转换和instanceof

泛型类在它所有的实例中共享,就意味着判断一个实例是否是一个特别调用的泛
型的实例是毫无意义的:

Collection cs = new ArrayList<String>();
if (cs instanceof Collection<String>) {...}//非法

类似地,像这样的强制类型转换:

Collection<String> cstr = (Collection<String>) cs;//未检测警告

给出了一个未检测的警告,因为这里系统在运行时并不会检测。
对于类型变量也一样:

<T> T BadCast(T t, Object o) {
return (T) o;//未检测警告
}

类型变量不存在于运行时,这就是说它们对时间或空间的性能不会造成影响。
但也因此而不能通过强制类型转换可靠地使用它们了。

七-3 数组

数组对象的组件类型可能不是一个类型变量或一个参数化类型,除非它是一个
(无界的)通配符类型。你可以声明元素类型是类型变量和参数华类型的数组类型,
但元素类型不能是数组对象。
这自然有点郁闷,但这个限制对避免下面的情况是必要的:

List<Strign>[] lsa = new List<String>[10];//实际上是不允许的
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(8));
oa[1] = li;//不合理,但可以通过运行时的赋值检测
String s = lsa[1].get(0);//运行时出错:ClassCastException异常

如果参数化类型的数组允许的话,那么上面的例子编译时就不会有未检测的警告,
但在运行时出错。对于泛型编程,我们的主要设计目标是类型安全,而特别的是这个
语言的设计保证了如果使用了javac -source 1.5来编译整个程序而没有未检测的
警告的话,它是类型安全的。
但是你仍然会使用通配符数组,这与上面的代码相比有两个变化。首先是不使用
数组对象或元素类型被参数化的数组类型,这样我们就需要在从数组中取出一个字符
串的时候进行强制类型转换:

List<?>[] lsa = new List<?>[10];//没问题,无界通配符类型数组
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
oa[1] = li;//正确
String s = (String) lsa[1].get(0);//运行时错误,显式强制类型转换

第二个变化是,我们不创建元素类型被参数化的数组对象,但仍然使用参数化元素
类型的数组类型,这是允许的,但引起现未检测警告。这样的程序实际上是不安全的,
甚至最终会出错。

List<String>[] lsa = new List<?>[10];//未检测警告-这是不安全的!
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<integer>();
li.add(new Integer(3));
oa[1]=li;//正确
String s = lsa[1].get(0);//运行出错,但之前已经被警告

类似地,想创建一个元素类型是类型变量的数组对象的话,将会编译出错。

<T> T[] makeArray(T t){
return new T[100];//错误
}

因为类型变量并不存在于运行时,所以没有办法知道实际的数组类型是什么。
要突破这类限制,我们可以用第8部分说到的用类名作为运行时标记的方法。


八、 把类名作为运行时的类型标记

JDK1.5中的一个变化是java.lang.Class是泛化的,一个有趣的例子是对
容器外的东西使用泛型。
现在Class类有一个类型参数T,你可能会问,T代表什么啊?它就代表Class
对象所表示的类型。
比如,String.class的类型是Class<String>,Serializable.class的
类型是Class<Serializable>,这可以提高你的反射代码中的类型安全性。
特别地,由于现在Class类中的newInstance()方法返回一个T对象,因此
在通过反射创建对象的时候可以得到更精确的类型。
其中一个方法就是显式传入一个factory对象,代码如下:

interface Factory<T> {T make();}
public <T> Collection<T> select(Factory<T> factory, String statement){
Collection<T> result = new ArrayList<T>();
//用JDBC运行SQL查询
for(/*遍历JDBC结果*/){
T item = factory.make();
/*通过SQL结果用反射和设置数据项*/
result.add(item);
}
return result;
}

你可以这样调用:

select(new Factory<EmpInfo>(){ public EmpInfo make() {
return new EmpInfo();
}}
, "selection string");

或者声明一个EmpInfoFactory类来支持Factory接口:

class EmpInfoFactory implements Factory<EmpInfo>{
...
public EmpInfo make() { return new EmpInfo();}
}

然后这样调用:

select(getMyEmpInfoFactory(), "selection string");

这种解决办法需要下面的其中之一:
· 在调用的地方使用详细的匿名工厂类(verbose anonymous factory classes),或者
· 为每个使用的类型声明一个工厂类,并把工厂实例传递给调用的地方,这样有点不自然。

使用类名作为一个工厂对象是非常自然的事,这样的话还可以为反射所用。现在
没有泛型的代码可能写作如下:

Collection emps = sqlUtility.select(EmpInfo.class, "select * from emps");
...
public static Collection select(Class c, String sqlStatement) {
Collection result = new ArrayList();
/*用JDBC执行SQL查询*/
for(/*遍历JDBC产生的结果*/){
Object item = c.newInstance();
/*通过SQL结果用反射和设置数据项*/
result.add(item);
}
return result;
}

但是,这样并不能得到我们所希望的更精确的集合类型,现在Class是泛化的,
我们可以这样写:

Collection<EmpInfo> emps =
sqlUtility.select(EmpInfo.class, "select * from emps");
...
public static <T> Collection<T> select(Class<T> c, String sqlStatement) {
Collection<T> result = new ArrayList<T>();
/*用JDBC执行SQL查询*/
for(/*遍历JDBC产生的结果*/){
T item = c.newInstance();
/*通过SQL结果用反射和设置数据项*/
result.add(item);
}
return result;
}

这样就通过类型安全的方法来得到了精确的集合类型了。
这种使用类名作为运行时类型标记的技术是一个很有用的技巧,是需要知道的。
在处理注释的新的API中也有很多类似的情况。

九 通配符的其他作用

(more fun with wildcards,不知道如何译才比较妥当,呵呵。)

在这部分,我们将会仔细看看通配符的几个较为深入的用途。我们已经从几个
有界通配符的例子中看到,它对从某一数据结构中读取数据是很有用的。现在来看
看相反的情况,只对数据结构进行写操作。
下面的Sink接口就是这类情况的一个简单的例子:

interface Sink<T> {
flush(T t);
}

我们可以想象在下面的示范的例子中使用它,writeAll()方法用于把coll集合
里的所有元素填充(flush)到Sink接口变量snk中,并返回最后一个填充的元素。

public static <T> T writeAll(Collection<T> coll, Sink<T> snk){
T last;
for (T t: coll){
last = t;
snk.flush(last);
}
return last;
}
...
Sink<Object> s;
Collection<String> cs;
String str = writeAll(cs, s);//非法调用

如注释所注,这里对writeAll()方法的调用是非法的,因为无有效的类型参数
可以引用;String和Object都不适合作为T的类型,因为Collection和Sink的元素
必须是相同类型的。
我们可以通过使用通配符来改写writeAll()的方法头来处理,如下:

public static <T> T writeAll(Collection<? extends T>, Sink<T>) {...}
...
String str = writeAll(cs, s);//调用没问题,但返回类型错误

现在调用是合法的了,但由于T的类型跟元素类型是Object的s一样,因为返回的
类型也是Object,因此赋值是不正确的。
解决办法是使用我们之前从未见过的一种有界通配符形式:带下界的通配符。
语法 ? super T 表示了是未知的T的父类型,这与我们之前所使用的有界
(父类型:或者T类型本身,要记住的是,你类型关系是自反的)
通配符是对偶有界通配符,即用 ? extends T 表示未知的T的子类型。

public static<T> T writeAll(Collection<T> coll, Sink<? super T> snk) {...}
...
String str = writeAll(cs, s);//正确!

使用这个语法的调用是合法的,指向的类型是所期望的String类型。

现在我们来看一个比较现实一点的例子,java.util.TreeSet<E>表示元素类型
是E的树形数据结构里的元素是有序的,创建一个TreeSet对象的一个方法是使用参数
是Comparator对象的构造函数,Comparator对象用于对TreeSet对象里的元素进行
所期望的排序进行分类。

TreeSet(Comparator<E> c)

Comparator接口是必要的:

interface Comparator<T> {
int compare(T fst, T snd);
}

假设我们想要创建一个TreeSet<String>对象,并传入一下合适的Comparator
对象,我们传递的Comparator是能够比较字符串的。我们可以用Comparator<String>,
但Comparator<Object>也是可以的。但是,我们不能对Comparator<Object>对象
调用上面所给的构造函数,我们可以用一个下界通配符来得到我们想要的灵活性:

TreeSet(Comparator<? super E> c)

这样就可以使用适合的Comparator对象啦。
最后一个下界通配符的例子,我们来看看Collections.max()方法,这个方法
返回作为参数传递的Collection对象中最大的元素。
现在,为了max()方法能正常运行,传递的Collection对象中的所有元素都必
须是实现了Comparable接口的,还有就是,它们之间必须是可比较的。
先试一下泛化方法头的写法:

public static <T extends Comparable<T>>
T max(Collection<T> coll)

那样,方法就接受一个自身可比较的(comparable)某个T类型的Collection
对象,并返回T类型的一个元素。这样显得太束缚了。
来看看为什么,假设一个类型可以与合意的对象进行比较:

class Foo implements Comparable<Object> {...}
...
Collection<Foo> cf = ...;
Collectins.max(cf);//应该可以正常运行

cf里的每个对象都可以和cf里的任意其他元素进行比较,因为每个元素都是Foo
的对象,而Foo对象可以与任意的对象进行比较,特别是同是Foo对象的。但是,使用
上面的方法头,我们会发现这样的调用是不被接受的,指向的类型必须是Foo,但Foo
并没有实现Comparable<Foo>。
T对于自身的可比性不是必须的,需要的是T与其父类型是可比的,就像下面:
(实际的Collections.max()方法头在后面的第10部分将会讲得更多)

public static <T extends Comparable<? super T>>
T max(Collection<T> coll)

这样推理出来的结果基本上适用于想用Comparable来用于任意类型的用法:
就是你想这样用Comparable<? super T>。
总的来说,如果你有一个只能一个T类型参数作为实参的API的话,你就应该用
下界通配符类型(? suer T);相反,如果API只返回T对象,你就应该用上界通
配符类型(? extends T),以使得你的客户的代码有更大的灵活性。

九-1 通配符捕捉(?wildcard capture)

现在应该很清楚,给出下面的例子:

Set<?> unknownSet = new HashSet<String>();
...
/** 给Set对象s添加一个元素t*/
public static <T> void addToSet<Set<T> s, T t) {...}

下面的调用是非法的。

addToSet(unknownSet, "abc");//非法的

这无异于实际传递的Set对象是一个字符串类型的Set对象,问题是作为实参传递的
是一个未知类型的Set对象,这样就不能保证它是一个字符串类型或其他类型的Set对象。
现在,来看下面:

class Collections{
...
<T> public static Set<T> unmodifiableSet<Set<T> set) {...}
}
...
Set<?> s = Collections.unmodifiableSet(unknownSet);//这是可以的,
//为什么呢?
看起来这应该是不允许的,但是请看看这个特别的调用,这完全是安全的,因此
这是允许的。这里的unmodifiableSet()确实是对任何类型的Set都适合,不管它的
元素类型是什么。
因为这种情况出现得相对频繁,因此就有一个特殊的规则,对代码能够被检验是
安全的任何特定的环境,那样的代码都是允许的。这个规则就是所谓的“通配符捕捉”,
允许编译器对泛型方法引用未知类型的通配符作为类型实参。

十 把遗留代码转化为泛型代码

早前,我们展示了如何使泛型代码和遗留代码交互,现在该是时候来看看更难的
问题:把老代码改为泛型代码。
如果决定了把老代码转换为泛型代码,你必须慎重考虑如何修改你的API。
你不能对泛型API限制得太死,它得要继续支持API的最初约定。再看几个关于
java.util.Collection的例子。非泛型的API就像这样:

interface Collection {
public boolean containsAll(Collection c);
public boolean addAll(Collection c);
}

先这样简单来尝试一下泛化:

interface Collection<E> {
public boolean containsAll(Collection<E> c);
public boolean addAll(Collection<E> c);
}

这个当然是类型安全的,它没有做到API的最初约定,containsAll()方法接受
传入的任何类型的Collection对象,只有当Collection对象中只包括E类型的实例
的时候才正确。但是:
· 传入的Collection对象的静态类型可能不同,这样的原因可能是调用者不知道
传入的Collection对象的精确类型,又或者它是Collection<S>类型的,其中S是E的
子类型。
· 对不同类型的Collection对象调用方法containsAll()完全是合法的,程序
应该能够运行,返回的是false值。
对于addAll()方法这种情况,我们应该能够添加任何存在了E类型的子类型的Collection
对象,我们在第5部分中看过了如何正确处理这种情况。
还要保证改进的API能够保留对老客户的二进制支持(? binary compatibility)。
这就意味着API“擦除”后(erasure)必须与最初的非泛型API一致。在大多数的情
况的结果是自然而然的,但有些小地方却不尽如此。我们将仔细去看看我们之前遇到
过的最小的Collections.max()方法,正如我们在第9部分所见,似乎正确的max()
的方法头:

public static <T extends Comparable<? super T>>
T max(CollectionT> coll)

基本没问题,除了方法头被“擦除”后的情况:

public static Comparable max(Collection coll)

这与max()方法最初的方法头不一样:

public static Object max(Collection coll)

本来是想得到想要的max()方法头,但是没成功,所有老的二进制class文件
调用的Collections.max()都依赖于一个返回Object类型的方法头。
我们可以在类型参数T的边界中显式指定一个父类型来强制改变“擦除”的结果。

public static <T extends Object & Comparable<? super T>>
T max(Collection<T> coll)

这是一个对类型参数给出多个边界的例子,语法是这样:T1 & T2 ... & Tn.
多边界类型变量对边界类型列表中的所有类型的子类型都是可知的,当使用多边界
类型的时候,边界类型列表中的第一个类型将被作为类型变量“擦除”后的类型。
最后,我们应该记住max()方法只是从传入的Collection方法中读取数据,
因此也就适用于类型是T的子类型的任何Collection对象。
这样就有了我们JDK中实际的方法头:

public static <T extends Object & Comparable<? super T>>
T max(Collection<? extends T> coll)

在实践中很少会有涉及到这么多东西的情况,但专业类型设计者在转换现有的API
的时候应该有所准备的仔细思虑。
另一个问题就是要小心协变返回(covariant returns)的情况,那就是改进
子类中方法的返回类型。你不应该在老API中使用这个特性。
假设你最初的API是这样的:

public class Foo {
public Foo create {...}//工厂方法,应该是创建声明的类的一个实例
}
public class Bar extends Foo {
public Foo create() {...}//实际是创建一个Bar实例
}

用协变返回的话,是这样改:

public class Foo {
public Foo create {...}//工厂方法,应该是创建声明的类的一个实例
}
public class Bar extends Foo {
public Bar create() {...}//实际是创建一个Bar实例
}

现在,假设有这样的第三方客户代码:

public class Baz extends Bar {
public Foo create() {...} //实际是创建一个Baz实例
}

Java虚拟机不直接支持不同返回类型的方法的覆盖,编译器就是支持这样的
特性。结果就是,除非重编译Baz类,否则的话它不会正确覆盖Bar中的create()
方法。此外,Baz类需要修改,因为上面写的代码不能通过编译,Baz中create()
方法的返回类型不是Bar类中create()方法的返回类型的子类型。

posted @ 2005-08-12 19:35 风 阅读(638) | 评论 (0) | 编辑 收藏

eclipse3.1简介及其插件

引论
    笔者使用Eclipse有些时日了,从Eclipse2.0使用到现在,今天从  http://www.eclipse.org岗站上下载了最新版的Eclipse3.1,使用之后犹感它的强大,Eclipse在平时的工作中给笔者带来了非常的方便,更兼如此今天 使用Eclipse3.1后更感觉它的得心和应手,使人耳目一新,因此笔记将它的新特性及使用后感写出来。希望Eclipse能给更多的JAVA和C开发者带来工作中的方便。
一、新特性
   1.速度更快,效率更高。我们打开Eclipse3.1一看,包括启动,开发的速度都 比3.0快很多了,我大约测试一下,同一个环境下,比3.0启动快了几十秒。
    2.组件功能更强大,并带有非常强大图形编辑功能,支持可视化的Applet,Swing,AWT等图形组件的开发。
   3.支持EJB3.0.
   4.支持UML2.0,并带有UML2.0模型编辑器。
   5.带有商业智能的报表项目和报表开发。
   6.支持新版的AOP插件用于可视化的开发AOP应用程序和调试AOP的应用程序。
   7.不像3.0一定需要JDK5.0的JRE,它只需要JDK1.4.1以上就可以了。
二、各插件介绍     
   1。JDT(Java Development Tools):Java设计工具,最新版3.1RC4,需求Eclipse3.1支持.
   2.PDE(Plugin Development Environment):插件设计环境,用于设计自定义插件,最新版3.1RC4,需求Eclipse3.1支持
   3.Platform: Eclipse的核心运行平台,目前最新版3.1.
   4. C/C++ IDE: 一看就知道,用于设计C/C++项目。 
   5.EMF(Eclipse Modeling Framework):Eclipse模型框架,目前最新版2.1.0,支持 Eclipse3.1及更新版
   6.GEF (Graphical Editor Framework):图形编辑框架,用于辅助图形设计,目前最新版 3.1RC4,支持Eclipse3.1. 
   7、UML2: UML编辑器,最新版1.1RC4,支持Eclipse3.1,需求EMF2.1RC1
   8.VE(Visual Editor):可视化图形编辑组件,用于提供AWT/SWT/Swing的图形编辑,最新版1.1M2,支持Eclipse3.1.
   9. J2EE Standard Tools:用于设计J2EE应用程序的插件,最新版1.0M5,支持Eclipse3.1.
   10.WST - Web Standards Tools: 用于设计Web应用程序的插件,最新版1.0M5,支持Eclipse3.1.
   11.Eclipse Test and Performance Tools Platform:用于调试,单元测试和测试项目的插件。
   12.Business Intelligence and Reporting Tools (BIRT):商业智能和商业报表开发插件,它包括Chart Engine(图形引擎),Report Framework(报表框架),
Runtime ENV(运行时环境)。
   13. AJDT - AspectJ Development Tools:用于开发AOP(面向方面编程)的开发ECLIPSE插件。
   14.AspectJ: 用于开发AOP的开发环境。
   15.CME - Concern Manipulation Environment:用于开发AOP的一组可视化工具插件。
三、下载和安装
   1.下载,从Eclipse的网站http://www.eclipse.org/downloads下载上述插件。并解压压缩。
   2.安装有多种方法,我推荐用Eclipse环境中Help菜单中的安装并更新。
     (1)将解压后的Eclipse-sdk-platform-win32-3.1目录挎贝一个你要做为安装的目录如C:\
     (2)将JDK1.4.1及以上的JDK的JRE挎贝到eclipse.exe所在的目录。
     (3)点击eclipse.exe运行,启动eclipse
     (4)我们发现非常快的速度就启动了eclipse3.1,莘进入它一个欢迎界面。
     (5)我们选择Help/SoftWare Update/Search and Installer菜单,选择。
     (6)依提示一个个完成安装。
四、总结
   Eclipse是一款免费的IDE,支持JAVA和C/C++开发,非常方便与快捷,有强大而又灵活扩展的插件功能,目前Borland也加入该社团的开发,因此我们相信eclipse将成为IDE 的饺饺者了。

posted @ 2005-08-12 00:55 风 阅读(511) | 评论 (0) | 编辑 收藏

JDK5.0文档,CHM版本的

http://www.matrix.org.cn/resource/upload/content/2005_07_30_191519_vorbArhhNZ.chm

posted @ 2005-08-11 23:58 风 阅读(1739) | 评论 (7) | 编辑 收藏

Jdk5.0新特性——Generic Types (泛型) (一)

     摘要: 本文摘自fasttalk的blog,觉得还可以加以收藏:JDK1.5 令我们期待很久,可是当他发布的时候却更换版本号为5.0。这说明Java已经有大幅度的变化。本文将讲解JDK5.0支持的新功能-----Java的泛型. 目录   1. 介绍2. 定义简单Java泛型3. 泛型通配符     3.1有限制的通配符4...  阅读全文

posted @ 2005-08-11 23:39 风 阅读(1425) | 评论 (2) | 编辑 收藏

JNI的调用的过程

 最近在公司里做了一个手机的项目,需要JAVA程序在发送短信的时候和第三方的短信服务器连接。短信接口是用C++写的。琢磨了三天,大致搞懂了JNI的主体部分。先将心得整理,希望各位朋友少走弯路。
    首先引用一篇文章,介绍一个简单的JNI的调用的过程。
    JAVA以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得很少,约束了它的功能。解决JAVA对本地操作的一种方法就是JNI。 
    JAVA通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,在UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使JAVA可以实现和本地机器的紧密联系,调用系统级的各接口方法。 
    简单介绍及应用如下: 
    一、JAVA中所需要做的工作 
        在JAVA程序中,首先需要在类中声明所调用的库名称,如下: 
  1.         static { 
  2.                  System.loadLibrary(“goodluck”); 
  3.                }
 
        在这里,库的扩展名字可以不用写出来,究竟是DLL还是SO,由系统自己判断。 
        还需要对将要调用的方法做本地声明,关键字为native。并且只需要声明,而不需要具 体实现。如下: 
        public native static void set(int i); 
        public native static int get(); 
        然后编译该JAVA程序文件,生成CLASS,再用JAVAH命令,JNI就会生成C/C++的头文件。 
        例如程序testdll.java,内容为: 
  1.         public class testdll 
  2.          { 
  3.            static 
  4.                  { 
  5.                   System.loadLibrary("goodluck"); 
  6.                  } 
  7.            public native static int get(); 
  8.            public native static void set(int i); 
  9.            public static void main(String[] args) 
  10.                 { 
  11.                   testdll test = new testdll(); 
  12.                   test.set(10); 
  13.                   System.out.println(test.get()); 
  14.                  } 
  15.            }
 
    用javac testdll.java编译它,会生成testdll.class。 
    再用javah testdll,则会在当前目录下生成testdll.h文件,这个文件需要被C/C++程序调用来生成所需的库文件。 
    二、C/C++中所需要做的工作 
    对于已生成的.h头文件,C/C++所需要做的,就是把它的各个方法具体的实现。然后编译连接成库文件即可。再把库文件拷贝到JAVA程序的路径下面,就可以用JAVA调用C/C++所实现的功能了。 
    接上例子。我们先看一下testdll.h文件的内容: 
    /* DO NOT EDIT THIS FILE - it is machine generated */ 
    #include <jni.h> 
    /* Header for class testdll */ 
    #ifndef _Included_testdll 
    #define _Included_testdll 
    #ifdef __cplusplus 
    extern "C" { 
    #endif 
     /* 
      * Class: testdll 
      * Method: get 
      * Signature: ()I 
      */ 
    JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass); 
      /* 
       * Class: testdll 
       * Method: set 
       * Signature: (I)V 
       */ 
    JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint); 
    #ifdef __cplusplus 
                } 
    #endif 
    #endif 
    在具体实现的时候,我们只关心两个函数原型 
    JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass); 和 
    JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint); 
    这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。而jint是以JNI为中介使JAVA的int类型与本地的int沟通的一种类型,我们可以视而不见,就当做int使用。函数的名称是JAVA_再加上java程序的package路径再加函数名组成的。参数中,我们也只需要关心在JAVA程序中存在的参数,至于JNIEnv*和jclass我们一般没有必要去碰它。 
    好,下面我们用testdll.cpp文件具体实现这两个函数: 
    #include "testdll.h" 
    int i = 0; 
    JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass) 
      { 
       return i; 
      } 
    JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint j) 
      { 
       i = j; 
      } 
    编译连接成库文件,本例是在WINDOWS下做的,生成的是DLL文件。并且名称要与JAVA中需要调用的一致,这里就是goodluck.dll 。把goodluck.dll拷贝到testdll.class的目录下,java testdll运行它,就可以观察到结果了。 
我的项目比较复杂,需要调用动态链接库,这样在JNI传送参数到C程序时,需要对参数进行处理转换。才可以被C程序识别。
大体程序如下:
  1. public class SendSMS {
  2. static
  3.     {
  4.       System.out.println(System.getProperty("java.library.path"));
  5.       System.loadLibrary("sms");
  6.     }
  7.     public native static int SmsInit();
  8.     public native static int SmsSend(byte[] mobileNo, byte[] smContent);
  9. }

在这里要注意的是,path里一定要包含类库的路径,否则在程序运行时会抛出异常:
java.lang.UnsatisfiedLinkError: no sms in java.library.path
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1491)
         at java.lang.Runtime.loadLibrary0(Runtime.java:788)
         at java.lang.System.loadLibrary(System.java:834)
         at com.mobilesoft.sms.mobilesoftinfo.SendSMS.<clinit>(SendSMS.java:14)
    at com.mobilesoft.sms.mobilesoftinfo.test.main(test.java:18)
Exception in thread "main"
指引的路径应该到.dll文件的上一级,如果指到.dll,则会报:
java.lang.UnsatisfiedLinkError: C:\sms.dll: Can't find dependent libraries
         at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1560)
         at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1485)
         at java.lang.Runtime.loadLibrary0(Runtime.java:788)
         at java.lang.System.loadLibrary(System.java:834)
         at com.mobilesoft.sms.mobilesoftinfo.SendSMS.<clinit>(SendSMS.java:14)
         at com.mobilesoft.sms.mobilesoftinfo.test.main(test.java:18)
Exception in thread "main"
通过编译,生成com_mobilesoft_sms_mobilesoftinfo_SendSMS.h头文件。(建议使用Jbuilder进行编译,操作比较简单!)这个头文件就是Java和C之间的纽带。要特别注意的是方法中传递的参数jbyteArray,这在接下来的过程中会重点介绍。
  1. /* DO NOT EDIT THIS FILE - it is machine generated */
  2. #include <jni.h>
  3. /* Header for class com_mobilesoft_sms_mobilesoftinfo_SendSMS */
  4. #ifndef _Included_com_mobilesoft_sms_mobilesoftinfo_SendSMS
  5. #define _Included_com_mobilesoft_sms_mobilesoftinfo_SendSMS
  6. #ifdef __cplusplus
  7. extern "C" {
  8. #endif
  9. /*
  10.  * Class:     com_mobilesoft_sms_mobilesoftinfo_SendSMS
  11.  * Method:    SmsInit
  12.  * Signature: ()I
  13.  */
  14. JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsInit
  15.   (JNIEnv *, jclass);
  16. /*
  17.  * Class:     com_mobilesoft_sms_mobilesoftinfo_SendSMS
  18.  * Method:    SmsSend
  19.  * Signature: ([B[B)I
  20.  */
  21. JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsSend
  22.   (JNIEnv *, jclass, jbyteArray, jbyteArray);
  23. #ifdef __cplusplus
  24. }
  25. #endif
  26. #endif

对于我要调用的C程序的动态链接库,C程序也要提供一个头文件,sms.h。这个文件将要调用的方法罗列了出来。
  1. /*
  2.  * SMS API 
  3.  * Author: yippit
  4.  * Date: 2004.6.8
  5.  */
  6. #ifndef MCS_SMS_H
  7. #define MCS_SMS_H
  8. #define DLLEXPORT __declspec(dllexport)
  9. /*sms storage*/
  10. #define SMS_SIM        0
  11. #define SMS_MT        1
  12. /*sms states*/
  13. #define SMS_UNREAD        0
  14. #define SMS_READ            1
  15. /*sms type*/
  16. #define SMS_NOPARSE        -1
  17. #define SMS_NORMAL        0
  18. #define SMS_FLASH            1
  19. #define SMS_MMSNOTI        2
  20. typedef struct tagSmsEntry {
  21.     int index;        /*index, start from 1*/
  22.     int status;        /*read, unread*/
  23.     int type;            /*-1-can't parser 0-normal, 1-flash, 2-mms*/
  24.     int storage;    /*SMS_SIM, SMS_MT*/
  25.     char date[24];
  26.     char number[32];
  27.     char text[144];
  28. } SmsEntry;
  29. DLLEXPORT int SmsInit(void);
  30. DLLEXPORT int SmsSend(char *phonenum, char *content);
  31. DLLEXPORT int SmsSetSCA(char *sca);
  32. DLLEXPORT int SmsGetSCA(char *sca);
  33. DLLEXPORT int SmsSetInd(int ind);
  34. DLLEXPORT int SmsGetInd(void);
  35. DLLEXPORT int SmsGetInfo(int storage, int *max, int *used);
  36. DLLEXPORT int SmsSaveFlash(int flag);
  37. DLLEXPORT int SmsRead(SmsEntry *entry, int storage, int index); 
  38. DLLEXPORT int SmsDelete(int storage, int index);
  39. DLLEXPORT int SmsModifyStatus(int storage, int index); /*unread -> read*/
  40. #endif

在有了这两个头文件之后,就可以进行C程序的编写了。也就是实现对JNI调用的两个方法。在网上的资料中,由于调用的方法实现的都比较简单,(大多是打印字符串等)所以避开了JNI中最麻烦的部分,也是最关键的部分,参数的传递。由于Java和C的编码是不同的,所以传递的参数是要进行再处理,否则C程序是会对参数在编译过程中提出警告,例如;warning C4024: 'SmsSend' : different types for formal and actual parameter 2等。
Sms.c的程序如下:
  1. #include "sms.h"
  2. #include "com_mobilesoft_sms_mobilesoftinfo_SendSMS.h"
  3. JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsInit(JNIEnv * env, jclass jobject)
  4. {
  5.     return SmsInit();
  6. }
  7. JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsSend(JNIEnv * env, jclass jobject, jbyteArray mobileno, jbyteArray smscontent)
  8. {
  9.     char * pSmscontent ;
  10.     //jsize theArrayLengthJ = (*env)->GetArrayLength(env,mobileno);
  11.     jbyte * arrayBody = (*env)->GetByteArrayElements(env,mobileno,0);
  12.     char * pMobileNo = (char *)arrayBody;
  13.     printf("[%s]\n ", pMobileNo);
  14.     //jsize size = (*env)->GetArrayLength(env,smscontent);
  15.     arrayBody = (*env)->GetByteArrayElements(env,smscontent,0);
  16.     pSmscontent = (char *)arrayBody;
  17.     printf("<%s>\n", pSmscontent);
  18.     return SmsSend(pMobileNo,pSmscontent); 
  19. }

对于C或C++,在程序上是会有稍微的不同,这可以由读者对其进行适当的修改。这里要注意的是GetArrayLength,GetByteArrayElements等这些JNI中已经包含的方法,这些方法是专门对转换参数类型而提供的。具体的方法有很多,在下一篇中会做专门的介绍。
在完成了上述的文件后,可以对sms.c进行编译,生成.dll文件(建议在release中编译,这样动态链接库的容积会比较小!)
完成.dll文件的编译后,就可以在Java中调用C程序中的方法了。例如文件test.java
  1. public class test {
  2.   public test() {
  3.   }
  4.   public static void main(String[] args) {
  5.     byte[] mobileno = {
  6.         0x31, 0x33, 0x36, 0x36, 0x31, 0x36, 0x33, 0x30, 0x36, 0x36, 0x37, 0x00};
  7.     String smscontentemp = "早上好";
  8.     byte[] temp = {0};
  9.    try {
  10.       byte[] smscontentdb = smscontentemp.getBytes("gbk");
  11.       byte[] smscontent = new byte[smscontentdb.length + temp.length];
  12.       System.arraycopy(smscontentdb, 0, smscontent, 0, smscontentdb.length);
  13.       System.arraycopy(temp, 0, smscontent, smscontentdb.length, temp.length);
  14.       SendSMS sendSMS = new SendSMS();
  15.       sendSMS.SmsInit();
  16.       if (sendSMS.SmsSend(mobileno, smscontent) >= 0) {
  17.         System.out.println("chenggong !");
  18.       }
  19.       else {
  20.         System.out.println("shibai !");
  21.       }
  22.     }catch (Exception ex) {}
  23.   }
  24. }

在这个文件中要注意的有一点,就是在传递字节数组到C程序中时,最后的结尾一定要以0结束。这是一个偷懒的做法,不过是个有效的做法。因为大多数情况下,接口是由第三方提供的。所以我们一般是不知道在C的方法里,具体是怎么处理参数的。而C又是要求数组是有长度。所以,在Java中,如果你不想写程序传数组的长度,那么在数组中以0结尾就是最方便的方法了。当然,如果有更好的方法也希望大家提出。
到这里,一个完整的Java通过JNI调用动态链接库的程序就完成了。实际上也不是很复杂。只要多注意一下细节,是很容易得出来的。

posted @ 2005-08-09 11:54 风 阅读(621) | 评论 (0) | 编辑 收藏

关于NDS在unix下的数据备份恢复技巧

在unix下备份或恢复数据命令使用方法:
1、备份
      ndsbackup cvf 文件名 o=组织名称
      其中o为非必须参数。如果异机备份需用R参数。
      如:ndsbackup cvRf 192.168.130.73  文件名 o=组织名称
      注意备份时会提示你输入用户名和口令,(如:admin.com /1)
2、恢复
     ndsbackup cvRf ip 文件名 
     回车后输入用户名及口令。
3、如果发生preferred-server无法访问,可以设置/etc/hosts文件 增加一个nds指定的server名即可。

posted @ 2005-08-09 11:44 风 阅读(318) | 评论 (0) | 编辑 收藏

关于ORA-01000: maximum open cursors exceeded的注意

很多朋友在Java开发中,使用Oracle数据库的时候,经常会碰到有ORA-01000: maximum open cursors exceeded.的错误。

实际上,这个错误的原因,主要还是代码问题引起的。
ora-01000: maximum open cursors exceeded.
表示已经达到一个进程打开的最大游标数。

这样的错误很容易出现在Java代码中的主要原因是:Java代码在执行conn.createStatement()和conn.prepareStatement()的时候,实际上都是相当与在数据库中打开了一个cursor。尤其是,如果你的createStatement和prepareStatement是在一个循环里面的话,就会非常容易出现这个问题。因为游标一直在不停的打开,而且没有关闭。

一般来说,我们在写Java代码的时候,createStatement和prepareStatement都应该要放在循环外面,而且使用了这些Statment后,及时关闭。最好是在执行了一次executeQuery、executeUpdate等之后,如果不需要使用结果集(ResultSet)的数据,就马上将Statment关闭。

对于出现ORA-01000错误这种情况,单纯的加大open_cursors并不是好办法,那只是治标不治本。实际上,代码中的隐患并没有解除。
而且,绝大部分情况下,open_cursors只需要设置一个比较小的值,就足够使用了,除非有非常特别的要求。

posted @ 2005-08-06 18:34 风 阅读(5032) | 评论 (6) | 编辑 收藏

仅列出标题
共20页: First 上一页 12 13 14 15 16 17 18 19 20 下一页 
 
Powered by:
BlogJava
Copyright © 风