Introduction

Introspection is an important feature of the Java language. Using introspection we can get the internal information of a class at run-time. This information includes methods, fields, constructors and so on. One use of introspection is in developing applications that use plug-ins. An application can determine the constructors, methods, and fields of the plug-in classes and use this information at run-time. Other uses of introspection are in creating Java Beans and developing Javadocs.

Background

The class to be introspected can be obtained using the forName() method of the java.lang.Class class. We can get an array of all the methods of a class using the getMethods() method of java.lang.Class. Similarly, we can use the getConstructors() and getFields() methods to get all the constructors and fields, respectively. The parameters of the methods and constructors can be obtained by using the getParameterTypes() method of the Method or Constructor classes.

Using the Code

In the code, I have created a GUI consisting of a TextField item to accept the name of the class to be introspected and three JList items to display the methods, fields, and constructors of the class.

lblClassName=new JLabel("Enter a class name: ");
txtClassName=new JTextField(20);
// For accepting class name

// For listing methods
lstMethods=new JList();
// For listing fields
lstFields=new JList();
// For listing constructors
lstConstructors=new JList();
lstMethods.setToolTipText("Methods");
lstFields.setToolTipText("Fields");
lstConstructors.setToolTipText("Constructors"); 

// Adding panels to frame
getContentPane().add(panelInput,"North");
getContentPane().add(panelOutput,"Center");

// Adding controls to panels
panelInput.add(lblClassName);
panelInput.add(txtClassName);
panelInput.add(btnIntrospect);
JScrollPane pane1=new JScrollPane(lstMethods);
panelOutput.add(pane1);
JScrollPane pane2=new JScrollPane(lstFields);
panelOutput.add(pane2);
JScrollPane pane3=new JScrollPane(lstConstructors);
panelOutput.add(pane3);

Here is the implementation of the actionPerformed method:

public void actionPerformed(ActionEvent e)
{
 if(e.getSource()==txtClassName||e.getSource()==btnIntrospect)
 {
    if(txtClassName.getText().trim().length()==0)
    // Show error if class name not entered
    {
       JOptionPane.showMessageDialog(this,
         "Please enter a Class or Interface name","Error",
         JOptionPane.ERROR_MESSAGE);
       return;
    }
    try
    {
       Class c=Class.forName(txtClassName.getText());
       // Get class name entered by user

Here is how we get the methods information:

// Get all methods
Method[] methods=c.getMethods();
StringBuffer buffer=new StringBuffer();
// Create a string buffer to store method names to be displayed in JList
if(methods.length>0)
{
   // Get the first method
   Method m=methods[0];
   // Find return type of the method
   String t=m.getReturnType().toString();
   if(t.startsWith("class"))
   {
      t=t.substring(6);
      // Remove the leading word "class"
   }
   buffer.append(t+" "+m.getName()+"("+params(m)+")");
   // Add method names to string buffer.
   // The user-defined params() method returns parameters of the function.
}
int ctr=1;
while(ctr<methods.length)
// Repeat same process for all methods
{
   Method m=methods[ctr];
   String t=m.getReturnType().toString();
   if(t.startsWith("class"))
   {
      t=t.substring(6);
   }
   // Add all method names to the string buffer separated with ";"
   buffer.append(";"+t+" "+m.getName()+"("+params(m)+")");               
   ctr++;
}
lstMethods.setListData(buffer.toString().split(";"));
// Split method names and display them on JList

Getting the fields information is as follows:

Field[] fields=c.getFields(); // Get all fields
buffer=new StringBuffer();
if(fields.length>0)
{
   // Get the first field
   Field f=fields[0];
   // Find data type of the field 
   String t=f.getGenericType().toString();
   if(t.startsWith("class"))
   {
      t=t.substring(6);
   }
   buffer.append(t+" "+f.getName());
}
ctr=1;
while(ctr<fields.length)
// Repeat same process for all fields
{
   Field f=fields[ctr];
   String t=f.getGenericType().toString();
   if(t.startsWith("class"))
   {
      t=t.substring(6);
   }
   buffer.append(";"+t+" "+f.getName());
   // Add all field names to the string buffer separated with ";"

   ctr++;
}
lstFields.setListData(buffer.toString().split(";"));
// Split field names and display them on JList

This is how we get the constructors information:

    // Get all constructors
    Constructor[] constructors=c.getConstructors();
    buffer=new StringBuffer();
    if(constructors.length>0)
    {
       // Get the first constructor
       Constructor s=constructors[0];
       buffer.append(s.getName()+"("+cParams(s)+")");
       // Add constructor names to string buffer.
       // The user-defined cParams() method
       // returns parameters of the constructor.
    }
    ctr=1;
    while(ctr<constructors.length)
    // Repeat same process for all constructors
    {
       Constructor s=constructors[ctr];
       buffer.append(";"+s.getName()+"("+cParams(s)+")");
       // Add all constructor names to the string buffer separated with ";"

       ctr++;
    }
    lstConstructors.setListData(buffer.toString().split(";"));
    // Split constructor names and display them on JList
}
catch(ClassNotFoundException ex)
{
    JOptionPane.showMessageDialog(this, 
       "Invalid Class or Interface name. Check Classpath.",
       "Error",JOptionPane.ERROR_MESSAGE);
    // Show error if invalid class or interface name entered
}

The code for getting the parameter types for methods is listed below:

public String params(Method m)
{
  // Get all parameter types
  Class[] parameters=m.getParameterTypes();
  StringBuffer buffer=new StringBuffer();
  if(parameters.length>0)
  {
     // Get first parameter type
     Class c=parameters[0];
     buffer.append(c.getName());
     // Add to buffer
  }
  int ctr=1;
  while(ctr<parameters.length)
  // Repeat for all parameters            
  {
     Class c=parameters[ctr];
     buffer.append(","+c.getName());
     ctr++;
  }
  return buffer.toString();
  // Return all parameter types
}

Here is how we get the parameter types for the constructors:

public String cParams(Constructor s)
{
  // Get all parameter types
  Class[] parameters=s.getParameterTypes();
  StringBuffer buffer=new StringBuffer();
  if(parameters.length>0)
  {
     // Get first parameter type
     Class c=parameters[0];
     buffer.append(c.getName());
     // Add to buffer
  }
  int ctr=1;
  while(ctr<parameters.length)
  // Repeat for all parameters
  {
     Class c=parameters[ctr];
     buffer.append(","+c.getName());
     ctr++;
  }
  return buffer.toString();
  // Return all parameter types
}

Points of Interest

The program can be compiled and run from the command line as follows:

javac MyIntrospector.java
java MyIntrospector

I have also created an executable jar file called MyIntrospector.jar. This file can be executed by double clicking on it in Windows Explorer.

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"