因此,通过阅读一些文章,我从中得到的消息是,可以实时修改字段并为类设置值,而无需重新编译。
那么,是否可以对第三方java库创建的类执行此操作,而这些类没有可用的源代码/是否可以在运行时使用反射来修改类实例?
反射在其他哪些场景中常用?
我正在努力理解反思是如何适用的。
任何时候在运行时处理字符串,并希望将该字符串的一部分视为语言中的标识符。
- 远程过程调用——将通过网络接收到的消息的一部分作为方法名称
- 序列化和反序列化--将字段名转换为字符串,这样您就可以将对象的字段写入流,然后再将其转换回对象
- 对象关系映射——维护对象中的字段和数据库中的列之间的关系
- 与动态类型脚本语言的接口——将脚本语言生成的字符串值转换为对对象上的字段或方法的引用
它还可以用于允许在语言中模拟语言功能。考虑将字符串转换为类名的命令行java com.example.MyClass
。这不需要反射,因为java
可执行文件可以将.class
文件转换为代码,但如果没有反射,它将无法在Wrapper
委托其参数的情况下写入java com.example.Wrapper com.example.MyClass
,如:
class Wrapper {
public static void main(String... argv) throws Exception {
// Do some initialization or other work.
Class<?> delegate = Class.forName(argv[0]);
Method main = delegate.getMethod("main", String[].class);
main.apply(null, Arrays.asList(argv).subList(1, argv.length).toArray(argv));
}
}
另一个案例是开发eclipse/netbeans等IDE,以确定抽象类中的哪些方法需要由子类实现,并自动为您编写缺少的方法调用(一个示例)。
像Guice或Spring这样的注入框架使用反射来帮助您在运行时构建对象的实例。
反射在需要配置将事物串在一起的情况下也很有用。例如,在我编写的一个应用程序中,我有一个@Report("debts")注释,它只是添加到生成报告的方法中。然后,在XML配置中,用户可以简单地添加:
<requiredReports="debits,blah,another"/>
这最大限度地减少了将XML代码映射到实际方法的麻烦,因为反射可以发现报告方法并使其直接可用。
我被要求为下面的语句创建一个解决方案。
"1)差异服务:•可以计算两个对象之间的差异,并返回结果"差异"•可以对原始对象应用先前创建的"diff",以便返回的对象与用于计算的修改后的对象匹配差异"
如果不使用反射,这将非常困难。使用反射,我可以列出所有未知对象的Class元素、属性和方法。我可以使用这些来获取对象中包含的值。我可以比较原始和修改后的对象值,创建反映两个对象之间变化的"diff"对象。
使用Java反射,我可以读取"diff"对象中的指令,并将其应用于原始对象。Java反射为我提供了更改原始对象未知属性值所需的工具。如果原始属性为null,我可以调用setter方法并在需要的地方实例化类型,以便在原始对象上设置修改后的值。
"diff"应用程序适用于任何两个相同类型的对象,但它们可以是任何类型,两个对象都必须是相同的类型。
反射非常强大,允许我们创建真正的通用多态方法、函数、库和系统,其中传递的对象类型在编译时不需要已知。这适用于同时使用Java反射和泛型,这是一个非常强大的组合。
最后,我还使用JavaReflection创建了一个通用排序函数,该函数可以使用Class的任何属性作为排序键对任何Class类型的任何列表进行排序。只要调用方法传递了要使用的列表和属性名,该方法就会返回一个排序列表。
以下是在中使用反射的一些情况
public class Main {
public static void main(String[] args) {
displayProperties(Stage.class);
}
public static void displayProperties(Class class) {
boolean hasParam = false;
boolean hasReturn = false;
ArrayList<Method> propMethods = new ArrayList<>();
Method[] methods = clazz.getMethods();
for (Method m: methods) {
Parameter[] paraType = m.getParameters();
if(m.getParameterCount()<2) {
if ((m.getReturnType() == void.class && paraType.length == 1) || (m.getReturnType() != void.class && paraType.length == 0)) {
//Get the properties alone
propMethods.add(m);
}
}
}
for (int i = 0; i < propMethods.size(); i++) {
if (propMethods.get(i).getName().startsWith("get") || propMethods.get(i).getName().startsWith("set")) {
System.out.println(readWrite(propMethods.get(i), propMethods) + " " + propMethods.get(i).getName().substring(3)+"( "+propMethods.get(i).getReturnType().getTypeName()+" )");
} else
System.out.println(readWrite(propMethods.get(i), propMethods) + " " + propMethods.get(i).getName() + "( "+propMethods.get(i).getReturnType().getTypeName()+" )");
}
}
public static String readWrite(Method method, ArrayList<Method> propMeths) {
ArrayList<Method> temp;
temp = propMeths;
boolean readIn = false;
boolean writeIn = false;
String onlyName = method.getName().substring(3);
for (int i = 0; i < temp.size(); i++) {
//use the substring--
if (temp.get(i).getName().startsWith("get") && temp.get(i).getName().endsWith(onlyName)) {
readIn = true;
}
if (temp.get(i).getName().startsWith("set") && temp.get(i).getName().endsWith(onlyName)) {
writeIn = true;
}
}
if (readIn == true && writeIn == true)
return "rw ";
else if (readIn == true && writeIn == false)
return "r ";
else
return "w ";
}
}
字符串类的另一种情况
public static void main(String[] args)
{
displayProperties(String.class);
}
public static void displayProperties(Class class){
clazz.getDeclaredFields();
Method[] methods = clazz.getDeclaredMethods();
for(int ii = 0; ii<methods.length; ii++){
System.out.println("Method Name: "+methods[ii].getName());
System.out.println("Method Type: "+methods[ii].getReturnType());
System.out.println("Method Pa: "+methods[ii].getParameterCount());
System.out.println("Method Type: "+methods[ii].getReturnType());
}
}
使用反射从XML加载
public static Object loadFromXml(String filePath) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
File newFile = new File(filePath);
Document doc = builder.parse(newFile);
Node root = doc.getFirstChild();
return loadObjectElement(root);
}
/**
* This method loads from an xml file and returns all the contents of the file as an object
* @param root The node passed in to the method from which the "tree" gets a new level
* @return all the contents of the xml file as an object
* @throws Exception
*/
public static Object loadObjectElement(Node root) throws Exception {
//loads the root
String studentClass = root.getAttributes().getNamedItem("class").getTextContent();
Object newStudentObject = Class.forName(studentClass).newInstance();
//gets the children nodes (may have text elements like n)
NodeList studentFieldList = root.getChildNodes();
//iterates through the children nodes
for (int i = 0; i < studentFieldList.getLength(); i++) {
//checks to make sure the child node is not a text node
if (studentFieldList.item(i).getNodeType() != Node.TEXT_NODE) {
//checks if the current node does not have children
if (studentFieldList.item(i).getChildNodes().getLength() == 0) {
//receives data of the current node
String nameField = studentFieldList.item(i).getAttributes().getNamedItem("name").getTextContent();
String valueField = studentFieldList.item(i).getAttributes().getNamedItem("value").getTextContent();
Field declaredFieldInClass = newStudentObject.getClass().getDeclaredField(nameField);
//makes the field accessible
declaredFieldInClass.setAccessible(true);
//checks the field type
switch (declaredFieldInClass.getType().getSimpleName().toLowerCase()) {
case "integer":
case "int":
declaredFieldInClass.set(newStudentObject, Integer.valueOf(valueField));
break;
case "float":
declaredFieldInClass.set(newStudentObject, Float.valueOf(valueField));
break;
case "boolean":
declaredFieldInClass.set(newStudentObject, Boolean.valueOf(valueField));
break;
default:
declaredFieldInClass.set(newStudentObject, valueField);
}
declaredFieldInClass.setAccessible(false);
} else {
//there are children in the current node
NodeList modulesObjectList = studentFieldList.item(i).getChildNodes();
String nameField = studentFieldList.item(i).getAttributes().getNamedItem("name").getTextContent();
Field declaredFieldInClass = newStudentObject.getClass().getDeclaredField(nameField);
List<Object> modules = new ArrayList<>();
//adds the modules into the array
for (int j = 0; j < modulesObjectList.getLength(); j++) {
if (modulesObjectList.item(j).getNodeType() != Node.TEXT_NODE) {
//recursively calls the the loadObjectElement method for any sub lists
modules.add(loadObjectElement(modulesObjectList.item(j)));
}
}
//sets the modules of the specific student that the method is working with
declaredFieldInClass.set(newStudentObject, modules);
}
}
}
return newStudentObject;
}