Java 101: חבילות מארגנות שיעורים וממשקים

למה להמציא את הגלגל מחדש? קלישאה זו חלה על פיתוח תוכנה, כאשר מפתחים מסוימים משכתבים לעתים קרובות את אותו קוד עבור תוכניות שונות. שני חסרונות בגישה זו הם:

  1. זה מבזבז זמן
  2. זה מציג את הפוטנציאל לבאגים בקוד באגים

כחלופה לשכתוב אותו קוד, סביבות פיתוח תוכנה רבות מספקות כלי ספריה המארגן קוד בשימוש תכוף. לאחר שמפתחים מסיימים ניפוי באגים באיזה קוד רב פעמי, הם משתמשים בכלי לאחסון קוד זה בספריה - אחד או יותר קבצים המכילים קוד בשימוש תכוף לשימוש בתוכניות שונות. במהלך בניית התוכנית, המהדר או כלי הספרייה ניגש לספרייה כדי לחבר את הקוד המוזכר בספריה לתוכנית.

ספריות הן בסיסיות בג'אווה. הם מאפשרים, בין השאר, למטען הכיתות של ה- JVM לאתר קבצי כיתות. (אני אבדוק מעמיסי כיתות במאמר עתידי.) מסיבה זו, ספריות ג'אווה ידועות בכינוין ספריות כיתות. עם זאת, Java מתייחסת לספריות כיתות כחבילות.

מאמר זה בוחן חבילות; אני מראה לך כיצד ליצור חבילות של מחלקות וממשקים, כיצד לייבא (כלומר, להכניס לתוכנית) מחלקות וממשקים ארוזים, כיצד להעביר חבילות על הכונן הקשיח, וכיצד להשתמש בקבצי jar כדי להכיל חבילות.

הערה
ניסוי החבילה היחידה של מאמר זה הוא ספציפי ל- Windows. אתה אמור להיות מסוגל להקצות ניסוי זה בקלות לפלטפורמות שאינן Windows.

מהן חבילות?

חבילה היא אוסף של כיתות וממשקים. לכל חבילה שם משלה והיא מארגנת את המחלקות והממשקים ברמה העליונה (כלומר, לא מקושרת) למרחב שמות נפרד , או לאוסף שמות. למרות שאותם מחלקות וממשקים אינם יכולים להופיע באותה חבילה, הם יכולים להופיע בחבילות שונות מכיוון שמרחב שמות נפרד מקצה לכל חבילה.

מנקודת מבט של יישום, השוואת חבילה לספריה מוכיחה את עצמה כמועילה, כמו גם השוואת מחלקות החבילה והממשקים עם קבצי הכיתות של הספריה. זכור גישות אחרות - כגון שימוש במאגרי מידע - ליישום חבילות, לכן אל תתרגל תמיד להשוות חבילות לספריות. אך מכיוון ש- JVM רבים משתמשים בספריות ליישום חבילות, מאמר זה משווה חבילות לספריות. ה- Java 2 SDK מארגן את אוסף המחלקות והממשקים העצומים שלו להיררכיית עץ דמוית חבילות בתוך חבילות, המקבילה לספריות בספריות. היררכיה זו מאפשרת ל- Sun Microsystems להפיץ בקלות (ואתם לעבוד איתם בקלות) את אותם מחלקות וממשקים. דוגמאות לחבילות Java כוללות:

  • java.lang:אוסף של כיתות הקשורות לשפה, כגון Objectו String, המאורגן javaשל החבילה langמחבילת משנה
  • java.lang.ref:אוסף של שיעורים הקשורים לשפת התייחסות, כגון SoftReferenceו ReferenceQueue, המאורגן refתת-מחבילת המשנה של javaשל החבילה langמחבילת משנה
  • javax.swing:אוסף של מחלקות רכיבים הקשורות לסווינג, כגון JButtonוממשקים, כגון ButtonModel, המאורגנות javaxבחבילה swingהמשנה של החבילה

תווים תקופתיים מפרידים בין שמות חבילות. לדוגמה, ב- javax.swing, תו נקודה מפריד בין שם החבילה לשם חבילת javaxהמשנה swing. תו תקופתי הוא המקבילה הבלתי תלויה בפלטפורמה של תווי קו נטוי קדימה ( /), תווי קו נטוי ( \), או תווים אחרים להפרדת שמות ספריות ביישום חבילה מבוסס ספריה, ענפי מסד נתונים ביישום חבילה מבוסס היררכי, וכן הלאה. .

עֵצָה
כשם שלא תוכלו לאחסן קובץ וספריה עם שמות זהים באותה ספרייה, לא תוכלו לאחסן מחלקה או ממשק וחבילה עם שמות זהים באותה חבילה. לדוגמה, קיבל חבילה בשם accounts, אתה לא יכול לאחסן הן חבילה מחלקה בשם payableב accounts. כדי להימנע משמות מתנגשים, אותיות גדולות באות הראשונה של שמות המחלקות והממשקים, באותיות קטנות של האות הראשונה של שמות החבילות. בעזרת הדוגמה הקודמת, אחסן מחלקה Payableבחבילה accountsכמו accounts.Payableוחבילה payableבחבילה accountsכמו accounts.payable. קרא מידע נוסף על מוסכמות שמות אחרות ממוסכמות הקוד של Sun עבור שפת התכנות Java .

צור חבילה של שיעורים וממשקים

המחלקות והממשקים של כל קובץ מקור מתארגנים לחבילה. בשנתי packageהיעדרותו ההוראה, כיתות אלה וממשקים שייכים החבילה ללא שם (מדריך ד"ש JVM כספרייה-הספרייה הנוכחית שבה תכנית Java מתחילה ביצוע שלה באמצעות Windows java.exe, או OS-השווה, תכנית-ואינה מכיל חבילות משנה) . אך אם packageההנחיה מופיעה בקובץ מקור, ההנחיה הזו נותנת שם לחבילה עבור אותם מחלקות וממשקים. השתמש בתחביר הבא כדי לציין packageהנחיה בקוד המקור:

'package' packageName ['.' subpackageName ...] ';'

packageהוראה מתחילה עם packageמילות המפתח. מזהה העונה לשם חבילה packageName, מיד אחריו. אם מחלקות וממשקים אמורים להופיע בתוך חבילת משנה (ברמה כלשהי) בתוך packageName, subpackageNameמופיע מזהה אחד או יותר המופרד מהתקופה packageName. קטע הקוד הבא מציג זוג packageהנחיות:

משחק חבילה; משחק חבילות. מכשירים;

packageההנחיה הראשונה מזהה חבילה בשם game. כל המחלקות והממשקים המופיעים בקובץ המקור של אותה הוראה מסודרים gameבחבילה. packageההנחיה השנייה מזהה חבילת משנה בשם devices, השוכנת בחבילה בשם game. כל המחלקות והממשקים המופיעים בקובץ המקור של אותה הוראה מתארגנים gameבחבילה devicesהמשנה של החבילה . אם יישום JVM ממפה את שמות החבילות לשמות ספריות, game.devicesממפה game\devicesלהיררכיית ספריות תחת Windows game/devicesוהיררכיית ספריות תחת Linux או Solaris.

זְהִירוּת
רק packageהוראה אחת יכולה להופיע בקובץ מקור. יתר על כן, packageההנחיה חייבת להיות הקוד הראשון (מלבד הערות) באותו קובץ. הפרת אחד מהכללים גורמת למהדר של ג'אווה לדווח על שגיאה.

כדי לעזור לך להרגיש בנוח עם חבילות, הכנתי דוגמה המשתרעת על כל הנושאים במאמר זה. בחלק זה תלמד כיצד ליצור את חבילת הדוגמה. בחלקים מאוחרים יותר תלמד כיצד לייבא מחלקה וממשק מחבילה זו, כיצד להעביר חבילה זו למיקום אחר בכונן הקשיח ועדיין לגשת לחבילה מתוכנית וכיצד לאחסן את החבילה בקובץ jar. . רישום 1 מציג את קוד המקור של החבילה:

רישום 1. A.java

// חבילת A.java testpkg; מחלקה ציבורית A {int x = 1; ציבורי int y = 2; מוגן int z = 3; int returnx () {return x; } public int returny () {return y; } מוגן int returnz () {return z; } ממשק ציבורי StartStop {void start (); עצירה בטלה (); }} מחלקה B {חלל סטטי ציבורי שלום () {System.out.println ("שלום"); }}

רישום 1 מציג את קוד המקור לחבילה ששמתם לראשונה. package testpkg;שמות ההנחיה כי החבילה testpkg. בתוך testpkgשיעורים Aו B. בתוך Aשלוש הצהרות שדה, שלוש הצהרות שיטות והצהרת ממשק פנימית. בתוך Bטענת שיטה אחת. קוד המקור כולו מאוחסן A.javaכי Aהוא בכיתה ציבורית. המשימה שלנו: להפוך את קוד המקור הזה לחבילה שמורכבת משתי מחלקות וממשק פנימי (או ספריה המכילה שלוש קבצי כיתות). השלבים הבאים ספציפיים ל- Windows מבצעים את אותה משימה:

  1. פתח חלון פקודה של Windows וודא שאתה נמצא c:בספריית הבסיס של הכונן (הספריה הראשית - המיוצגת על ידי תו נטוי אחורי ( \). לשם כך הקלד את c:הפקודה ואחריה cd \הפקודה. (אם אתה משתמש בכונן אחר, החלף c:בכונן שבחרת. כמו כן, אל תשכח ללחוץ על מקש Enter לאחר הקלדת פקודה.)
  2. צור testpkgספריה על ידי הקלדה md testpkg. הערה: בעת ביצוע השלבים של מאמר זה, אל תקלידו נקודות אחרי הפקודות.
  3. הפוך testpkgאת הספריה הנוכחית על ידי הקלדה cd testpkg.
  4. השתמש בעורך כדי להזין את קוד המקור של Listing 1 ולשמור את הקוד A.javaבקובץ testpkg.
  5. הידור על A.javaידי הקלדה javac A.java. אתה צריך לראות classfiles A$StartStop.class, A.class, ו B.classהמופיעים testpkgבמדריך.

איור 1 ממחיש את שלבים 3 עד 5.

מזל טוב! יצרת זה עתה את החבילה הראשונה שלך. חשוב על חבילה זו שהיא מכילה שני מחלקות ( Aו- B) Aוממשק פנימי יחיד ( StartStop). ניתן גם לחשוב על החבילה הזו כספרייה המכילה שלושה classfiles: A$StartStop.class, A.class, ו B.class.

הערה
כדי למזער התנגשויות בשמות החבילות (במיוחד בקרב חבילות מסחריות), סאן קבעה מוסכמה בה שם הדומיין של החברה של החברה הופך את קידומה של שם החבילה. לדוגמה, חברה עם x.comכמו שם תחום האינטרנט שלה a.bכשם חבילה ( a) ולאחריה שם מחבילת משנה ( b) קידומות com.xכדי a.b, וכתוצאה מכך com.x.a.b. המאמר שלי אינו פועל על פי האמנה הזו מכיוון testpkgשהחבילה היא זריקה המיועדת למטרות הוראה בלבד.

ייבא את השיעורים והממשקים של החבילה

Once you have a package, you will want to import classes and/or interfaces—actually, class and/or interface names—from that package to your program, so it can use those classes and/or interfaces. One way to accomplish that task is to supply the fully qualified package name (the package name and all subpackage names) in each place where the reference type name (the class or interface name) appears, as Listing 2 demonstrates:

Listing 2. Usetestpkg1.java

// Usetestpkg1.java class Usetestpkg1 implements testpkg.A.StartStop { public static void main (String [] args) { testpkg.A a = new testpkg.A (); System.out.println (a.y); System.out.println (a.returny ()); Usetestpkg1 utp = new Usetestpkg1 (); utp.start (); utp.stop (); } public void start () { System.out.println ("Start"); } public void stop () { System.out.println ("Stop"); } } 

By prefixing testpkg. to A, Usetestpkg1 accesses testpkg's class A in two places and A's inner interface StartStop in one place. Complete the following steps to compile and run Usetestpkg1:

  1. Open a Windows command window and make sure you are in the c: drive's root directory.
  2. Ensure the classpath environment variable does not exist by executing set classpath=. (I discuss classpath later in this article.)
  3. Use an editor to enter Listing 2's source code and save that code to a Usetestpkg1.java file in the root directory.
  4. Compile Usetestpkg1.java by typing javac Usetestpkg1.java. You should see classfile Usetestpkg1.class appear in the root directory.
  5. Type java Usetestpkg1 to run this program.

Figure 2 illustrates Steps 3 through 5 and shows the program's output.

According to Usetestpkg1's output, the main() method's thread successfully accesses testpkg.A's y field and calls the returny() method. Furthermore, the output shows a successful implementation of the testpkg.A.StartStop inner interface.

For Usetestpkg1, prefixing testpkg. to A in three places doesn't seem a big deal. But who wants to specify a fully qualified package name prefix in a hundred places? Fortunately, Java supplies the import directive to import a package's public reference type name(s), so you do not have to enter fully qualified package name prefixes. Express an import directive in source code via the following syntax:

'import' packageName [ '.' subpackageName ... ] '.' ( referencetypeName | '*' ) ';' 

An import directive consists of the import keyword immediately followed by an identifier that names a package, packageName. An optional list of subpackageName identifiers follows to identify the appropriate subpackage (if necessary). The directive concludes with either a referencetypeName identifier that identifies a specific class or interface from the package, or an asterisk (*) character. If referencetypeName appears, the directive is a single-type import directive. If an asterisk character appears, the directive is a type-on-demand import directive.

Caution
As with the package directive, import directives must appear before any other code, with three exceptions: a package directive, other import directives, or comments.

The single-type import directive imports the name of a single public reference type from a package, as the following code fragment demonstrates:

import java.util.Date; 

The previous single-type import directive imports class name Date into source code. As a result, you specify Date instead of java.util.Date in each place that class name appears in source code. For example, when creating a Date object, specify Date d = new Date (); instead of java.util.Date d = new java.util.Date ();.

יש לנקוט בזהירות באמצעות importהוראות מסוג יחיד . אם המהדר מזהה importהנחיה מסוג יחיד המציין שם סוג הפניה שהוכרז גם בקובץ מקור, המהדר מדווח על שגיאה, כפי שמדגים קטע הקוד הבא:

ייבא java.util.Date; תאריך כיתה {}

המהדר מתייחס לשבר הקוד כניסיון להציג שני סוגי התייחסות באותו Dateשם: