Cách nhập một lớp từ gói mặc định


98

Có thể trùng lặp: Làm thế nào để truy cập các lớp java trong gói mặc định?


Tôi đang sử dụng Eclipse 3.5 và tôi đã tạo một dự án với một số cấu trúc gói cùng với gói mặc định. Tôi có một lớp trong gói mặc định - Calculations.java và tôi muốn sử dụng lớp đó trong bất kỳ gói nào (ví dụ: trong com.company.calc). Khi tôi cố gắng sử dụng lớp nằm trong gói mặc định, nó gây cho tôi lỗi trình biên dịch. Nó không thể nhận ra lớp trong gói mặc định. Vấn đề ở đâu?

Calculations.java - mã nguồn

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

Tôi không thể đặt lớp của mình trong bất kỳ gói nào khác. Lớp này có một số phương thức gốc được triển khai trong Delphi. Nếu tôi đặt lớp đó vào bất kỳ thư mục nào, tôi sẽ phải thực hiện các thay đổi đối với DLL đó mà tôi muốn tránh (thực sự - tôi không thể). Đó là lý do tại sao tôi đặt lớp của mình trong gói mặc định.


1
Tôi đã tìm thấy liên kết này: stackoverflow.com/questions/283816/… sau khi tạo câu hỏi này.
Michał Ziober


Tất nhiên, phần quan trọng của câu hỏi này là lớp mã của nó phải nằm trong gói mặc định . Tính đến bây giờ, bất kỳ câu trả lời nào khác ngoài việc sử dụng phản ánh API (thực sự, một overkill cho một cái gì đó đơn giản này)không một giải pháp. Thật đáng kinh ngạc khi Java cố gắng có chiếc bánh của nó (không khuyến khích gói mặc định) và ăn nó (làm cho JNI trở nên phức tạp, hầu hết chúng ta kết thúc bằng cách sử dụng các tệp DLL yêu cầu gói mặc định).
ADTC

Lý do có vẻ lịch sử, nhưng nó đôi khi cắn. ví dụ: `` `T.java: import static a.Foo. *; class T {Bar bar = new Bar (); } a / Foo.java: gói a; public class Foo {public static final class Bar {}} `` Ở trên biên dịch tốt, tuy nhiên, nếu Foo được đặt trong gói mặc định, nó không hoạt động. Vì vậy, tôi không thể nhập tĩnh Foo. * Để sử dụng Thanh viết tắt thay vì Foo.Bar.
Kedar Mhaswade

Câu trả lời:


87

Từ đặc tả ngôn ngữ Java :

Đây là một lỗi thời gian biên dịch để nhập một loại từ gói không tên.

Bạn sẽ phải truy cập lớp thông qua phản chiếu hoặc một số phương thức gián tiếp khác.


1
Wow, tôi thực sự không biết java cả. Đó là một sự giúp đỡ tuyệt vời. Đoán tôi sẽ phải di chuyển lớp học của tôi vào một gói ...
anhoppe

46

Các lớp trong gói mặc định không thể được nhập bởi các lớp trong gói. Đây là lý do tại sao bạn không nên sử dụng gói mặc định.


Đây phải là câu trả lời được chấp nhận mặc định, vì nó hữu ích nhất. Cảm ơn bạn.
Neoraptor

8

Có một giải pháp cho vấn đề của bạn. Bạn có thể sử dụng sự phản chiếu để đạt được nó.

Đầu tiên, hãy tạo một giao diện cho lớp mục tiêu của bạn Calculatons:

package mypackage;

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

}

Tiếp theo, làm cho lớp mục tiêu của bạn triển khai giao diện đó :

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

Cuối cùng, sử dụng phản chiếu để tạo một thể hiện của Calculationslớp và gán nó cho một biến kiểu CalculationsInterface:

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

5

Tôi có thể cung cấp cho bạn đề xuất này, Theo như kinh nghiệm lập trình C và C ++ của tôi, Một lần, khi tôi gặp vấn đề tương tự, tôi đã giải quyết nó bằng cách thay đổi cấu trúc dll được viết trong Tệp ".C" bằng cách thay đổi tên của chức năng đã triển khai chức năng gốc JNI. ví dụ: Nếu bạn muốn thêm chương trình của mình trong gói "com.mypackage", Bạn thay đổi nguyên mẫu của hàm / phương thức triển khai tệp ".C" của JNI thành sau:

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
}

Vì tôi là người mới sử dụng delphi, tôi không thể đảm bảo với bạn nhưng cuối cùng sẽ nói điều này, (tôi đã học được vài điều sau khi tìm kiếm thông tin về Delphi và JNI): Hãy hỏi những người (nếu bạn không phải là người) đã cung cấp triển khai Delphi cho bản gốc mã để thay đổi tên hàm thành một cái gì đó như sau:

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;

Tuy nhiên, một lời khuyên cuối cùng: Mặc dù bạn (Nếu bạn là lập trình viên delphi) hoặc họ sẽ thay đổi nguyên mẫu của các hàm này và biên dịch lại tệp dll, khi tệp dll được biên dịch, bạn sẽ không thể thay đổi tên gói của bạn. Tệp "Java" một lần nữa và một lần nữa. Bởi vì, điều này một lần nữa sẽ yêu cầu bạn hoặc họ thay đổi nguyên mẫu của các hàm trong delphi với các tiền tố đã thay đổi (ví dụ: JAVA_yourpackage_with_underscores_for_inner_packages_JavaFileName_MethodName)

Tôi nghĩ rằng điều này giải quyết được vấn đề. Trân trọng cảm ơn, Harshal Malshe


Điều này rất tốt cho bất kỳ ai đang cố gắng sử dụng Thư viện bản địa trong các dự án của họ.
Randnum

5

Từ một số nơi tôi tìm thấy bên dưới: -

Trong thực tế, bạn có thể.

Sử dụng API phản xạ, bạn có thể truy cập bất kỳ lớp nào cho đến nay. Ít nhất tôi đã có thể :)

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

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

2
Có vẻ như phản ánh là cách duy nhất để đi. Tôi có một thư viện JNI đơn giản từ chối hoạt động khi ở trong bất kỳ gói nào khác với gói mặc định. Tôi không xây dựng DLL nên tôi không thể xây dựng lại nó. Bất cứ điều gì tôi làm đều phải sử dụng Java. Cảm ơn bạn đã tiết kiệm trong ngày :)
ADTC

3

Thật không may, bạn không thể nhập một lớp mà không có trong một gói. Đây là một trong những lý do khiến nó rất không được khuyến khích. Những gì tôi sẽ thử là một loại proxy - đặt mã của bạn vào một gói mà mọi thứ đều có thể sử dụng, nhưng nếu bạn thực sự cần thứ gì đó trong gói mặc định, hãy tạo một lớp rất đơn giản để chuyển tiếp các cuộc gọi đến lớp bằng mã thực. Hoặc, thậm chí đơn giản hơn, chỉ cần mở rộng nó.

Để đưa ra một ví dụ:

import my.packaged.DefaultClass;

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

public class DefaultClass {

   // Code here

}

1

Tạo một gói mới Sau đó di chuyển các lớp của gói mặc định trong gói mới và sử dụng các lớp đó


Chào mừng bạn đến với StackOverflow! Có lẽ bạn có thể thêm chi tiết để giải thích rõ hơn những phần quan trọng nhất trong câu trả lời của bạn. Bạn đã đọc How do I write a good answer? để biết thêm thông tin. Ngoài ra, khi bạn nhận được nhiều danh tiếng hơn, bạn sẽ có thể đăng bài này dưới dạng nhận xét chứ không phải là câu trả lời, điều này sẽ phù hợp hơn.
Francesco B.

-1
  1. Tạo một gói mới.
  2. Di chuyển tệp của bạn từ gói mặc định sang gói mới.

-3
  1. Ví dụ: tạo gói (thư mục) "gốc" trong dự án của bạn.

    nguồn gói; (... / path_to_project / source /)

  2. Di chuyển YourClass.class vào một thư mục nguồn. (... / path_to_project / source / YourClass.class)

  3. Nhập như thế này

    nguồn nhập khẩu.YourClass;


1
câu trả lời không hay, nếu anh ấy muốn là cái này, anh ấy cần nó theo mặc định, không phải trong một số gói tùy chỉnh
Enerccio
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.