LAB 15 - Java Reflection

Goal

Given Note.java, ViolinNote.java HornNote.java

Java Reflection

Reflection gives your code access to internal information for classes loaded into the JVM and allows you to write code that works with classes selected during execution, not in the source code. You'll want to use the reflection API if you are writing development tools such as debuggers, class browsers, and GUI builders. With the reflection API you can:

For every loaded class, the Java Runtime Environment(JRE) maintains an associated Class object The Class object “reflects” the class it represents. We can use the Class object to discover information about a loaded class like name, modifiers (public, abstract, final) , superclasses, implemented interfaces, fields, methods, constructors. Furthemorewe can instantiate classes and invoke their methods via Class object. For accessing the Class object for a loaded class there are three methods:

For introspecting (examining) a class via its Class object

RTTI

Consider the following code. What is the output?

				 Note note;
				 note = new HornNote();
				 Class c = note.getClass();
				 System.out.println("class of note = " + c.getName());
				 note = new ViolinNote();
				 c = note.getClass();
				 System.out.println("now class of note = " + c.getName());
				 

We could also reassign c to reference any super class of ViolinNote. What is the output of the following code:

				 c = c.getSuperclass();
				 System.out.println("base class of note = " + c.getName());
				 c = c.getSuperclass();
				 System.out.println("base of base class of note = " + c.getName());
				 

Introspection

We can also find out about the methods and fields of a class. Assume that c still references an object of the ViolinNote class. Then the following loop prints out the names of all of the ViolinClass methods:

				 Method methods[] = c.getMethods();
				 for(int i = 0; i < methods.length; i++)
				 System.out.println(methods[i].getName());
				 

What is the output? To print the names of the ViolinNote fields as well as their current values in the particular ViolinNote object referenced by note:

				 Field fields[] = c.getFields();
				 try {
				 	 for(int i = 0; i < fields.length; i++) {
					 		 System.out.print(fields[i].getName() + " = ");
							 System.out.println(fields[i].getInt(note));
					}
				} catch(Exception e) {
				  // handle e
				 }
				 

What is the output?

Invoking Method Objects

We can ask a Method object to invoke the method it represents.(Of course we must provide it with the implicit and explicit arguments.) For example, let's create a generic Note object, then call its play() method using reflection:

				 note = new Note();
				 c = note.getClass();
				 Method meth = c.getMethod("play", null);
				 meth.invoke(note, null);
				 
What is the output?

Dynamic Instantiation

Consider a universal instrument that can imitate all other types of instruments. This is done with a play() method that expects as its input only the name of the type of note to play:

				class UniversalInstrument {
					  public void play(String noteType) {
					  		 try {
							 	 Class c = Class.forName(noteType); // find & load a class
								 Note note = (Note) c.newInstance();
								 note.play();
								 } catch (Exception e) {
								 // handle e here
								 }
								 }
								 }
								 

After creating a universal instrument, our test driver calls the play()method twice. The first time the string "ViolinNote" is the argument. The second time the string "HornNote" is the argument:

				UniversalInstrument inst = new UniversalInstrument();
				String noteType;
				noteType = "ViolinNote";
				inst.play(noteType);
				noteType = "HornNote";
				inst.play(noteType);
				

What is the output?