Generic methods בג'אווה

nocgod

New member
Generic methods בג'אווה

אני משחק קצת עם מתודות גנריות בג'אווה, אני מקבל הערה מעניינת שאני לא בדיוק יודע איך לסדר...

public <C extends Collection<V>, V> C readCollection(String path, Class<C> collectionType, Class<V> valueType)

זה הכותרת של המתודה, וזה הקריאה למתודה במהלך תוכנית
reader.readCollection("weights.model", new Vector<String>().getClass(), String.class);

אני מקבל את ההערה
Type safety: Unchecked invocation readCollection(String, Class<capture#1-of ? extends Vector>, Class<String>) of the generic method readCollection(String, Class<C>, Class<V>) of type JSONParsedFileHandler


אני כמובן יכול להתעלם ממנה...מצד שני הייתי רוצה לדעת ממה היא נובעת...יש רעיונות?
 

selalerer

New member
Java לא בודק שהפרמטר שאתה...

... מעביר הוא עם אותו סוג של generic parameter שהעברת.

למעשה, מבחינת השפה, זה כאילו העברת לשם Class או <?>Class

אולי זה רק הקומפיילר נותן לך ובזמן ריצה נזרקת exception.

זה כנראה קשור לזה שמבחינת הקוד המקומפל כל פרמטר ג'נרי הוא למעשה object בשביל לא ליצור יותר מ-class אחד לכל generic (ליצור <Vector<Object ולהשתמש בו בשביל כל ה-instanciations של Vector).

אני לא ממש הבנתי עד הסוף למה הקומפיילר לא בודק את זה.
 

selalerer

New member
קראתי על זה קצת ונראה ש-Java לא שומר שום מידע

על ה-type שה-generic class קיבל כפרמטר בקומפילציה. כלומר אם יש לך קוד מקומפל (למשל jar שאתה משתמש בו) ואתה קורא למטודה, אין לקומפיילר דרך לדעת (במידה ואין גם את ה-sourceים של ה-jar) את הפרמטר הזה.

כלומר במקרה שאתה הראית, מבחינת הקומפיילר, הפונקציה מקבלת Class ולא <Class<C.
 

nocgod

New member
שכתבתי לפי מה שקראתי/הבנתי

throws JsonParseException, JsonMappingException, IOException
{
ObjectMapper mapper = new ObjectMapper();

return mapper.readValue(new File(path), mapper.getTypeFactory().constructCollectionType(collectionType, valueType));
}

public <M extends Map<?, ?>> M readMap(String path, Class<M> mapType, Class<?> keyClass, Class<?> valueClass)
throws JsonParseException, JsonMappingException, IOException
{
ObjectMapper mapper = new ObjectMapper();

return mapper.readValue(new File(path), mapper.getTypeFactory().constructMapType(mapType, keyClass, valueClass));
}


עדיין קצת מכעיס שזה מחזיר לי את M לא בצורה פרמטרית...
 

nocgod

New member
קח עוד דוגמא שעובדת אבל מציגה לי warning

public <K, V, M extends Map<K, V>> M readMap(String path, Class<M> mapType, Class<K> keyClass, Class<V> valueClass) throws JsonParseException, JsonMappingException, IOException
{

ObjectMapper mapper = new ObjectMapper();

return mapper.readValue(new File(path), mapper.getTypeFactory().constructMapType(mapType, keyClass, valueClass));

}


והקריאה:

HashMap<String, Double> weightMap;
JSONParsedFileHandler reader = new JSONParsedFileHandler();
weightMap = reader.readMap("weights.model", HashMap.class, String.class, Double.class);

System.out.println(weightMap);

וזה עובד יופי אבל עדיין מציג לי את הwarning הבא:

Type safety: The expression of type HashMap needs unchecked conversion to conform to HashMap<String,Double>


אין איזה דרך לגרום לו להבין שכשהוא מחזיר את M זה צריך להיות בעצם M<K,V>zzz ?
 

selalerer

New member
כנראה שאין דרך.

כשהקומפיילר לוקח בחשבון שהקוד המקומפל הוא ללא ה-K וה-V והוא צריך להתנהג אותו דבר כאשר אתה מקמפל את הקוד ביחד או בנפרד (למשל תעביר אותו ל-jar אחר) אז מבחינתו זה <M<Object, Object והוא לא יכול לבדוק לך את הסוגים (אז הוא רק מזהיר אותך).
 

nocgod

New member
הבנתי שהדבר היחיד שפרמטריזציה טובה בשבילו היא

בדיקת טיפוסים בזמן קומפילציה. כי בזמן ריצה הוא פשוט מוחק את כל המידע הזה.
דיי מאכזב ת'אמת... מעניין אם זה ככה עקום גם ב #C...
 

selalerer

New member
אני חושב שלא.

בקישור ששמתי הוא כותב שב-#C נקטו בגישה אחרת.
 
ב-#C יש RTTI מלא.

 
למעלה