Jak zaimportować klasę z domyślnego pakietu

98

Możliwy duplikat: Jak uzyskać dostęp do klas java w pakiecie domyślnym?


Używam Eclipse 3.5 i utworzyłem projekt z pewną strukturą pakietu wraz z pakietem domyślnym. Mam jedną klasę w domyślnym pakiecie - Calculations.java i chcę użyć tej klasy w dowolnym pakiecie (na przykład w com.company.calc). Kiedy próbuję użyć klasy, która jest w domyślnym pakiecie, wyświetla mi się błąd kompilatora. Nie jest w stanie rozpoznać klasy w domyślnym pakiecie. Gdzie jest problem?

Calculations.java - kod źródłowy

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

Nie mogę umieścić mojej klasy w żadnym innym pakiecie. Ta klasa ma kilka natywnych metod, które są zaimplementowane w Delphi. Jeśli umieszczę tę klasę w którymkolwiek z folderów, będę musiał wprowadzić zmiany w tej bibliotece DLL, których chcę uniknąć (naprawdę - nie mogę). Dlatego umieściłem moją klasę w domyślnym pakiecie.

Michał Ziober
źródło
1
Znalazłem ten link: stackoverflow.com/questions/283816/ ... po utworzeniu tego pytania.
Michał Ziober
Oczywiście ważnym elementem tego pytania jest to, że klasa i jej kod muszą znajdować się w domyślnym pakiecie . Jak na razie, każda odpowiedź inna niż użyć refleksji API (naprawdę, overkill czegoś to proste) to nie rozwiązanie. To zadziwiające, jak Java próbuje mieć swoje ciasto (odradza domyślny pakiet) i też je zjeść (sprawia, że ​​JNI jest tak zawiłe, że większość z nas korzysta z bibliotek DLL, które wymagają domyślnego pakietu).
ADTC,
Powód wydaje się historyczny, ale czasami gryzie. np. `` `` T.java: import static a.Foo. *; klasa T {Bar bar = nowy Bar (); } a / Foo.java: pakiet a; public class Foo {public static final class Bar {}} `` Powyższe kompiluje się dobrze, jednak jeśli Foo jest umieszczone w domyślnym pakiecie, nie działa. Dlatego nie mogę statycznie zaimportować Foo. *, Aby użyć skrótu Bar zamiast Foo.Bar.
Kedar Mhaswade,

Odpowiedzi:

87

Ze specyfikacji języka Java :

Importowanie typu z nienazwanego pakietu jest błędem czasu kompilacji.

Będziesz musiał uzyskać dostęp do klasy poprzez odbicie lub inną pośrednią metodę.

McDowell
źródło
1
Wow, naprawdę w ogóle nie znam javy. To była wielka pomoc. Chyba będę musiał przenieść moją klasę do paczki ...
anhoppe
46

Klasy w pakiecie domyślnym nie mogą być importowane przez klasy w pakietach. Dlatego nie powinieneś używać domyślnego pakietu.

matowe b
źródło
Powinna to być domyślna akceptowana odpowiedź, ponieważ jest najbardziej przydatna. Dziękuję Ci.
Neoraptor
8

Istnieje obejście problemu. Aby to osiągnąć, możesz użyć refleksji.

Najpierw utwórz interfejs dla swojej klasy docelowej Calculatons:

package mypackage;

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

}

Następnie spraw, aby klasa docelowa implementowała ten interfejs :

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

Na koniec użyj refleksji, aby utworzyć instancję Calculationsklasy i przypisać ją do zmiennej typu CalculationsInterface:

Class<?> calcClass = Class.forName("Calculations");
CalculationsInterface api = (CalculationsInterface)calcClass.newInstance();
// Use it 
double res = api.GetProgress(10);
Mohammad Banisaeid
źródło
5

Mogę dać ci tę sugestię, o ile wiem z mojego doświadczenia w programowaniu C i C ++. Kiedyś, gdy miałem ten sam problem, rozwiązałem go, zmieniając zapisaną strukturę dll w pliku „.C”, zmieniając nazwę pliku funkcja, która zaimplementowała natywną funkcjonalność JNI. na przykład, jeśli chcesz dodać swój program w pakiecie „com.mypackage”, zmieniasz prototyp funkcji / metody JNI implementującej plik „.C” na ten:

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
}

Ponieważ jestem nowy w Delphi, nie mogę Ci zagwarantować, ale powiem to na koniec (dowiedziałem się kilku rzeczy po googlowaniu o Delphi i JNI): Zapytaj tych ludzi (jeśli nie jesteś tym jedynym), którzy dostarczyli implementację natywnego Delphi kod, aby zmienić nazwy funkcji na takie:

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;

Ale ostatnia rada: chociaż Ty (jeśli jesteś programistą delphi) lub oni zmienisz prototypy tych funkcji i ponownie skompilujesz plik dll, po skompilowaniu pliku dll nie będziesz w stanie zmienić nazwy pakietu swojego Plik „Java” ponownie i ponownie. Ponieważ to ponownie będzie wymagało od Ciebie lub ich zmiany prototypów funkcji w delphi ze zmienionymi prefiksami (np. JAVA_yourpackage_with_underscores_for_inner_packages_JavaFileName_MethodName)

Myślę, że to rozwiązuje problem. Dzięki i pozdrawiam, Harshal Malshe

Harshal Malshe
źródło
To jest dobre dla każdego, kto próbuje używać bibliotek natywnych w swoich projektach.
Randnum
5

Z niektórych, gdzie znalazłem poniżej: -

W rzeczywistości możesz.

Używając reflections API, możesz uzyskać dostęp do dowolnej dotychczasowej klasy. Przynajmniej udało mi się :)

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

String fooReturned =
    (String) fooMethod.invoke(fooClass.newInstance(), "I did it");
Adnan Ghaffar
źródło
2
Wydaje się, że refleksja to jedyna droga. Mam bibliotekę JNI, która po prostu odmawia działania w jakimkolwiek pakiecie innym niż domyślny. Nie zbudowałem biblioteki DLL, więc nie mogę jej odbudować. Wszystko, co robię, musi być w Javie. Dziękuję za uratowanie dnia :)
ADTC
3

Niestety nie możesz zaimportować klasy, jeśli nie znajduje się ona w pakiecie. Jest to jeden z powodów, dla których jest to wysoce odradzane. To, co chciałbym, to coś w rodzaju proxy - umieść swój kod w pakiecie, którego każdy może użyć, ale jeśli naprawdę potrzebujesz czegoś w domyślnym pakiecie, uczyń tę bardzo prostą klasę, która przekazuje wywołania do klasy z prawdziwym kodem. Lub jeszcze prościej, po prostu przedłuż.

Dać przykład:

import my.packaged.DefaultClass;

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

public class DefaultClass {

   // Code here

}
Jon
źródło
1

Utwórz nowy pakiet A następnie przenieś klasy domyślnego pakietu do nowego pakietu i użyj tych klas

Khushboo Kashyap
źródło
Witamy w StackOverflow! Być może możesz dodać więcej szczegółów, aby lepiej wyjaśnić najważniejsze części Twojej odpowiedzi. Przeczytaj artykuł Jak napisać dobrą odpowiedź? po więcej informacji. Ponadto, gdy zdobędziesz więcej reputacji, będziesz mógł opublikować to jako komentarz, a nie odpowiedź, co byłoby bardziej odpowiednie.
Francesco B.
-1
  1. Utwórz nowy pakiet.
  2. Przenieś pliki z domyślnego pakietu do nowego.
Evgueni
źródło
-3
  1. Na przykład utwórz pakiet „główny” (folder) w swoim projekcie.

    źródło pakietu; (... / ścieżka_do_projektu / źródło /)

  2. Przenieś YourClass.class do folderu źródłowego. (... / ścieżka_do_projektu / źródło / TwojaKlasa.class)

  3. Importuj w ten sposób

    źródło importu.YourClass;

Andrey
źródło
1
zła odpowiedź, jeśli tego chce, potrzebuje jej domyślnie, a nie w jakimś niestandardowym pakiecie
Enerccio