1 / 18

Java Reflection

חומרי עזר שהוכנו ע"י משתתפי קורס מורים מובילים תשע"א ניתן להשתמש בחומרים לצורך הוראה בלבד. אסור לפרסם את החומרים או לעשות בהם שימוש מסחרי כלשהו ללא קבלת אישור מראש מצוות הפיתוח. Java Reflection. הוכן על-ידי אחמד ג'בארה. מה זה ?.

Download Presentation

Java Reflection

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. חומרי עזר שהוכנו ע"י משתתפי קורס מורים מובילים תשע"א ניתן להשתמש בחומרים לצורך הוראה בלבד. אסור לפרסם את החומרים או לעשות בהם שימוש מסחרי כלשהו ללא קבלת אישור מראש מצוות הפיתוח Java Reflection הוכן על-ידי אחמד ג'בארה

  2. מה זה ? Reflection is the ability of a running program to examine itself and its software environment, and to change what it does depending on what it finds • מנגנון שמאפשר לתוכנית בשפת ג'אווה לבחון/לשנות את עצמה בזמן ריצה, הן בפן המבני והן בהתנהגותי. • דוגמאות : • התוכנית תדע לברר ולמצוא את רשימת השיטות, הבנאים והתכונות של מחלקה מסוימת בזמן ריצה. • התוכנית תדע לקחת את מרכיבי המחלקה ולהשתמש בהן. למשל, • להפעיל את אחת השיטות • ליצור אובייקט דרך אחד הבנאים • בהינתן אובייקט כלשהו, התוכנית תדע למצוא מאיזה סוג מחלקה הוא ואת ההיררכיה של מחלקות הירושה. • בקצרה: בעזרת מנגנון זה נוכל לעשות כל מה שידענו לעשות עד כה רק בזמן ריצה.

  3. למה זה טוב ? • עיקר השימוש ב- Reflectionהוא לפיתוח כלים (שיודעים לדלות מידע על התוכנית בזמן ריצתה) ויישומים שנדרשת בהם מידה רבה של גמישות. • חשיבות המנגנון נובעת מעצם העובדה שניתן לכתוב תוכניות שמסוגלות לעבוד עם מחלקות ולהפעיל שיטות שהתוכנית לא ידעה על קיומן בזמן קומפילציה.

  4. איך עושים את זה ? • כדי שתוכנית תוכל לבחון את המבנה של עצמה ואת זה של סביבתה יש צורך שלתוכנית יהיה ייצוג לעצמה. כלומר, התוכנית מחזיקה מידע שמייצג אותה. מידע כזה נקרא metadata • בסביבה שהיא מונחית עצמים, מידע זה נשמר באובייקטים שנקראים metaobjects . • תהליך שבו תוכנית בוחנת בזמן ריצה את ה- metaobjects בסביבת הריצה שלה נקרא introspection • שפת ג'אווה מחזיקה לכל מחלקה בשפה metaobject שמכיל מידע מבני/התנהגותי אודות מחלקה זו.

  5. איך עושים את זה ? המחלקה Class • נקודת ההתחלה היא הכרת המחלקה Class שמוגדרת ב- java.lang.Class • כל מחלקה שמוגדרת בתוכנית ונטענת לזכרון מיוצגת על ידי metaobject מסוג המחלקה Class. • אובייקט זה (שנוצר אוטומטית על ידי ה- JVM) מכיל מידע אודות המחלקה וגם פעולות שמאפשרות לברר מידע זה. • מידע זה כולל • החבילה שמשתייכת אליה המחלקה • מחלקת הבסיס של מחלקה זו • רשימת השיטות של המחלקה • רשימת בנאים • תכונות • וכו'

  6. אובייקט מסוג המחקלה Class - דוגמה • public class Point{ • private int x, y; • public Point(int x, int y){ • this.x = x; • this.y = y; • } • public void show() { • System.out.print(“(“+x+”,”+y+”)”); • } • } • public class Program { • public static void main(String[] args){ • Point p1 = new Point(2,3); • Point p2 = new Point(5,1); • p1.show(); • p2.show(); • } • } • תוכנית זו מגדירה מחלקה Point ויוצרת שני אובייקטים מסוג מחלקה זו. • בפועל, יש לנו עוד אובייקט נוסף מסוג מחלקה אחרת שנקראת Class. • אובייקט זה נוצר בעבור המחלקה Point והוא מכיל מידע מבני עליה. • אובייקט זה יידע להגיד לנו מי היא מחלקת הבסיס של Point, איזה שיטות יש ב- Point .

  7. Base-level Objects vs. Meta-level Objects • ובכן, בסביבת הריצה של תוכנית ג'אווה מבחינים בין שני סוגי אובייקטים: • אובייקטים שהתוכנית שלנו יוצרת (כמו בדרך כלל) והם מכונים : base-level objects • אובייקטים לייצוג התוכנית (metaobjects) והם מכונים : meta-level objects Metaobject (Point) Meta-level p1 p2 x=5 y=1 x=2 y=3 Base-level

  8. איך ניגשים לאובייקט מסוג Class? • ישנן מספר דרכים • תכונה סטטית של המחלקה • Point.class • שם המחלקה (ניתן כמחרוזת) • Class.forName(“Point”) • אובייקט כלשהו מסוג המחלקה. • p1.getClass() • public class Point{ • private int x, y; • public Point(int x, int y){ • this.x = x; • this.y = y; • } • public void show() { • System.out.print(“(“+x+”,”+y+”)”); • } • } • public class Program { • public static void main(String[] args){ • Point p1 = new Point(2,3); • Point p2 = new Point(5,1); • p1.show(); • p2.show(); • } • } • בשלושת המקרים קיבלנו את אותה תשובה. מצביע על אובייקט מסוג המחלקה Class שמכיל מידע על המחלקה Point. • לכן, • Class c1 = Point.class; • Class c2 = Class.forName(“Point”); • Class c3 = p1.getClass();

  9. Base-level Objects vs. Meta-level Objects Metaobject (Point) Meta-level Class.forName(“Point”) p2.getClass() Point.class p1.getClass() p2 x=5 y=1 x=2 y=3 p1 Base-level

  10. הצגת היררכית המחלקות של אובייקט כלשהו public class Point{ private int x, y; public Point(int x, int y){ this.x = x; this.y = y; } public void show() { System.out.print(“(“+x+”,”+y+”)”); } } public class Program { public static void showHierarchy(Object o){ Class c = o.getClass(); do { System.out.println(c.getName()); c=c.getSuperclass(); }while (c!=null); } public static void main(String[] args) { showHierarchy(new Point(2,3)); showHierarchy("Test"); showHierarchy(7); } } • השיטה הסטטית showHierarchy מקבלת אובייקט כלשהו. • הסוג האמיתי (הדינמי) של הפרמטר o אינו ידוע ויכול להיות כל דבר. • השיטה הסטטית מדפיסה את מסלול הירושה מהמחלקה הבסיסית Object ועד למחלקה האמיתית של o. • שים לב, בשיטה הראשית, כל פעם שולחים ארגומנט מסוג אחר. • נקודת המפתח של הפתרון היא שורה 12 שהחזירה לנו את האובייקט שמכיל את המידע המבני של המחלקה האמיתית של הפרמטר o.

  11. הצגת מבנה מחלקה כלשהי • השיטה הסטטית showStructure מקבלת אובייקט כלשהו. • הסוג האמיתי (הדינמי) של הפרמטר o אינו ידוע ויכול להיות כל דבר. • השיטה הסטטית מדפיסה את מבנה המחלקה של אובייקט זה. (Point) • שורה 4 מבקשת אובייקט מסוג Class. • שורה 5 מפעילה שיטה שמחזירה מערך של כל תכונות המחלקה . שים לב, שכל תכונה היא אובייקט • שורה 6 מפעילה שיטה שמחזירה מערך של שיטות המחלקה. כל שיטה היא אובייקט מסוג המחלקה Method. • המידע שמתקבל שייך רק למחלקה עצמה ואינו כולל מידע שמחלקה זו ירשה. • לקבלת מידע (ציבורי בלבד) שהתקבל בירושה יש להשתמש בשיטות האלה : getFields, getMethods, getConstructors. import java.lang.reflect.*; public class Program { public static void showStructure(Object o) { Class c = o.getClass(); Field[] fs = c.getDeclaredFields(); Method[] ms = c.getDeclaredMethods(); Constructor[] cs = c.getDeclaredConstructors(); for (int k=0; k < fs.length; k++) System.out.println(fs[k]); for (int k=0; k < ms.length ; k++) System.out.println(ms[k]); for (int k=0; k < cs.length ; k++) System.out.println(cs[k]); } public static void main(String[] args) { showStructure(new Point(2,3)); } }

  12. שיטה אחת להצגת מצב כל אובייקט. • השיטה הסטטית showState מקבלת אובייקט כלשהו. • הסוג האמיתי (הדינמי) של הפרמטר o אינו ידוע ויכול להיות כל דבר. • השיטה הסטטית עוברת על כל תכונות המחלקה. לכל תכונה היא מדפיסה את ערכה באובייקט o שהועבר כפרמטר. • במקרה והתכונה מוגדרת כפרטית, משנים לה את ההרשאות לציבורית ואז מבקשים את הערך. • כמובן ניתן לשנות בקלות את השיטה כדי לכלול בהדפסה את התכונות שהתקבלו בירושה. public class Point { private int x,y; private String color; public Point(int x, int y, String color){ this.x=x; this.y=y; this.color = color; } public void show() { System.out.println("("+x+","+y+","+color+")"); } } import java.lang.reflect.*; public class Program { public static void showState(Object o) throws Exception{ Class c = o.getClass(); Field[] fs = c.getDeclaredFields(); for (int k=0; k < fs.length; k++){ if (!fs[k].isAccessible()) fs[k].setAccessible(true); System.out.println(fs[k].get(o)); } } public static void main(String[] args) throws Exception{ showState(new Point(2,3,"Red")); } }

  13. הפעלת שיטה בזמן ריצה – מצביע לפונקציה • השיטה הסטטית methodCallמקבלת אובייקט כלשהו. • הסוג האמיתי (הדינמי) של הפרמטר o אינו ידוע ויכול להיות כל דבר. • השיטה הסטטית בודקת האם לאובייקט זה יש שיטה בשם show שלא מקבלת פרמטרים. • אם לא, מוצגת הודעה. • אם כן, שיטה זו מופעלת. • השיטה getMethod מקבלת את שם השיטה אותה מחפשים, ורשימה של סוגי פרמטרים (כולם אובייקטים מסוג Class). אם השיטה לא מקבלת פרמטרים מעבירים null. • השיטה invoke מפעילה את השיטה שנמצאת באובייקט m . הפרמטר הראשון שלה הוא האובייקט עליו פועלת השיטה, והפרמטר השני רשימת ארגומנטים לשיטה. public class Point { private int x,y; private String color; public Point(int x, int y, String color){ this.x=x; this.y=y; this.color = color; } public void show() { System.out.println("("+x+","+y+","+color+")"); } } import java.lang.reflect.*; public class Program { public static void methodCall(Object o) throws Exception{ Class c = o.getClass(); Method m = c.getMethod("show",null); if (m==null) System.out.println("no such method"); else m.invoke(o, null); } public static void main(String[] args) throws Exception{ methodCall(new Point(2,3,"Red")); } }

  14. הפעלת שיטה פרטית • השיטה הסטטית methodCallמקבלת אובייקט כלשהו. • הסוג האמיתי (הדינמי) של הפרמטר o אינו ידוע ויכול להיות כל דבר. • השיטה הסטטית בודקת האם לאובייקט זה יש שיטה בשם show שלא מקבלת פרמטרים. • אם לא, מוצגת הודעה. • אם כן, שיטה זו מופעלת. • השיטה getMethod מקבלת את שם השיטה אותה מחפשים, ורשימה של סוגי פרמטרים (כולם אובייקטים מסוג Class). אם השיטה לא מקבלת פרמטרים מעבירים null. • השיטה invoke מפעילה את השיטה שנמצאת באובייקט m . הפרמטר הראשון שלה הוא האובייקט עליו פועלת השיטה, והפרמטר השני רשימת ארגומנטים לשיטה. public class Point { private int x,y; private String color; public Point(int x, int y, String color){ this.x=x; this.y=y; this.color = color; } private void show() { System.out.println("("+x+","+y+","+color+")"); } } import java.lang.reflect.*; public class Program { public static void main(String[] args) throws Exception{ Point p1 = new Point(2,3); Class c = p1.getClass(); Method m = c.getMethod("show", null); If (m!=null) { if (!m.isAccessible()) m.setAccessible(true); m.invoke(p1, null); { } }

  15. שכפול מערך אובייקטים מסוגים שונים • נתון מערך אובייקטים מסוגים שונים. למשל , Object[] • ברור שמערך כזה יכול להחזיק אובייקטים מכל סוג שנרצה. • המטרה • שכפול המערך באופן מלא. כלומר, שכפול המערך כאובייקט ושכפול כל אחד מהאובייקטים שלו. • הבעיה • כדי לשכפל אובייקט יש צורך להשתמש בבנאי העתקה. אך לצורך שימוש בבנאי העתקה עלינו לדעת מראש את שם המחלקה. אבל נקודת המוצא שלנו שאנחנו לא יודעים שום דבר על האובייקטים של המערך. • פתרון • נבדוק את גודל המערך ונקצה מערך של אובייקטים חדש. אך, זה רק מערך הפניות ויש להקצות את האובייקטים האמיתיים. • לכל תא במערך נבקש את ה- metaobject שלו. • מתוך ה- metaobject נברר אם המחלקה המקורית של האובייקט מכילה בנאי העתקה. • במידה וכן נפעיל בנאי זה ובכך נשכפל את האובייקט. • במידה ואין קיימות לא מעט אפשרויות נוספות כדי להתמודד (Cloning למשל) אך לא נטפל בהן כאן ולכן נבצע הפניה לאובייקט המקורי. • הדוגמה שנציג כאן מחזיקה מערך צורות (רק לצורך הפשטות בלבד). דרך הפתרון לא משתנה.

  16. שכפול מערך אובייקטים מסוגים שונים public abstract class Shape { abstract double calcArea(); { public class Circle extends Shape { private int x,y; private int rad; public Circle(int x, int y, int rad) { this.x = x; this.y = y; this.rad = rad; { public Circle(Circle c) { this.x = c.x; this.y = c.y; this.rad = c.rad; } double calcArea() { return Math.PI*rad*rad; } } public class Rect extends Shape { private int w,h; public Rect(int w, int h) { this.w = w; this.h = h; } public Rect(Rect r) { this.w = r.w; this.h = r.h; } public double calcArea() { return w*h; { {

  17. שכפול מערך אובייקטים מסוגים שונים - המשך import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.*; public class Program { public static Shape[] duplicate(Shape[] shapes) throws Exception{ if (shapes==null) return null; Shape[] dShapes = new Shape[shapes.length]; for (int k=0; k < shapes.length ; k++){ Class c = shapes[k].getClass(); Constructor ctr = c.getConstructor(c); If (ctr != null) dShapes[k] = (Shape)ctr.newInstance(shapes[k]); else dShapes[k] = shapes[k]; } return dShapes; } public static void main(String[] args) throws Exception{ Shape[] shapes = {new Circle(1,1,3), new Circle(5,4,1), new Rect(4,7),new Circle(1,1,1)}; Shape[] dShapes; dShapes=duplicate(shapes); } {

  18. שכפול מערך אובייקטים מסוגים שונים - המשך צילום המסך מראה את הזכרון של שני המערכים (מקורי + העתק). חשוב לשים לב שתי נקודות : המערכים והאיבירים שלהם הם אובייקטים שונים לחלוטין במובן הזה שיש להם כתובות שונות בזכרון (לכל אחד מספר מזהה אחר). בנוסף סוג המחלקה של כל אובייקט נשמר גם הוא.

More Related