在 Java 中使用内省





4.00/5 (2投票s)
本文描述了如何在 Java 中使用内省获取类的内部细节。
引言
内省是 Java 语言的一项重要特性。 使用内省,我们可以在运行时获取类的内部信息。 这些信息包括方法、字段、构造函数等。 内省的一个用途是在开发使用插件的应用程序中。 应用程序可以确定插件类的构造函数、方法和字段,并在运行时使用这些信息。 内省的其他用途包括创建 Java Bean 和开发 Javadoc。
背景
可以使用 java.lang.Class
类的 forName()
方法获取要内省的类。 我们可以使用 java.lang.Class
的 getMethods()
方法获取类中所有方法的一个数组。 类似地,我们可以使用 getConstructors()
和 getFields()
方法分别获取所有构造函数和字段。 可以使用 Method
或 Constructor
类的 getParameterTypes()
方法获取方法和构造函数的参数。
Using the Code
在代码中,我创建了一个 GUI,包含一个 TextField
项来接受要内省的类名,以及三个 JList
项来显示该类的所有方法、字段和构造函数。
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);
以下是 actionPerformed
方法的实现
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
以下是如何获取方法信息
// 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
获取字段信息如下
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
这是我们获取构造函数信息的方式
// 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
}
获取方法参数类型的代码如下所示
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
}
以下是如何获取构造函数的参数类型
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
}
关注点
该程序可以从命令行编译和运行如下
javac MyIntrospector.java
java MyIntrospector
我还创建了一个名为 MyIntrospector.jar 的可执行 jar 文件。 可以通过在 Windows 资源管理器中双击该文件来执行它。