web-dev-qa-db-fra.com

Comment importer une classe d'un paquet par défaut

Dupliquer possible: Comment accéder aux classes Java dans le paquet par défaut?


J'utilise Eclipse 3.5 et j'ai créé un projet avec une structure de package avec le package par défaut. J'ai une classe dans le package par défaut - Calculations.Java et je souhaite utiliser cette classe dans l'un des packages (par exemple, dans com.company.calc). Quand j'essaie d'utiliser la classe qui est dans le paquet par défaut, cela me donne une erreur de compilation. Il n'est pas capable de reconnaître la classe dans le package par défaut. Où est le problème?

Calculations.Java - code source

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

Je ne peux pas mettre ma classe dans un autre paquet. Cette classe a des méthodes natives qui sont implémentées dans Delphi. Si je mets cette classe dans l’un des dossiers, je devrai apporter des modifications à celle-ci DLL que je veux éviter (vraiment - je ne peux pas)). C’est pourquoi je mets ma classe dans le paquet par défaut.

86
Michał Ziober

De la spécification de langage Java :

Il s'agit d'une erreur de compilation lors de l'importation d'un type à partir du package non nommé.

Vous devrez accéder au cours via une réflexion ou une autre méthode indirecte.

79
McDowell

Les classes du package par défaut ne peuvent pas être importées par les classes des packages. C'est pourquoi vous ne devez pas utiliser le package par défaut.

42
matt b

Il existe une solution de contournement pour votre problème. Vous pouvez utiliser la réflexion pour y parvenir.

Tout d'abord, créer une interface pour votre classe cible Calculatons:

package mypackage;

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

}

Ensuite, faites votre classe cible implémente cette interface:

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

Enfin, tilisez la réflexion pour créer une instance de Calculations class et l'assigner à une variable de type CalculationsInterface:

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

Je peux vous donner cette suggestion, autant que je sache de mon expérience en programmation C et C++, Une fois, lorsque j’avais le même problème, je l’ai résolu en modifiant la structure écrite de la DLL dans le fichier ".C" en modifiant le nom du fichier. fonction qui implémentait la fonctionnalité native JNI. Par exemple, si vous souhaitez ajouter votre programme dans le package "com.mypackage", vous modifiez le prototype du JNI implémentant la fonction/méthode du fichier ".C" à celle-ci:

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
}

Étant donné que je suis nouveau à Delphes, je ne peux pas vous garantir, mais je vais le dire enfin (j’ai appris peu de choses après avoir consulté Google sur Delphi et JNI): Demandez à ces personnes (si vous n’êtes pas celui-là) qui ont fourni l’implémentation Delphi de l’indigène code pour changer les noms de fonctions en quelque chose comme ceci:

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;

Mais un dernier conseil: bien que vous (si vous êtes le programmeur Delphi) ou que vous changiez les prototypes de ces fonctions et que vous recompiliez le fichier dll, une fois le fichier dll compilé, vous ne pourrez plus modifier le nom du paquet de votre fichier. Fichier "Java" encore et encore. Parce que cela nécessitera à nouveau que vous ou eux modifiiez les prototypes des fonctions de Delphi avec les préfixes modifiés (par exemple, Java_votrepackage_avec_underscores_pour_inner_packages_JavaFileName_MethodName)

Je pense que cela résout le problème. Merci et salutations, Harshal Malshe

4
Harshal Malshe

De certains où j'ai trouvé ci-dessous: -

En fait, vous pouvez.

En utilisant l’API de réflexion, vous pouvez accéder à n’importe quelle classe. Au moins j'ai pu :)

Class fooClass = Class.forName("FooBar");
Method fooMethod =
    fooClass.getMethod("fooMethod", new Class[] { String.class });

String fooReturned =
    (String) fooMethod.invoke(fooClass.newInstance(), "I did it");
4
Adnan Ghaffar

Malheureusement, vous ne pouvez pas importer une classe sans la placer dans un paquet. C'est l'une des raisons pour lesquelles il est fortement découragé. Ce que je voudrais essayer est une sorte de proxy - mettez votre code dans un paquet utilisable à tout moment, mais si vous avez vraiment besoin de quelque chose dans le paquet par défaut, faites-en une classe très simple qui transfère les appels à la classe avec le code réel. Ou, encore plus simple, il suffit de l’étendre.

Pour donner un exemple:

import my.packaged.DefaultClass;

public class MyDefaultClass extends DefaultClass {}
package my.packaged.DefaultClass;

public class DefaultClass {

   // Code here

}
1
Jon