1 / 22

Containers ב Java

Containers ב Java. תכנות מתקדם 89-210 תרגול מספר 3 תש"ע 2009-2010. אליהו חלסצ'י. כלל חשוב לגבי השיעורים הבאים: שאלות על שיעורי הבית – לא בזמן התרגול. ניתן לשאול, כמובן, אחרי. ב java אין templates . המפתחים החליטו שניתן לתכנת בצורה גנרית גם ללא תמיכה ב templates .

jmcauley
Download Presentation

Containers ב Java

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Containers ב Java תכנות מתקדם 89-210תרגול מספר 3 תש"ע 2009-2010 אליהו חלסצ'י

  2. כלל חשוב לגבי השיעורים הבאים: שאלות על שיעורי הבית – לא בזמן התרגול. ניתן לשאול, כמובן, אחרי.

  3. ב java אין templates. המפתחים החליטו שניתן לתכנת בצורה גנרית גם ללא תמיכה ב templates. במקום, ישנה קבוצה של collections, שיכולה לספק את רוב הצרכים שלנו ב containers. קבוצה זו לא נבנתה לשם יעילות כמו ה STL של C++. בעבר קבוצה זו עבדה עם הטיפוס Object וכך היה ניתן להכניס פנימה כל מופע מכל מחלקה. אך העבודה עם Object מצריכה casting וזה האט את הביצועים, כיום ניתן להגדיר את הטיפוס המוכנס ל container. לא ניתן להכניס primitive types ל containers, משום שדרוש אובייקט, לכן יש את המחלקות העוטפות כדוגמת Integer. כמובן שהדבר צורך יותר זיכרון... הקדמה

  4. נניח שנרצה למיין רשימה, פעם בסדר עולה ופעם בסדר יורד, האם נצטרך לשם כך שני מימושים? התשובה היא לא, אם משתמשים ב Strategy Pattern. ע"פ תבנית זו, אלגוריתם המיון ישתמש בהחלטה מבחוץ כיצד למיין את הרשימה. כדי להשפיע על שיטת המיון ב Containers השונים ב java, משתמשים בתבנית זו באמצעות comparator. Comparator

  5. כל מחלקה יכולה לממש את הממשקים הבאים: ע"פ המימוש באחד מממשקים אלו, ה containers מחליטים כיצד למיין בפנים את העצמים השמורים. Comparator interface Comparator { int compare(Object o1, Object o2); } • interface Comparable { • int compareTo(Object o) ; • }

  6. דוגמא: Comparator Robot r1=new RV1(); Robot r2=new RV1(); Robot r3=new RV1(); r1.setName("aaabc"); r2.setName("aabc"); r3.setName("abc"); ArrayList<Robot> ar=new ArrayList<Robot>(); ar.add(r3); ar.add(r2); ar.add(r1); Collections.sort(ar); for(int i=0;i<ar.size();i++){ System.out.println(ar.get(i).getName()); } פלט: aaabc aabc abc publicclass RV1 implements Robot ,Comparable<Robot>{ … private String name; public String getName() { returnname; } publicint compareTo(Robot arg0) { returnname.compareTo(arg0.getName()); } } • מיון: אופטימיזציה של merge sort מהירה ויציבה: • מיון מהיר: • nlog(n) תמיד מובטח (בניגוד ל quick sort) • עובד מהר יותר על רשימות כמעט ממוינות. • מיון יציב : • - לא ממיינת עצמים שווים. (דוג' דואר שממוין לפי תאריך)

  7. ב java יש שני סוגים של Containers: Collections קבוצה של ערכים בודדים List – רשימה: שומר על הערכים ברצף מסוים. Set – קבוצה: אותו הערך לא יכול להופיע יותר מפעם אחת. Map קבוצה של הזוגות מפתח + ערך לכל אלו מימושים שונים על בסיס הצורות שלמדתם בקורס מבנה נתונים. לכל אחד יתרונות וחסרונות אחרים, ולכן יש להתאים את ה container לדרישות התוכנה. Containers שימושיים

  8. להלן כמה דוגמאות: List ArrayList ממומש על בסיס מערך: גישה אקראית מהירה, אך הוספה ומחיקה מהאמצע איטית. LinkedList ממומש על בסיס רשימה מקושרת דו כיוונית: גישה אקראית איטית, אך הוספה ומחיקה מהאמצע מהירה. Set HashSet לשימוש כשזמן חיפוש האלמנט חשוב, יש לממש המתודה HashCode() לאובייקט שברצוננו להכניס. TreeSet ניתן בקלות להוציא רשימה ממוינת. Map HashMap ממומש באמצעות hash tables, אובייקט המפתח חייב לממש את HashCode() LinkedHashMap – אותו הדבר, אך שומר גם את סדר ההכנסה. TreeMap – ממומש ע"י עץ אדום שחור, ניתן לקבל תוצאות ממוינות. Containers שימושיים

  9. מתודות שימושיות ל Collections: boolean add(Objetc o) boolean add(Collection c) void clear() boolean contains(Object o) boolean isEmpty() Iterator iterator() boolean remove(Object o) boolean removeAll(Collection c) int size() Object[] toArray() Containers שימושיים

  10. מתודות שימושיות ל Map: Object put(Object key, Object value) void putAll(Map t) Object get(Object key) void clear() boolean containsKey(Object key) boolean containsValue(Object value) boolean isEmpty() Object remove(Object key) int size() Set entrySet() Set keySet() Collection values() Containers שימושיים

  11. מטרת ה Iterator היא לספק גישה לעצמים ב Container מבלי לחשוף את אופן פעולתו. בממשק (של List לדוג') לא ניתן לספק את כל האופנים השונים בהם נרצה לטייל ב container. ייתכנו כמה iterators עבור אותו ה container כל אחד יטייל בדרך שונה על העצמים. Iterator

  12. דוגמאות: Iterator ArrayList<Robot> ar=new ArrayList<Robot>(); ar.add(r3); ar.add(r2); ar.add(r1); for(int i=0;i<ar.size();i++){ System.out.println(ar.get(i).getName()); } Iterator<Robot> it=ar.iterator(); while (it.hasNext()){ System.out.println(it.next().getName()); }

  13. דוגמאות: HashSet HashMap Iterator HashSet hs<Robot>=new HashSet<Robot> (); hs.add(r3); hs.add(r2); hs.add(r1); Iterator<Robot> it=hs.iterator(); while (it.hasNext()){ System.out.println(it.next().getName()); } String key; HashMap<String,Robot> hm=new HashMap<String,Robot> (); hm.put(r3.getName(), r3); hm.put(r2.getName(), r2); hm.put(r1.getName(), r1); Iterator<String> it=hm.keySet().iterator(); while (it.hasNext()){ key=it.next(); System.out.println(hm.get(key).getName()); }

  14. בעיה: נניח שיש לנו n סוגים של אובייקטים ולכל אחד שם, אופן פעולת התוכנית צריך להיות כך שהמשתמש בכל פעם בוחר שם והאובייקט הרצוי נוצר. לכאורה, במקרה הגרוע צריך n השוואות כדי לדעת באיזה שם המשתמש בחר, וע"פ השם הזה ליצור את האובייקט הרצוי. O(n) דרך טובה יותר לפתור את הבעיה, היא להשתמש ב Factory Pattern, יש הרבה דרכים למימוש, נראה דוגמא לדרך אחת. Factory Pattern

  15. Factory Pattern private HashMap<String,RobotFac> robotFactory; public RobotFactory(){ robotFactory=new HashMap<String,RobotFac> (); robotFactory.put("RV1", new RV1Fac()); robotFactory.put("RV2", new RV2Fac()); robotFactory.put("Aibo", new AiboFac()); } public Robot createRobot(String type){ return ((RobotFac)robotFactory.get(type)).create(); } } import java.util.HashMap; publicclass RobotFactory { privateinterface RobotFac{ public Robot create(); } privateclass RV1Fac implements RobotFac{ public Robot create(){ returnnew RV1();} } privateclass RV2Fac implements RobotFac{ public Robot create(){ returnnew RV2();} } privateclass AiboFac implements RobotFac{ public Robot create(){ returnnew Aibo();} } • ניצור ממשק עם הפקודה create.

  16. Factory Pattern private HashMap<String,RobotFac> robotFactory; public RobotFactory(){ robotFactory=new HashMap<String,RobotFac> (); robotFactory.put("RV1", new RV1Fac()); robotFactory.put("RV2", new RV2Fac()); robotFactory.put("Aibo", new AiboFac()); } public Robot createRobot(String type){ return (robotFactory.get(type).create(); } } import java.util.HashMap; publicclass RobotFactory { privateinterface RobotFac{ public Robot create(); } privateclass RV1Fac implements RobotFac{ public Robot create(){ returnnew RV1();} } privateclass RV2Fac implements RobotFac{ public Robot create(){ returnnew RV2();} } privateclass AiboFac implements RobotFac{ public Robot create(){ returnnew Aibo();} } • ניצור ממשק עם הפקודה create. • נממש את הממשק ע"י מחלקות עבור כל אחד מסוגי האובייקטים הרצויים.

  17. Factory Pattern private HashMap<String,RobotFac> robotFactory; public RobotFactory(){ robotFactory=new HashMap<String,RobotFac> (); robotFactory.put("RV1", new RV1Fac()); robotFactory.put("RV2", new RV2Fac()); robotFactory.put("Aibo", new AiboFac()); } public Robot createRobot(String type){ return (robotFactory.get(type).create(); } } import java.util.HashMap; publicclass RobotFactory { privateinterface RobotFac{ public Robot create(); } privateclass RV1Fac implements RobotFac{ public Robot create(){ returnnew RV1();} } privateclass RV2Fac implements RobotFac{ public Robot create(){ returnnew RV2();} } privateclass AiboFac implements RobotFac{ public Robot create(){ returnnew Aibo();} } • ניצור ממשק עם הפקודה create. • נממש את הממשק ע"י מחלקות עבור כל אחד מסוגי האובייקטים הרצויים. • ניצור HashMap עבור המחלקות הנ"ל,כשהמפתח הוא השם דרכוהמשתמש בוחר ליצור את האובייקט הרצוי.

  18. Factory Pattern private HashMap<String,RobotFac> robotFactory; public RobotFactory(){ robotFactory=new HashMap<String,RobotFac> (); robotFactory.put("RV1", new RV1Fac()); robotFactory.put("RV2", new RV2Fac()); robotFactory.put("Aibo", new AiboFac()); } public Robot createRobot(String type){ return (robotFactory.get(type).create(); } } import java.util.HashMap; publicclass RobotFactory { privateinterface RobotFac{ public Robot create(); } privateclass RV1Fac implements RobotFac{ public Robot create(){ returnnew RV1();} } privateclass RV2Fac implements RobotFac{ public Robot create(){ returnnew RV2();} } privateclass AiboFac implements RobotFac{ public Robot create(){ returnnew Aibo();} } • ניצור ממשק עם הפקודה create. • נממש את הממשק ע"י מחלקות עבור כל אחד מסוגי האובייקטים הרצויים. • ניצור HashMap עבור המחלקות הנ"ל,כשהמפתח הוא השם דרכוהמשתמש בוחר ליצור את האובייקט הרצוי. • נכניס את הזוגות String, RobotFac>> ל Hashmap

  19. Factory Pattern private HashMap<String,RobotFac> robotFactory; public RobotFactory(){ robotFactory=new HashMap<String,RobotFac> (); robotFactory.put("RV1", new RV1Fac()); robotFactory.put("RV2", new RV2Fac()); robotFactory.put("Aibo", new AiboFac()); } public Robot createRobot(String type){ return (robotFactory.get(type).create(); } } import java.util.HashMap; publicclass RobotFactory { privateinterface RobotFac{ public Robot create(); } privateclass RV1Fac implements RobotFac{ public Robot create(){ returnnew RV1();} } privateclass RV2Fac implements RobotFac{ public Robot create(){ returnnew RV2();} } privateclass AiboFac implements RobotFac{ public Robot create(){ returnnew Aibo();} } • ניצור ממשק עם הפקודה create. • נממש את הממשק ע"י מחלקות עבור כל אחד מסוגי האובייקטים הרצויים. • ניצור HashMap עבור המחלקות הנ"ל,כשהמפתח הוא השם דרכוהמשתמש בוחר ליצור את האובייקט הרצוי. • נכניס את הזוגות String, RobotFac>> ל Hashmap • פקודת יצירת האובייקט: בהינתן מחרוזת שהמשתמש בחר, ניגש בזמןשל O(1) ל HashMap אל האובייקט השמור תחת אותה המחרוזתכמפתח נקרא ל create ונקבל את האובייקט הרצוי. • החלפנו O(n) זמן ב O(n) מקום, וקיבלנו זמן של O(1) ליצירת אובייקטים + נוחות לתחזק ולהוסיף בעתיד או אובייקטים ל Factory.

  20. העובדה ש containers מקבלים אובייקט מצריכה אותנו לבזבז זיכרון בעקבות השימוש במחלקות העוטפות, במקרה שאנו רוצים להשתמש רק ב primitive types. הקבוצה GNU Trove יצרה Collections חדשים שמקבלים primitive types ובכך חוסכות זיכרון, וכן משפרת משמעותית את הביצועים. באתר הקורס פרטים על הורדה + הדרך להוסיף jars לפרויקט באמצעות ה eclipse. Trove

  21. קוד לדוגמא: Trove import gnu.trove.*; publicclass HelloWorldApp { static TByteFloatHashMap hm=new TByteFloatHashMap(); publicstaticvoid main(String[] args) { float lastValueForThisKey; byte key1=1,key2=2,key3=3; hm.put(key1, (float) 0.2); lastValueForThisKey=hm.put(key1, (float) 0.1); System.out.println("last value for key1 was "+lastValueForThisKey); hm.put(key2, (float) 0.2); hm.put(key3, (float) 0.3); TByteFloatIterator it= hm.iterator(); while (it.hasNext()){ it.advance(); System.out.println("key: "+it.key()+" , value: "+ it.value()); } } } פלט: last value for key1 was 0.2 key: 2 , value: 0.2 key: 1 , value: 0.1 key: 3 , value: 0.3

  22. מנה 2 חסרונות של ה containers ב java לעומת C++ STL באיזה אלגוריתם מיון משתמש Collections.sort() ומדוע? בדקו האם המתודה boolean contains(Object o) מחזירה "אמת" לפי תוכן האובייקט או לפי מיקומו בזיכרון. כנסו לאתר Sun ותכירו עוד containers כגון PriorityQueue, Hashtable צרו collection כלשהו עבור int באמצעות trove ותעברו עליו באמצעות iterator. הטמעה

More Related