CSC/ECE 517 Fall 2010/ch1 1c JF: Difference between revisions
No edit summary |
No edit summary |
||
Line 25: | Line 25: | ||
In a language with a reflective package, like Java, | In a language with a reflective package, like Java, the package is not automatically included in the functionality. It must be imported with: | ||
import java.lang.reflect.*; | import java.lang.reflect.*; | ||
Also, for any given object ''A'', a separate class object ''B'', is created and that ''B'' contains the information about ''A''. For example, with the given class: | |||
public class Sample { | public class Sample { | ||
Line 35: | Line 38: | ||
The class information can be found by invoking: | The class information can be found by invoking: | ||
Sample samp = new Sample(); | Sample samp = new Sample(); //Create an instance of Sample | ||
Class sampClass = | Class sampClass = samp.getClass(); //Create a class object for instance of Sample | ||
System.out.println( | System.out.println(sampClass.getName()); //Display class name | ||
and the method list can be found with: | and the method list can be found with: | ||
Method[] meth = sampClass.getMethods(); | Method[] meth = sampClass.getMethods(); //Return array of method objects for Class object of Sample instance | ||
for (int i = 0; i < m.length; i++){ | for (int i = 0; i < m.length; i++){ | ||
System.out.println(meth[i]); | System.out.println(meth[i]); //Display methods | ||
} | } | ||
In Java, a Class object is created to access class information, and | In Java, a Class object is created to access class information, and method information for the object is stored in method objects that can be accessed via the Class object. | ||
= Intercessive Features = | = Intercessive Features = | ||
Another important feature granted by reflection, is the ability for dynamic implementation of code. This can take many forms, including object creation and method calling at runtime. Again, in an inherently reflective language, these calls are made directly on the object. However, when a language has a reflective package to handle reflective features, the calls are directed through a separate object. | |||
For example, in Ruby, this | |||
For example, in Ruby, this class: | |||
class Sample | class Sample | ||
Line 67: | Line 71: | ||
end | end | ||
defines three methods that print different numbers depending on which method is called. Without reflection, calls to these methods could not be changed at runtime. However, reflection allows the method calls to depend on string values that do not have to be initialized until runtime as seen in the following code: | |||
samp = Sample.new #Create an instance of the Sample class | |||
option="printOne" | option="printOne" | ||
samp.send(option) #printOne method is called | |||
option="printThree" | option="printThree" | ||
samp.send(option) #printThree method is called | |||
What is printed from this code depends on the value of "option", which might not have a value until runtime. In this code, the call: | |||
s.send(option) | s.send(option) | ||
is the same, but the "option" value has changed and that is what determines the method that is called. This same feature exists in languages with reflective packages, but again it is accessed indirectly. For example, in Java, a similar class: | |||
is the same, but the "option" value has changed and that is what determines the method that is called. This same | |||
public class Sample { | public class Sample { | ||
Line 93: | Line 99: | ||
public void printThree(){ | public void printThree(){ | ||
System.out.println("3"); | System.out.println("3"); | ||
} | } | ||
} | } | ||
handles reflection by accessing the method through a Class object and Method object: | |||
Sample samp = new Sample(); | |||
Class sampClass = samp.getClass(); | |||
String option = "printOne"; | |||
try { | |||
Method meth = sampClass.getMethod(option); | |||
m.invoke(s, null); | |||
} catch (NoSuchMethodException nsme){ | |||
nsme.printStackTrace(); | |||
} catch (IllegalAccessException iae){ | |||
iae.printStackTrace(); | |||
} catch (InvocationTargetException ite){ | |||
ite.printStackTrace(); | |||
} | |||
option = "printThree"; | |||
try { | |||
Method m = sampClass.getMethod(option); | |||
m.invoke(s, null); | |||
} catch (NoSuchMethodException nsme){ | |||
nsme.printStackTrace(); | |||
} catch (IllegalAccessException iae){ | |||
iae.printStackTrace(); | |||
} catch (InvocationTargetException ite){ | |||
ite.printStackTrace(); | |||
} | |||
The result of this code is the same as the Ruby code, but to achieve it a Class object was created to retrieve information about the original object, and a Method object was created to retrieve method information from the Class object. | |||
= References = | = References = |
Revision as of 00:53, 9 September 2010
Reflective Language Features vs Reflective Packages
Introduction
Reflection allows a program to access information about its objects (introspection) and to modify program behavior based on that information (intercession 3). Some languages, like Ruby and SmallTalk, are inherently reflective, while other languages, like C# and Java, implement reflective language by including a reflective package. In a reflective language, information about an object or class is accessed directly. In languages with reflective packages, the information is accessed by creating another object that can access that information. There are many features that reflection gives a language. Implementation for these features differs depending on whether it is an inherently reflective language, or a language with a reflective package.
Introspective Features
One of the most powerful features that reflection provides is the ability, given an object, to know what kind of object it is, and what methods it contains. In a reflective language, like Ruby, that is done by directly querying the object. For example, with the given class:
class Sample #empty class end s = Sample.new
The call:
puts s.class
will list "Sample" as the class and the call:
puts s.methods
will list the methods that Sample has (which will include all the methods in Sample's superclass – Object).
In a language with a reflective package, like Java, the package is not automatically included in the functionality. It must be imported with:
import java.lang.reflect.*;
Also, for any given object A, a separate class object B, is created and that B contains the information about A. For example, with the given class:
public class Sample { //Empty class }
The class information can be found by invoking:
Sample samp = new Sample(); //Create an instance of Sample Class sampClass = samp.getClass(); //Create a class object for instance of Sample System.out.println(sampClass.getName()); //Display class name
and the method list can be found with:
Method[] meth = sampClass.getMethods(); //Return array of method objects for Class object of Sample instance for (int i = 0; i < m.length; i++){ System.out.println(meth[i]); //Display methods }
In Java, a Class object is created to access class information, and method information for the object is stored in method objects that can be accessed via the Class object.
Intercessive Features
Another important feature granted by reflection, is the ability for dynamic implementation of code. This can take many forms, including object creation and method calling at runtime. Again, in an inherently reflective language, these calls are made directly on the object. However, when a language has a reflective package to handle reflective features, the calls are directed through a separate object.
For example, in Ruby, this class:
class Sample def printOne puts 1 end def printTwo puts 2 end def printThree puts 3 end end
defines three methods that print different numbers depending on which method is called. Without reflection, calls to these methods could not be changed at runtime. However, reflection allows the method calls to depend on string values that do not have to be initialized until runtime as seen in the following code:
samp = Sample.new #Create an instance of the Sample class option="printOne" samp.send(option) #printOne method is called option="printThree" samp.send(option) #printThree method is called
What is printed from this code depends on the value of "option", which might not have a value until runtime. In this code, the call:
s.send(option)
is the same, but the "option" value has changed and that is what determines the method that is called. This same feature exists in languages with reflective packages, but again it is accessed indirectly. For example, in Java, a similar class:
public class Sample { public void printOne(){ System.out.println("1"); } public void printTwo(){ System.out.println("2"); } public void printThree(){ System.out.println("3"); } }
handles reflection by accessing the method through a Class object and Method object:
Sample samp = new Sample(); Class sampClass = samp.getClass(); String option = "printOne"; try { Method meth = sampClass.getMethod(option); m.invoke(s, null); } catch (NoSuchMethodException nsme){ nsme.printStackTrace(); } catch (IllegalAccessException iae){ iae.printStackTrace(); } catch (InvocationTargetException ite){ ite.printStackTrace(); } option = "printThree"; try { Method m = sampClass.getMethod(option); m.invoke(s, null); } catch (NoSuchMethodException nsme){ nsme.printStackTrace(); } catch (IllegalAccessException iae){ iae.printStackTrace(); } catch (InvocationTargetException ite){ ite.printStackTrace(); }
The result of this code is the same as the Ruby code, but to achieve it a Class object was created to retrieve information about the original object, and a Method object was created to retrieve method information from the Class object.
References
[1] Reflection-Oriented Programming
[2] Procedural Reflection in Programming Languages
[3] Evolving a Reflective Language Lessons Learned from Implementing Traits
[4] Java Reflection Explained Simply
[6] Thomas, Dave with Chad Fowler and Andy Hunt. Programming Ruby. North Carolina: The Pragmatic Bookshelf, 2005.