【问题标题】:How to import a class from default package如何从默认包中导入类
【发布时间】:2011-01-12 16:31:00
【问题描述】:

可能重复:How to access java-classes in the default-package?


我正在使用 Eclipse 3.5,并且我创建了一个带有一些包结构以及默认包的项目。我在默认包中有一个类 - Calculations.java,我想在任何包中使用该类(例如在com.company.calc 中)。当我尝试使用默认包中的类时,它给了我一个编译器错误。它无法识别默认包中的类。问题出在哪里?

Calculations.java - 源代码

public class Calculations {
    native public int Calculate(int contextId);
    native public double GetProgress(int contextId);
    static  {
        System.loadLibrary("Calc");
    }
}

我不能将我的课程放在任何其他包中。这个类有一些在 Delphi 中实现的本地方法。如果我将该类放在任何文件夹中,我将不得不更改我想要避免的那个 DLL(真的 - 我不能)。这就是为什么我把我的类放在默认包中。

【问题讨论】:

  • 我在创建这个问题后找到了这个链接:stackoverflow.com/questions/283816/…
  • 当然,这个问题的重点是类它的代码必须在默认包中。到目前为止,除了使用反射 API (对于这么简单的事情来说,真的有点过头了) 之外的任何答案都不是 解决方案。令人难以置信的是,Java 是如何试图获得它的蛋糕(不鼓励默认包)并吃掉它(让 JNI 如此复杂,我们大多数人最终都使用需要默认包的 DLL)。
  • 原因似乎是历史性的,但有时确实会咬人。例如``` T.java: 导入静态 a.Foo.*;类 T { 酒吧酒吧 = 新酒吧(); } a/Foo.java: 包 a; public class Foo { public static final class Bar { } } ``` 上面编译得很好,但是,如果 Foo 放在默认包中,它就不起作用。因此,我不能静态导入 Foo.* 以便使用简写 Bar 而不是 Foo.Bar。

标签: java java-native-interface native-methods default-package


【解决方案1】:

您的问题有一个解决方法。您可以使用反射来实现它。

首先,为您的目标类Calculatons创建一个接口

package mypackage;

public interface CalculationsInterface {  
    int Calculate(int contextId);  
    double GetProgress(int contextId);  

}

接下来,让您的目标类实现该接口

public class Calculations implements mypackage.CalculationsInterface {
    @Override
    native public int Calculate(int contextId);
    @Override
    native public double GetProgress(int contextId);
    static  {
        System.loadLibrary("Calc");
    }
}

最后,使用反射创建Calculations类的实例并将其分配给CalculationsInterface类型的变量:

Class<?> calcClass = Class.forName("Calculations");
CalculationsInterface api = (CalculationsInterface)calcClass.newInstance();
// Use it 
double res = api.GetProgress(10);

【讨论】:

    【解决方案2】:

    创建一个新包 然后将默认包的类移动到新包中并使用这些类

    【讨论】:

    • 欢迎来到 StackOverflow!也许您可以添加更多详细信息,以更好地解释答案中最重要的部分。阅读How do I write a good answer? 了解更多信息。此外,一旦您获得更多声誉,您就可以将其发布为评论而不是答案,这会更合适。
    【解决方案3】:
    1. 例如,在您的项目中创建“根”包(文件夹)。

      包源; (.../path_to_project/source/)

    2. 将 YourClass.class 移动到源文件夹中。 (.../path_to_project/source/YourClass.class)

    3. 像这样导入

      导入源.YourClass;

    【讨论】:

    • 不好的答案,如果他想要这个,他默认需要它,而不是在某些自定义包中
    【解决方案4】:

    从我在下面找到的一些地方:-

    事实上,你可以。

    到目前为止,您可以使用反射 API 访问任何类。至少我能够:)

    Class fooClass = Class.forName("FooBar");
    Method fooMethod =
        fooClass.getMethod("fooMethod", new Class[] { String.class });
    
    String fooReturned =
        (String) fooMethod.invoke(fooClass.newInstance(), "I did it");
    

    【讨论】:

    • 似乎反射是唯一的出路。我有一个 JNI 库,它在默认包以外的任何包中都拒绝工作。我没有构建 DLL,所以我无法重建它。我所做的任何事情都必须使用 Java。谢谢你拯救了一天:)
    【解决方案5】:

    不幸的是,如果一个类没有放在包中,您就无法导入它。这也是它非常不受欢迎的原因之一。我会尝试一种代理——将你的代码放入一个任何东西都可以使用的包中,但是如果你真的需要默认包中的某些东西,那就把它变成一个非常简单的类,它将调用转发到带有真实代码的类。或者,更简单,只是扩展它。

    举个例子:

    import my.packaged.DefaultClass;
    
    public class MyDefaultClass extends DefaultClass {}
    package my.packaged.DefaultClass;
    
    public class DefaultClass {
    
       // Code here
    
    }

    【讨论】:

      【解决方案6】:
      1. 创建一个新包。
      2. 将文件从默认包移至新包。

      【讨论】:

        【解决方案7】:

        我可以给你这个建议, 据我的 C 和 C++ 编程经验所知, 有一次,当我遇到同样的问题时,我通过更改实现 JNI 本机功能的函数的名称来更改“.C”文件中的 dll 编写结构来解决它。 例如,如果您想在包“com.mypackage”中添加您的程序, 您将实现“.C”文件功能/方法的 JNI 的原型更改为:

        JNIEXPORT jint JNICALL
        Java_com_mypackage_Calculations_Calculate(JNIEnv *env, jobject obj, jint contextId)
        {
           //code goes here
        }
        
        JNIEXPORT jdouble JNICALL
        Java_com_mypackage_Calculations_GetProgress(JNIEnv *env, jobject obj, jint contextId)
        {
          //code goes here
        }
        

        由于我是 delphi 新手,我不能向你保证,但最后还是要说一下,(我在谷歌上搜索过 Delphi 和 JNI 后学到了一些东西): 询问那些提供本机代码的 Delphi 实现的人(如果你不是那个人)将函数名称更改为如下内容:

        function Java_com_mypackage_Calculations_Calculate(PEnv: PJNIEnv; Obj: JObject; contextId: JInt):JInt; {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
        var
        //Any variables you might be interested in
        begin
          //Some code goes here
        end;
        
        
        
        function Java_com_mypackage_Calculations_GetProgress(PEnv: PJNIEnv; Obj: JObject; contextId: JInt):JDouble; {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
        var
        //Any variables you might be interested in
        begin
        //Some code goes here
        end;
        

        但是,最后的建议:虽然你(如果你是 delphi 程序员)或者他们会改变这些函数的原型并重新编译 dll 文件,但是一旦编译了 dll 文件,你将无法更改包您的“Java”文件的名称一次又一次。 因为,这将再次要求您或他们使用更改的前缀更改 delphi 中函数的原型(例如 JAVA_yourpackage_with_underscores_for_inner_packages_JavaFileName_MethodName)

        我认为这可以解决问题。 感谢致敬, 哈沙尔·马尔谢

        【讨论】:

        • 这对任何试图在项目中使用原生库的人都有好处。
        【解决方案8】:

        来自Java language spec

        从未命名的包中导入类型是编译时错误。

        您必须通过反射或其他间接方法访问该类。

        【讨论】:

        • 哇,我真的一点儿不懂java。这是一个很大的帮助。我想我得把我的班级搬进一个包里……
        【解决方案9】:

        默认包中的类不能被包中的类导入。这就是为什么你不应该使用默认包的原因。

        【讨论】:

        • 这应该是默认接受的答案,因为它是最有用的。谢谢。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-26
        • 2015-11-14
        • 2016-11-06
        • 2020-03-07
        相关资源
        最近更新 更多