166 } |
168 } |
167 |
169 |
168 /** |
170 /** |
169 * Look for attributes representing annotations and unpack them. |
171 * Look for attributes representing annotations and unpack them. |
170 */ |
172 */ |
171 private AnnotationEntryGen[] unpackAnnotations(final Attribute[] attrs) { |
173 private AnnotationEntryGen[] unpackAnnotations(final Attribute[] attrs) |
|
174 { |
172 final List<AnnotationEntryGen> annotationGenObjs = new ArrayList<>(); |
175 final List<AnnotationEntryGen> annotationGenObjs = new ArrayList<>(); |
173 for (final Attribute attr : attrs) { |
176 for (final Attribute attr : attrs) { |
174 if (attr instanceof RuntimeVisibleAnnotations) { |
177 if (attr instanceof RuntimeVisibleAnnotations) |
|
178 { |
175 final RuntimeVisibleAnnotations rva = (RuntimeVisibleAnnotations) attr; |
179 final RuntimeVisibleAnnotations rva = (RuntimeVisibleAnnotations) attr; |
176 final AnnotationEntry[] annos = rva.getAnnotationEntries(); |
180 final AnnotationEntry[] annos = rva.getAnnotationEntries(); |
177 for (final AnnotationEntry a : annos) { |
181 for (final AnnotationEntry a : annos) { |
178 annotationGenObjs.add(new AnnotationEntryGen(a, |
182 annotationGenObjs.add(new AnnotationEntryGen(a, |
179 getConstantPool(), false)); |
183 getConstantPool(), false)); |
180 } |
184 } |
181 } else if (attr instanceof RuntimeInvisibleAnnotations) { |
185 } |
182 final RuntimeInvisibleAnnotations ria = (RuntimeInvisibleAnnotations) attr; |
186 else |
183 final AnnotationEntry[] annos = ria.getAnnotationEntries(); |
187 if (attr instanceof RuntimeInvisibleAnnotations) |
184 for (final AnnotationEntry a : annos) { |
188 { |
185 annotationGenObjs.add(new AnnotationEntryGen(a, |
189 final RuntimeInvisibleAnnotations ria = (RuntimeInvisibleAnnotations) attr; |
186 getConstantPool(), false)); |
190 final AnnotationEntry[] annos = ria.getAnnotationEntries(); |
|
191 for (final AnnotationEntry a : annos) { |
|
192 annotationGenObjs.add(new AnnotationEntryGen(a, |
|
193 getConstantPool(), false)); |
|
194 } |
187 } |
195 } |
188 } |
|
189 } |
196 } |
190 return annotationGenObjs.toArray(new AnnotationEntryGen[annotationGenObjs.size()]); |
197 return annotationGenObjs.toArray(new AnnotationEntryGen[annotationGenObjs.size()]); |
191 } |
198 } |
|
199 |
192 |
200 |
193 /** |
201 /** |
194 * @return the (finally) built up Java class object. |
202 * @return the (finally) built up Java class object. |
195 */ |
203 */ |
196 public JavaClass getJavaClass() { |
204 public JavaClass getJavaClass() { |
197 final int[] interfaces = getInterfaces(); |
205 final int[] interfaces = getInterfaces(); |
198 final Field[] fields = getFields(); |
206 final Field[] fields = getFields(); |
199 final Method[] methods = getMethods(); |
207 final Method[] methods = getMethods(); |
200 Attribute[] attributes; |
208 Attribute[] attributes = null; |
201 if (annotation_vec.isEmpty()) { |
209 if (annotation_vec.isEmpty()) { |
202 attributes = getAttributes(); |
210 attributes = getAttributes(); |
203 } else { |
211 } else { |
204 // TODO: Sometime later, trash any attributes called 'RuntimeVisibleAnnotations' or 'RuntimeInvisibleAnnotations' |
212 // TODO: Sometime later, trash any attributes called 'RuntimeVisibleAnnotations' or 'RuntimeInvisibleAnnotations' |
205 final Attribute[] annAttributes = AnnotationEntryGen.getAnnotationAttributes(cp, getAnnotationEntries()); |
213 final Attribute[] annAttributes = AnnotationEntryGen.getAnnotationAttributes(cp, getAnnotationEntries()); |
206 attributes = new Attribute[attribute_vec.size() + annAttributes.length]; |
214 attributes = new Attribute[attribute_vec.size()+annAttributes.length]; |
207 attribute_vec.toArray(attributes); |
215 attribute_vec.toArray(attributes); |
208 System.arraycopy(annAttributes, 0, attributes, attribute_vec.size(), annAttributes.length); |
216 System.arraycopy(annAttributes,0,attributes,attribute_vec.size(),annAttributes.length); |
209 } |
217 } |
210 // Must be last since the above calls may still add something to it |
218 // Must be last since the above calls may still add something to it |
211 final ConstantPool _cp = this.cp.getFinalConstantPool(); |
219 final ConstantPool _cp = this.cp.getFinalConstantPool(); |
212 return new JavaClass(class_name_index, superclass_name_index, file_name, major, minor, |
220 return new JavaClass(class_name_index, superclass_name_index, file_name, major, minor, |
213 super.getAccessFlags(), _cp, interfaces, fields, methods, attributes); |
221 super.getAccessFlags(), _cp, interfaces, fields, methods, attributes); |
214 } |
222 } |
215 |
223 |
|
224 |
216 /** |
225 /** |
217 * Add an interface to this class, i.e., this class has to implement it. |
226 * Add an interface to this class, i.e., this class has to implement it. |
218 * |
|
219 * @param name interface to implement (fully qualified class name) |
227 * @param name interface to implement (fully qualified class name) |
220 */ |
228 */ |
221 public final void addInterface(final String name) { |
229 public void addInterface( final String name ) { |
222 interface_vec.add(name); |
230 interface_vec.add(name); |
223 } |
231 } |
224 |
232 |
|
233 |
225 /** |
234 /** |
226 * Remove an interface from this class. |
235 * Remove an interface from this class. |
227 * |
|
228 * @param name interface to remove (fully qualified name) |
236 * @param name interface to remove (fully qualified name) |
229 */ |
237 */ |
230 public void removeInterface(final String name) { |
238 public void removeInterface( final String name ) { |
231 interface_vec.remove(name); |
239 interface_vec.remove(name); |
232 } |
240 } |
|
241 |
233 |
242 |
234 /** |
243 /** |
235 * @return major version number of class file |
244 * @return major version number of class file |
236 */ |
245 */ |
237 public int getMajor() { |
246 public int getMajor() { |
238 return major; |
247 return major; |
239 } |
248 } |
240 |
249 |
241 /** |
250 |
242 * Set major version number of class file, default value is 45 (JDK 1.1) |
251 /** Set major version number of class file, default value is 45 (JDK 1.1) |
243 * |
|
244 * @param major major version number |
252 * @param major major version number |
245 */ |
253 */ |
246 public void setMajor(final int major) { // TODO could be package-protected - only called by test code |
254 public void setMajor( final int major ) { // TODO could be package-protected - only called by test code |
247 this.major = major; |
255 this.major = major; |
248 } |
256 } |
249 |
257 |
250 /** |
258 |
251 * Set minor version number of class file, default value is 3 (JDK 1.1) |
259 /** Set minor version number of class file, default value is 3 (JDK 1.1) |
252 * |
|
253 * @param minor minor version number |
260 * @param minor minor version number |
254 */ |
261 */ |
255 public void setMinor(final int minor) { // TODO could be package-protected - only called by test code |
262 public void setMinor( final int minor ) { // TODO could be package-protected - only called by test code |
256 this.minor = minor; |
263 this.minor = minor; |
257 } |
264 } |
258 |
265 |
259 /** |
266 /** |
260 * @return minor version number of class file |
267 * @return minor version number of class file |
261 */ |
268 */ |
262 public int getMinor() { |
269 public int getMinor() { |
263 return minor; |
270 return minor; |
264 } |
271 } |
265 |
272 |
|
273 |
266 /** |
274 /** |
267 * Add an attribute to this class. |
275 * Add an attribute to this class. |
268 * |
|
269 * @param a attribute to add |
276 * @param a attribute to add |
270 */ |
277 */ |
271 public final void addAttribute(final Attribute a) { |
278 public void addAttribute( final Attribute a ) { |
272 attribute_vec.add(a); |
279 attribute_vec.add(a); |
273 } |
280 } |
274 |
281 |
275 public final void addAnnotationEntry(final AnnotationEntryGen a) { |
282 public void addAnnotationEntry(final AnnotationEntryGen a) { |
276 annotation_vec.add(a); |
283 annotation_vec.add(a); |
277 } |
284 } |
278 |
285 |
|
286 |
279 /** |
287 /** |
280 * Add a method to this class. |
288 * Add a method to this class. |
281 * |
|
282 * @param m method to add |
289 * @param m method to add |
283 */ |
290 */ |
284 public final void addMethod(final Method m) { |
291 public void addMethod( final Method m ) { |
285 method_vec.add(m); |
292 method_vec.add(m); |
286 } |
293 } |
|
294 |
287 |
295 |
288 /** |
296 /** |
289 * Convenience method. |
297 * Convenience method. |
290 * |
298 * |
291 * Add an empty constructor to this class that does nothing but calling |
299 * Add an empty constructor to this class that does nothing but calling super(). |
292 * super(). |
|
293 * |
|
294 * @param access_flags rights for constructor |
300 * @param access_flags rights for constructor |
295 */ |
301 */ |
296 public void addEmptyConstructor(final int access_flags) { |
302 public void addEmptyConstructor( final int access_flags ) { |
297 final InstructionList il = new InstructionList(); |
303 final InstructionList il = new InstructionList(); |
298 il.append(InstructionConst.THIS); // Push `this' |
304 il.append(InstructionConst.THIS); // Push `this' |
299 il.append(new INVOKESPECIAL(cp.addMethodref(super_class_name, "<init>", "()V"))); |
305 il.append(new INVOKESPECIAL(cp.addMethodref(super_class_name, "<init>", "()V"))); |
300 il.append(InstructionConst.RETURN); |
306 il.append(InstructionConst.RETURN); |
301 final MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null, "<init>", |
307 final MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null, "<init>", |
302 class_name, il, cp); |
308 class_name, il, cp); |
303 mg.setMaxStack(1); |
309 mg.setMaxStack(1); |
304 addMethod(mg.getMethod()); |
310 addMethod(mg.getMethod()); |
305 } |
311 } |
306 |
312 |
|
313 |
307 /** |
314 /** |
308 * Add a field to this class. |
315 * Add a field to this class. |
309 * |
|
310 * @param f field to add |
316 * @param f field to add |
311 */ |
317 */ |
312 public final void addField(final Field f) { |
318 public void addField( final Field f ) { |
313 field_vec.add(f); |
319 field_vec.add(f); |
314 } |
320 } |
315 |
321 |
316 public boolean containsField(final Field f) { |
322 |
|
323 public boolean containsField( final Field f ) { |
317 return field_vec.contains(f); |
324 return field_vec.contains(f); |
318 } |
325 } |
319 |
326 |
320 /** |
327 |
321 * @return field object with given name, or null |
328 /** @return field object with given name, or null |
322 */ |
329 */ |
323 public Field containsField(final String name) { |
330 public Field containsField( final String name ) { |
324 for (final Field f : field_vec) { |
331 for (final Field f : field_vec) { |
325 if (f.getName().equals(name)) { |
332 if (f.getName().equals(name)) { |
326 return f; |
333 return f; |
327 } |
334 } |
328 } |
335 } |
329 return null; |
336 return null; |
330 } |
337 } |
331 |
338 |
332 /** |
339 |
333 * @return method object with given name and signature, or null |
340 /** @return method object with given name and signature, or null |
334 */ |
341 */ |
335 public Method containsMethod(final String name, final String signature) { |
342 public Method containsMethod( final String name, final String signature ) { |
336 for (final Method m : method_vec) { |
343 for (final Method m : method_vec) { |
337 if (m.getName().equals(name) && m.getSignature().equals(signature)) { |
344 if (m.getName().equals(name) && m.getSignature().equals(signature)) { |
338 return m; |
345 return m; |
339 } |
346 } |
340 } |
347 } |
341 return null; |
348 return null; |
342 } |
349 } |
343 |
350 |
|
351 |
344 /** |
352 /** |
345 * Remove an attribute from this class. |
353 * Remove an attribute from this class. |
346 * |
|
347 * @param a attribute to remove |
354 * @param a attribute to remove |
348 */ |
355 */ |
349 public void removeAttribute(final Attribute a) { |
356 public void removeAttribute( final Attribute a ) { |
350 attribute_vec.remove(a); |
357 attribute_vec.remove(a); |
351 } |
358 } |
352 |
359 |
|
360 |
353 /** |
361 /** |
354 * Remove a method from this class. |
362 * Remove a method from this class. |
355 * |
|
356 * @param m method to remove |
363 * @param m method to remove |
357 */ |
364 */ |
358 public void removeMethod(final Method m) { |
365 public void removeMethod( final Method m ) { |
359 method_vec.remove(m); |
366 method_vec.remove(m); |
360 } |
367 } |
361 |
368 |
362 /** |
369 |
363 * Replace given method with new one. If the old one does not exist add the |
370 /** Replace given method with new one. If the old one does not exist |
364 * new_ method to the class anyway. |
371 * add the new_ method to the class anyway. |
365 */ |
372 */ |
366 public void replaceMethod(final Method old, final Method new_) { |
373 public void replaceMethod( final Method old, final Method new_ ) { |
367 if (new_ == null) { |
374 if (new_ == null) { |
368 throw new ClassGenException("Replacement method must not be null"); |
375 throw new ClassGenException("Replacement method must not be null"); |
369 } |
376 } |
370 final int i = method_vec.indexOf(old); |
377 final int i = method_vec.indexOf(old); |
371 if (i < 0) { |
378 if (i < 0) { |
389 } else { |
396 } else { |
390 field_vec.set(i, new_); |
397 field_vec.set(i, new_); |
391 } |
398 } |
392 } |
399 } |
393 |
400 |
|
401 |
394 /** |
402 /** |
395 * Remove a field to this class. |
403 * Remove a field to this class. |
396 * |
|
397 * @param f field to remove |
404 * @param f field to remove |
398 */ |
405 */ |
399 public void removeField(final Field f) { |
406 public void removeField( final Field f ) { |
400 field_vec.remove(f); |
407 field_vec.remove(f); |
401 } |
408 } |
|
409 |
402 |
410 |
403 public String getClassName() { |
411 public String getClassName() { |
404 return class_name; |
412 return class_name; |
405 } |
413 } |
406 |
414 |
|
415 |
407 public String getSuperclassName() { |
416 public String getSuperclassName() { |
408 return super_class_name; |
417 return super_class_name; |
409 } |
418 } |
410 |
419 |
|
420 |
411 public String getFileName() { |
421 public String getFileName() { |
412 return file_name; |
422 return file_name; |
413 } |
423 } |
414 |
424 |
415 public void setClassName(final String name) { |
425 |
|
426 public void setClassName( final String name ) { |
416 class_name = name.replace('/', '.'); |
427 class_name = name.replace('/', '.'); |
417 class_name_index = cp.addClass(name); |
428 class_name_index = cp.addClass(name); |
418 } |
429 } |
419 |
430 |
420 public void setSuperclassName(final String name) { |
431 |
|
432 public void setSuperclassName( final String name ) { |
421 super_class_name = name.replace('/', '.'); |
433 super_class_name = name.replace('/', '.'); |
422 superclass_name_index = cp.addClass(name); |
434 superclass_name_index = cp.addClass(name); |
423 } |
435 } |
424 |
436 |
|
437 |
425 public Method[] getMethods() { |
438 public Method[] getMethods() { |
426 return method_vec.toArray(new Method[method_vec.size()]); |
439 return method_vec.toArray(new Method[method_vec.size()]); |
427 } |
440 } |
428 |
441 |
429 public void setMethods(final Method[] methods) { |
442 |
|
443 public void setMethods( final Method[] methods ) { |
430 method_vec.clear(); |
444 method_vec.clear(); |
431 for (final Method method : methods) { |
445 for (final Method method : methods) { |
432 addMethod(method); |
446 addMethod(method); |
433 } |
447 } |
434 } |
448 } |
435 |
449 |
436 public void setMethodAt(final Method method, final int pos) { |
450 |
|
451 public void setMethodAt( final Method method, final int pos ) { |
437 method_vec.set(pos, method); |
452 method_vec.set(pos, method); |
438 } |
453 } |
439 |
454 |
440 public Method getMethodAt(final int pos) { |
455 |
|
456 public Method getMethodAt( final int pos ) { |
441 return method_vec.get(pos); |
457 return method_vec.get(pos); |
442 } |
458 } |
|
459 |
443 |
460 |
444 public String[] getInterfaceNames() { |
461 public String[] getInterfaceNames() { |
445 final int size = interface_vec.size(); |
462 final int size = interface_vec.size(); |
446 final String[] interfaces = new String[size]; |
463 final String[] interfaces = new String[size]; |
447 interface_vec.toArray(interfaces); |
464 interface_vec.toArray(interfaces); |
448 return interfaces; |
465 return interfaces; |
449 } |
466 } |
450 |
467 |
|
468 |
451 public int[] getInterfaces() { |
469 public int[] getInterfaces() { |
452 final int size = interface_vec.size(); |
470 final int size = interface_vec.size(); |
453 final int[] interfaces = new int[size]; |
471 final int[] interfaces = new int[size]; |
454 for (int i = 0; i < size; i++) { |
472 for (int i = 0; i < size; i++) { |
455 interfaces[i] = cp.addClass(interface_vec.get(i)); |
473 interfaces[i] = cp.addClass(interface_vec.get(i)); |
456 } |
474 } |
457 return interfaces; |
475 return interfaces; |
458 } |
476 } |
459 |
477 |
|
478 |
460 public Field[] getFields() { |
479 public Field[] getFields() { |
461 return field_vec.toArray(new Field[field_vec.size()]); |
480 return field_vec.toArray(new Field[field_vec.size()]); |
462 } |
481 } |
|
482 |
463 |
483 |
464 public Attribute[] getAttributes() { |
484 public Attribute[] getAttributes() { |
465 return attribute_vec.toArray(new Attribute[attribute_vec.size()]); |
485 return attribute_vec.toArray(new Attribute[attribute_vec.size()]); |
466 } |
486 } |
467 |
487 |
468 // J5TODO: Should we make calling unpackAnnotations() lazy and put it in here? |
488 // J5TODO: Should we make calling unpackAnnotations() lazy and put it in here? |
469 public AnnotationEntryGen[] getAnnotationEntries() { |
489 public AnnotationEntryGen[] getAnnotationEntries() { |
470 return annotation_vec.toArray(new AnnotationEntryGen[annotation_vec.size()]); |
490 return annotation_vec.toArray(new AnnotationEntryGen[annotation_vec.size()]); |
471 } |
491 } |
472 |
492 |
|
493 |
473 public ConstantPoolGen getConstantPool() { |
494 public ConstantPoolGen getConstantPool() { |
474 return cp; |
495 return cp; |
475 } |
496 } |
476 |
497 |
477 public void setConstantPool(final ConstantPoolGen constant_pool) { |
498 |
|
499 public void setConstantPool( final ConstantPoolGen constant_pool ) { |
478 cp = constant_pool; |
500 cp = constant_pool; |
479 } |
501 } |
480 |
502 |
481 public void setClassNameIndex(final int class_name_index) { |
503 |
|
504 public void setClassNameIndex( final int class_name_index ) { |
482 this.class_name_index = class_name_index; |
505 this.class_name_index = class_name_index; |
483 class_name = cp.getConstantPool().getConstantString(class_name_index, |
506 class_name = cp.getConstantPool().getConstantString(class_name_index, |
484 Const.CONSTANT_Class).replace('/', '.'); |
507 Const.CONSTANT_Class).replace('/', '.'); |
485 } |
508 } |
486 |
509 |
487 public void setSuperclassNameIndex(final int superclass_name_index) { |
510 |
|
511 public void setSuperclassNameIndex( final int superclass_name_index ) { |
488 this.superclass_name_index = superclass_name_index; |
512 this.superclass_name_index = superclass_name_index; |
489 super_class_name = cp.getConstantPool().getConstantString(superclass_name_index, |
513 super_class_name = cp.getConstantPool().getConstantString(superclass_name_index, |
490 Const.CONSTANT_Class).replace('/', '.'); |
514 Const.CONSTANT_Class).replace('/', '.'); |
491 } |
515 } |
492 |
516 |
|
517 |
493 public int getSuperclassNameIndex() { |
518 public int getSuperclassNameIndex() { |
494 return superclass_name_index; |
519 return superclass_name_index; |
495 } |
520 } |
496 |
521 |
|
522 |
497 public int getClassNameIndex() { |
523 public int getClassNameIndex() { |
498 return class_name_index; |
524 return class_name_index; |
499 } |
525 } |
500 |
526 |
501 private List<ClassObserver> observers; |
527 private List<ClassObserver> observers; |
502 |
528 |
503 /** |
529 |
504 * Add observer for this object. |
530 /** Add observer for this object. |
505 */ |
531 */ |
506 public void addObserver(final ClassObserver o) { |
532 public void addObserver( final ClassObserver o ) { |
507 if (observers == null) { |
533 if (observers == null) { |
508 observers = new ArrayList<>(); |
534 observers = new ArrayList<>(); |
509 } |
535 } |
510 observers.add(o); |
536 observers.add(o); |
511 } |
537 } |
512 |
538 |
513 /** |
539 |
514 * Remove observer for this object. |
540 /** Remove observer for this object. |
515 */ |
541 */ |
516 public void removeObserver(final ClassObserver o) { |
542 public void removeObserver( final ClassObserver o ) { |
517 if (observers != null) { |
543 if (observers != null) { |
518 observers.remove(o); |
544 observers.remove(o); |
519 } |
545 } |
520 } |
546 } |
521 |
547 |
522 /** |
548 |
523 * Call notify() method on all observers. This method is not called |
549 /** Call notify() method on all observers. This method is not called |
524 * automatically whenever the state has changed, but has to be called by the |
550 * automatically whenever the state has changed, but has to be |
525 * user after he has finished editing the object. |
551 * called by the user after he has finished editing the object. |
526 */ |
552 */ |
527 public void update() { |
553 public void update() { |
528 if (observers != null) { |
554 if (observers != null) { |
529 for (final ClassObserver observer : observers) { |
555 for (final ClassObserver observer : observers) { |
530 observer.notify(this); |
556 observer.notify(this); |
531 } |
557 } |
532 } |
558 } |
533 } |
559 } |
|
560 |
534 |
561 |
535 @Override |
562 @Override |
536 public Object clone() { |
563 public Object clone() { |
537 try { |
564 try { |
538 return super.clone(); |
565 return super.clone(); |
539 } catch (final CloneNotSupportedException e) { |
566 } catch (final CloneNotSupportedException e) { |
540 throw new Error("Clone Not Supported"); // never happens |
567 throw new Error("Clone Not Supported"); // never happens |
541 } |
568 } |
542 } |
569 } |
543 |
570 |
|
571 |
544 /** |
572 /** |
545 * @return Comparison strategy object |
573 * @return Comparison strategy object |
546 */ |
574 */ |
547 public static BCELComparator getComparator() { |
575 public static BCELComparator getComparator() { |
548 return _cmp; |
576 return _cmp; |
549 } |
577 } |
550 |
578 |
|
579 |
551 /** |
580 /** |
552 * @param comparator Comparison strategy object |
581 * @param comparator Comparison strategy object |
553 */ |
582 */ |
554 public static void setComparator(final BCELComparator comparator) { |
583 public static void setComparator( final BCELComparator comparator ) { |
555 _cmp = comparator; |
584 _cmp = comparator; |
556 } |
585 } |
557 |
586 |
558 /** |
587 |
559 * Return value as defined by given BCELComparator strategy. By default two |
588 /** |
560 * ClassGen objects are said to be equal when their class names are equal. |
589 * Return value as defined by given BCELComparator strategy. |
|
590 * By default two ClassGen objects are said to be equal when |
|
591 * their class names are equal. |
561 * |
592 * |
562 * @see java.lang.Object#equals(java.lang.Object) |
593 * @see java.lang.Object#equals(java.lang.Object) |
563 */ |
594 */ |
564 @Override |
595 @Override |
565 public boolean equals(final Object obj) { |
596 public boolean equals( final Object obj ) { |
566 return _cmp.equals(this, obj); |
597 return _cmp.equals(this, obj); |
567 } |
598 } |
568 |
599 |
569 /** |
600 |
570 * Return value as defined by given BCELComparator strategy. By default |
601 /** |
571 * return the hashcode of the class name. |
602 * Return value as defined by given BCELComparator strategy. |
|
603 * By default return the hashcode of the class name. |
572 * |
604 * |
573 * @see java.lang.Object#hashCode() |
605 * @see java.lang.Object#hashCode() |
574 */ |
606 */ |
575 @Override |
607 @Override |
576 public int hashCode() { |
608 public int hashCode() { |