วิธีการนำเข้าคลาสจากแพ็คเกจเริ่มต้น


98

Possible Duplicate: จะเข้าถึง java-class ใน 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");
    }
}

ฉันไม่สามารถรวมชั้นเรียนไว้ในแพ็คเกจอื่นได้ คลาสนี้มีวิธีดั้งเดิมบางอย่างที่นำมาใช้ในเดลฟี ถ้าฉันใส่คลาสนั้นในโฟลเดอร์ใด ๆ ฉันจะต้องทำการเปลี่ยนแปลงกับ DLL ที่ฉันต้องการหลีกเลี่ยง (จริงๆ - ฉันทำไม่ได้) นั่นเป็นเหตุผลที่ฉันจัดชั้นเรียนไว้ในแพ็คเกจเริ่มต้น


1
ฉันพบลิงค์นี้: stackoverflow.com/questions/283816/…หลังจากสร้างคำถามนี้
Michał Ziober


แน่นอนบิตที่สำคัญของคำถามนี้ก็คือว่าชั้นและรหัสของมีอยู่ในแพคเกจเริ่มต้น ณ ตอนนี้คำตอบอื่น ๆ มากกว่าที่จะสะท้อนการใช้ API (จริงๆเป็น overkill หาสิ่งที่ง่ายนี้)คือไม่ได้แก้ปัญหา เป็นเรื่องที่เหลือเชื่อว่า Java พยายามจะมีเค้กอย่างไร (กีดกันแพ็คเกจเริ่มต้น) และกินมันด้วย (ทำให้ JNI ซับซ้อนมากพวกเราส่วนใหญ่จะใช้ DLL ที่ต้องใช้แพ็คเกจเริ่มต้น)
ADTC

เหตุผลดูเหมือนเป็นประวัติศาสตร์ แต่บางครั้งก็กัด เช่น `` T.java: import static a.Foo. *; คลาส T {Bar bar = new Bar (); } a / Foo.java: แพ็คเกจ a; คลาสสาธารณะ Foo {public static final class Bar {}} `` ข้างต้นคอมไพล์ได้ดีอย่างไรก็ตามหาก Foo อยู่ในแพ็กเกจเริ่มต้นจะไม่ทำงาน ดังนั้นฉันจึงไม่สามารถนำเข้า Foo ได้แบบคงที่ * เพื่อใช้ชวเลขบาร์แทน Foo.Bar
Kedar Mhaswade

คำตอบ:


87

จากข้อมูลจำเพาะภาษา Java :

เป็นข้อผิดพลาดเวลาคอมไพล์ในการนำเข้าชนิดจากแพ็คเกจที่ไม่มีชื่อ

คุณจะต้องเข้าถึงชั้นเรียนผ่านการสะท้อนกลับหรือวิธีทางอ้อมอื่น ๆ


1
ว้าวฉันไม่รู้จัก java เลยจริงๆ นั่นเป็นความช่วยเหลือที่ดี เดาว่าฉันจะต้องย้ายชั้นเรียนเป็นแพ็คเกจ ...
anhoppe

46

ไม่สามารถนำเข้าคลาสในแพ็กเกจเริ่มต้นโดยคลาสในแพ็กเกจ นี่คือเหตุผลที่คุณไม่ควรใช้แพ็คเกจเริ่มต้น


นี่ควรเป็นคำตอบที่ยอมรับโดยค่าเริ่มต้นเนื่องจากมีประโยชน์มากที่สุด ขอบคุณ.
Neoraptor

8

มีวิธีแก้ปัญหาสำหรับปัญหาของคุณ คุณสามารถใช้การสะท้อนเพื่อให้บรรลุได้

ขั้นแรกสร้างอินเทอร์เฟซสำหรับคลาสเป้าหมายของคุณ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);

5

ฉันสามารถให้คำแนะนำนี้แก่คุณได้เท่าที่ทราบจากประสบการณ์การเขียนโปรแกรม C และ C ++ ของฉันครั้งหนึ่งเมื่อฉันมีปัญหาเดียวกันฉันแก้ไขได้โดยการเปลี่ยนโครงสร้างที่เขียน dll ในไฟล์ ".C" โดยเปลี่ยนชื่อของไฟล์ ฟังก์ชันที่ใช้ฟังก์ชันดั้งเดิมของ JNI ตัวอย่างเช่นหากคุณต้องการเพิ่มโปรแกรมของคุณในแพ็กเกจ "com.mypackage" คุณจะเปลี่ยนต้นแบบของฟังก์ชัน / วิธีการของไฟล์ JNI ที่ใช้ ".C" เป็นไฟล์นี้:

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
}

เนื่องจากฉันยังใหม่กับเดลฟีฉันจึงไม่สามารถรับประกันคุณได้ แต่จะพูดอย่างนี้ในที่สุด (ฉันได้เรียนรู้บางสิ่งหลังจาก googling เกี่ยวกับ 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;

แต่คำแนะนำสุดท้าย: แม้ว่าคุณ (หากคุณเป็นโปรแกรมเมอร์เดลฟี) หรือพวกเขาจะเปลี่ยนต้นแบบของฟังก์ชันเหล่านี้และคอมไพล์ไฟล์ dll ใหม่เมื่อรวบรวมไฟล์ dll แล้วคุณจะไม่สามารถเปลี่ยนชื่อแพ็กเกจของคุณได้ ไฟล์ "Java" อีกครั้งและอีกครั้ง เนื่องจากสิ่งนี้จะทำให้คุณหรือพวกเขาต้องเปลี่ยนต้นแบบของฟังก์ชันในเดลฟีอีกครั้งด้วยคำนำหน้าที่เปลี่ยนไป (เช่น JAVA_yourpackage_with_underscores_for_inner_packages_JavaFileName_MethodName)

ฉันคิดว่าวิธีนี้ช่วยแก้ปัญหาได้ ขอขอบคุณและขอแสดงความนับถือ Harshal Malshe


เหมาะสำหรับทุกคนที่พยายามใช้ Native Libraries ในโครงการของตน
Randnum

5

จากที่ฉันพบด้านล่าง: -

ในความเป็นจริงคุณสามารถ

การใช้ reflections 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");

2
ดูเหมือนการสะท้อนเป็นหนทางเดียวที่จะไป ฉันมีไลบรารี JNI ที่ปฏิเสธที่จะทำงานเมื่ออยู่ในแพ็คเกจอื่นนอกเหนือจากค่าเริ่มต้น ฉันไม่ได้สร้าง DLL ดังนั้นฉันจึงไม่สามารถสร้างใหม่ได้ ทุกสิ่งที่ฉันทำต้องเป็นภาษา Java ขอบคุณสำหรับการบันทึกประจำวัน :)
ADTC

3

ขออภัยคุณไม่สามารถนำเข้าชั้นเรียนได้หากไม่อยู่ในแพ็คเกจ นี่เป็นสาเหตุหนึ่งที่ทำให้ท้อใจมาก สิ่งที่ฉันจะลองคือประเภทของพร็อกซี - ใส่รหัสของคุณลงในแพ็คเกจที่ทุกอย่างสามารถใช้ได้ แต่ถ้าคุณต้องการบางอย่างในแพ็คเกจเริ่มต้นให้สร้างคลาสที่เรียบง่ายมากซึ่งส่งต่อการโทรไปยังคลาสด้วยรหัสจริง หรือง่ายกว่าก็แค่ขยาย

เพื่อเป็นตัวอย่าง:

import my.packaged.DefaultClass;

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

public class DefaultClass {

   // Code here

}

1

สร้างแพ็คเกจใหม่จากนั้นย้ายคลาสของแพ็กเกจเริ่มต้นในแพ็กเกจใหม่และใช้คลาสเหล่านั้น


ยินดีต้อนรับสู่ StackOverflow! บางทีคุณอาจเพิ่มรายละเอียดเพิ่มเติมเพื่ออธิบายส่วนที่สำคัญที่สุดของคำตอบของคุณให้ดีขึ้น อ่านHow do I write a good answer? สำหรับข้อมูลเพิ่มเติม. นอกจากนี้เมื่อคุณมีชื่อเสียงมากขึ้นคุณจะสามารถโพสต์สิ่งนี้เป็นความคิดเห็นแทนที่จะเป็นคำตอบซึ่งจะเหมาะสมกว่า
Francesco B.

-1
  1. สร้างแพ็คเกจใหม่
  2. ย้ายไฟล์ของคุณจากแพ็คเกจเริ่มต้นไปยังแพ็กเกจใหม่

-3
  1. สร้างแพ็คเกจ "root" (โฟลเดอร์) ในโปรเจ็กต์ของคุณเช่น

    แหล่งบรรจุภัณฑ์ (... / path_to_project / ที่มา /)

  2. ย้าย YourClass.class ไปไว้ในโฟลเดอร์ต้นทาง (... / path_to_project / source / YourClass.class)

  3. นำเข้าแบบนี้

    แหล่งนำเข้า YourClass;


1
คำตอบที่ไม่ดีถ้าเขาต้องการสิ่งนี้เขาต้องการมันเป็นค่าเริ่มต้นไม่ใช่ในแพ็คเกจที่กำหนดเอง
Enerccio
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.