关于无包名类的导入问题

MakeLove 2005-10-20 09:48:58
刚买了一只加密狗,厂商接供了访问该狗的java类,该类使用了JNI接口,故无法改变该类的类名和包名。该类没有包名,即默认无包名的类,必须放到程序运行的根目录下。现在我使用JDK1.5,我所有的类若使用厂商提供的类访问狗,也必须不能带包名,即放到程序运行的根目录下,无法通过import导入没有包名的类。难道在JAVA中一个类若没有包名,就不能被有包名的类导入或使用吗?为了使用没有包名的类,必须我其它的类也不能有包名?不这样做就通不过编译,这是怎么回事?
注:厂商提供的无包名类为public类型。
...全文
893 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
MakeLove 2005-10-23
  • 打赏
  • 举报
回复
gtlang78() 说的没错。
我回去试了一下,确实含有native接口的方法的类也能造型到接口。这个方法解决无名包的导入问题可能是最简单的解决办法了吧。

谢谢指点。
gtlang78 2005-10-23
  • 打赏
  • 举报
回复
//Dog.java
public class Dog implements yourpackage.IDog {
//这两个常量移到IDog接口里去了
//public static final int TEST1 = 100;
//public static final String TEST2 = "Hello";

static {
try
{
System.loadLibrary("dog");
}
catch (Exception e)
{
e.printStackTrace();
}
}


//native 方法也可以实现接口
public native void method1();
public native int method2();

//底下这些字段和构造方法是在dll生成之后新加的,并没有影响到native方法的调用
/////////////////////////////////////////
private int a;
private String b;

public Dog()
{
System.out.println("Create new Dog");
a = 1;
b = "test";
System.out.println("TEST1=" + TEST1);
System.out.println("TEST2=" + TEST2);
}
}

//IDog.java
package yourpackage;

public interface IDog {
public static final int TEST1 = 100;
public static final String TEST2 = "Hello";

public void method1();
public int method2();
}

//DogFactory.java
package yourpackage;

public class DogFactory {
private static IDog dog = null;

public static IDog createDog() {
if (dog == null) {
try {
dog = (IDog)Class.forName("Dog").newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
return dog;
}
}

//TestDog.java
package yourpackage;

public class TestDog
{
public static void main(String[] args)
{
IDog dog = DogFactory.createDog();
dog.method1();
System.out.println(dog.method2());
}
}

/* Dog.h */
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Dog */

#ifndef _Included_Dog
#define _Included_Dog
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Dog
* Method: method1
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_Dog_method1
(JNIEnv *, jobject);

/*
* Class: Dog
* Method: method2
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_Dog_method2
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif


/* Dog.c */
#include "jni.h"
#include "Dog.h"

JNIEXPORT void JNICALL Java_Dog_method1(JNIEnv* env, jobject obj)
{
printf("method1 invoked\n");
}
JNIEXPORT jint JNICALL Java_Dog_method2(JNIEnv* env, jobject obj)
{
printf("method2 invoked\n");

return 999;
}

gtlang78 2005-10-23
  • 打赏
  • 举报
回复
楼主,你真的试过了么?解决问题不能光靠想象。
用native方法实现接口是可以的, 这我两年前就试过了,刚才又试了一下,结果还是一样。

>>>"这是因为一个含有JNI调用的类,其所有方法类型包括非私有字段变量都是不能改变的。"
没有这回事。只要这个类的包名、类名以及native方法的声明没有变化,对应的dll就不需要重新编译,其他的非native方法和字段可以随便改,这个我也试过的。

至于那些public类型常量字段,完全可以从Dog类里面删掉,提到IDog接口里面,不会影响到Dog类的编译,不信的话你可以自己试一下。

使用这种方法还有一个好处,就是如果你的IDE支持重构的话,就可以使用Extract Interface 功能自动从Dog类生成IDog接口,连复制修改代码的手续都省了。不过楼主你既然不怕麻烦,自己已经用反射的方法实现了,那就算了。

加密狗的厂商不愿意给你加包名就是因为包名改了,对应的.h文件需要重新生成,对应的.c文件里的所有函数名也都需要改,然后还要重新编译dll。而且为了支持其他不想加包名的客户,原来的java文件、.h文件和.c文件都还要保留,这样就需要维护两套源程序。要是我大概也会觉得麻烦, 不过那也没办法,谁让他们早点没考虑到这个问题呢。


后面是实验用到的所有文件,楼主你要是有兴趣就自己试一下,没兴趣的话就算了,反正不管简单办法还是苯办法,达到目的就行。
MakeLove 2005-10-22
  • 打赏
  • 举报
回复
public class Dog implements yourpackage.IDog
dog = (IDog)Class.forName("Dog").newInstance();
上面这两句是通不过的。
因为厂商的Dog类中的所有方法是native类型,还包括许多public类型常量字段,不可以映射到非native的接口。
MakeLove 2005-10-22
  • 打赏
  • 举报
回复
想法挺好,不过会产生运行时的异常或是通不过编译。因为厂商的类中的方法都是被声明为public native int 型的JNI调用,根本无法被提炼成接口,即就算能提炼成接口也会使Dog类在通过JNI接口访问DLL库时出现“不安全链接”的运行时异常。这是因为一个含有JNI调用的类,其所有方法类型包括非私有字段变量都是不能改变的,把一个native方法改成非native方法是无法正常运行的,估计编译都通不过。

我花了一个多小时写了个有包名的包装类,该类用java反射机制来调用厂商的无包名类,解决了无法调用厂商无包名类的问题。看来只有这种笨办法才能解决此问题了

真怀疑厂商做的java加密狗调用类是否被人做为商业用途用过?为什么这么明显又容易解决的问题都没解决。看来java项目中使用加密狗的可能很少,要不就是他的产品销量太小。
gtlang78 2005-10-21
  • 打赏
  • 举报
回复
干脆把他的类反编译,自己加上包名!
MakeLove 2005-10-21
  • 打赏
  • 举报
回复
只有JAVA反射机制可以解决此问题,但这样使用类实在太不方便了。
厂商说我如果订购500个以上加密狗上的话,可以给我重新编译一个类,加上包名。
退货,又花钱又麻费,没准还退不掉,怎么也是我赔本买卖。
MakeLove 2005-10-21
  • 打赏
  • 举报
回复
只有JAVA反射机制可以解决此问题,但这样使用类实在太不方便了。
厂商说我如果订购500个以加密狗上的话,可以经我重新编译一个类,加上包名。太不象话了
MakeLove 2005-10-21
  • 打赏
  • 举报
回复
因为有JNI调用,所以厂商的类不能改写。虽然厂商的类可以继承,但继承时也不能加包名,否则也无法通过编译。这意味我的程序只要有一处使用了厂商的类,所有其它的类都不能带包名,直郁闷,哪位高手知道解决办法?
zgysc 2005-10-21
  • 打赏
  • 举报
回复
up! tomcat5也是有这毛病,要想引入javabean,必须编译的类要有包名
gtlang78 2005-10-21
  • 打赏
  • 举报
回复
有一个地方写错了
public class interface IDog -> public interface IDog
gtlang78 2005-10-21
  • 打赏
  • 举报
回复
你有他的源代码? 那就好办了。方法就是把他的类中你要用到的方法抽出来自己写一个接口,然后修改他的类实现这个接口,你的程序中只通过接口来访问。就像下面这样:

//Dog.java
public class Dog implements yourpackage.IDog {
public void method1() {
...
}

public int method2() {
...
return xxx;
}

...
}


//IDog.java
package yourpackage;

public class interface IDog {
public void method1();
public int method2();
...
}


//DogFactory.java
package yourpackage;

public class DogFactory {
private static IDog dog = null;

public static IDog createDog() {
if (dog == null) {
try {
dog = (IDog)Class.forName("Dog").newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
return dog;
}
}

其它地方用的时候调用 DogFactory.createDog()来得到IDog的实例, 调用相应的方法。
凋零的老树 2005-10-21
  • 打赏
  • 举报
回复
可以不可以把这个类添加到jar中去了?
凋零的老树 2005-10-21
  • 打赏
  • 举报
回复
这个问题有点意思

首先是厂家实在是狗屁

然后怎么解决,呵呵,我也不知道了
MakeLove 2005-10-21
  • 打赏
  • 举报
回复
楼上的你试过吗?理论上我也原来也是像你这样想的,事实上根本行不通,编译都通不过。不信你自已去试一试。
fankobe 2005-10-21
  • 打赏
  • 举报
回复
其实不是这样的,就算一个类没有包名,它还是可以被访问到,只要它可以被编译器找到。而且你的类还是public的,就更好说了。

难道在JAVA中一个类若没有包名,就不能被有包名的类导入或使用吗?为了使用没有包名的类,必须我其它的类也不能有包名?

如果你的类A是package包,而你的类B是默认包的(就是没有包名的),那你就不能通过import包名来用你的类B,但是因为你的B是默认包的,所有你就把把它放到默认包中就可以了,编译器就会找到,因为,如果你的文件没有通过import导入包,编译器就会在默认包中寻找你需要的类。

呵呵,到这里你知道其实你不用必须把你的类B和A放到同一个文件夹啦。

默认包的位置就是你的classpath的位置。
如果你想把类B放在C:/dog这个文件夹中,类A不在C:/dog中,也想顺利访问到类B,那么你就把C:/dog放到你的classpath中,这样C:/dog就会成为默认包的位置了。
MakeLove 2005-10-21
  • 打赏
  • 举报
回复
他的JAVA类提供了源代码,但是相关的JNI调用使用的DLL库没有源代码,反编译重写一遍根本不现实。
低调的小青蛙 2005-10-20
  • 打赏
  • 举报
回复
我也试过了,这的确是个问题。

这样算得上是使用到了:
Class.forName("NoPackage").newInstance();

不过这样也很麻烦的


这个厂商也太不地道了,连个包名都没有,何况包名还可以顺便给他自己打广告。你应该找厂商更改,否则你就退货。你也可以全部翻编译,然后移动到一个包下面去。
网络精灵 2005-10-20
  • 打赏
  • 举报
回复
把厂商的类写一下,加上包名。
MakeLove 2005-10-20
  • 打赏
  • 举报
回复
使用 import JavaClass;
这样的语法根本通不过编译。
不使用import的话就必须放到跟JavaClass类同样的根目录下,变成无名包的类。
所有可能的方法我都试过了。
加载更多回复(3)

62,629

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧