什么是反思,为什么它有用?
我对Java特别感兴趣,但我认为任何语言的原理都是一样的。
什么是反思,为什么它有用?
我对Java特别感兴趣,但我认为任何语言的原理都是一样的。
当前回答
反射的简单示例。在国际象棋游戏中,您不知道用户在运行时会移动什么。反射可用于调用已在运行时实现的方法:
public class Test {
public void firstMoveChoice(){
System.out.println("First Move");
}
public void secondMOveChoice(){
System.out.println("Second Move");
}
public void thirdMoveChoice(){
System.out.println("Third Move");
}
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Test test = new Test();
Method[] method = test.getClass().getMethods();
//firstMoveChoice
method[0].invoke(test, null);
//secondMoveChoice
method[1].invoke(test, null);
//thirdMoveChoice
method[2].invoke(test, null);
}
}
其他回答
反射的使用
反射通常由需要检查或修改在Java虚拟机中运行的应用程序的运行时行为的程序使用。这是一个相对高级的特性,只有对语言基础有很强理解的开发人员才能使用。考虑到这一点,反射是一种强大的技术,可以使应用程序执行不可能执行的操作。
可扩展性功能
应用程序可以通过使用扩展性对象的完全限定名称创建扩展性对象实例来使用外部用户定义的类。类浏览器和可视化开发环境类浏览器需要能够枚举类的成员。可视化开发环境可以受益于利用反射中可用的类型信息来帮助开发人员编写正确的代码。调试器和测试工具调试器需要能够检查类中的私有成员。测试工具可以利用反射来系统地调用类上定义的可发现集合API,以确保测试套件中的代码覆盖率较高。
反射的缺点
反射是强大的,但不应滥用。如果可以在不使用反射的情况下执行一个操作,那么最好避免使用它。
性能开销
由于反射涉及动态解析的类型,因此无法执行某些Java虚拟机优化。因此,反射操作的性能比非反射操作慢,应该避免在性能敏感应用程序中频繁调用的代码段中使用。
安全性限制
反射需要在安全管理器下运行时可能不存在的运行时权限。对于必须在受限安全上下文(如Applet)中运行的代码,这是一个重要的考虑因素。
内部构件暴露
由于反射允许代码执行在非反射代码中非法的操作,例如访问私有字段和方法,因此使用反射可能会导致意外的副作用,这可能会导致代码功能失调,并可能破坏可移植性。反射代码打破了抽象,因此可能会随着平台的升级而改变行为。
来源:反射API
名称反射用于描述能够检查同一系统(或其本身)中其他代码的代码。
例如,假设您在Java中有一个未知类型的对象,如果存在,您希望对其调用“doSomething”方法。Java的静态类型系统并不是为了支持这一点而设计的,除非对象符合已知的接口,但是使用反射,您的代码可以查看对象并找出它是否有一个名为“doSomething”的方法,如果需要,可以调用它。
因此,给您一个Java代码示例(假设所讨论的对象是foo):
Method method = foo.getClass().getMethod("doSomething", null);
method.invoke(foo, null);
Java中一个非常常见的用例是注释的用法。例如,JUnit4将使用反射在类中查找标记有@Test注释的方法,然后在运行单元测试时调用它们。
有一些很好的反思示例可以帮助您开始http://docs.oracle.com/javase/tutorial/reflect/index.html
最后,是的,这些概念在其他支持反射的静态类型语言(如C#)中非常相似。在动态类型语言中,上面描述的用例不太必要(因为编译器将允许在任何对象上调用任何方法,如果不存在,则在运行时失败),但是第二种情况仍然很常见,即查找被标记或以某种方式工作的方法。
从评论更新:
检查系统中的代码并查看对象类型的能力是不是反思,而是类型反思。反射就是能够在运行时通过使用反省在某些语言中,这种区别是必要的支持内省,但不支持反思。一个这样的例子是C++
反射有很多用途。我更熟悉的是能够动态创建代码。
IE:基于任何数据的动态类、函数、构造函数(xml/array/sql results/hardcoded/etc.)
反射是让物体看到它们的外观。这个论点似乎与反思无关。事实上,这就是“自我识别”能力。
反射本身是指Java和C#等缺乏自我认知和自我感知能力的语言。因为他们没有自知之明的能力,当我们想要观察它的样子时,我们必须有另一件事来反思它的样子。优秀的动态语言,如Ruby和Python,可以在没有其他人帮助的情况下感知自己的反射。我们可以说,Java的对象在没有镜像的情况下无法感知它的样子,镜像是反射类的对象,但Python中的对象可以在没有镜像时感知它。这就是为什么我们需要在Java中进行反射。
反射允许在运行时动态实例化新对象、调用方法和获取/设置类变量的操作,而无需事先了解其实现。
Class myObjectClass = MyObject.class;
Method[] method = myObjectClass.getMethods();
//Here the method takes a string parameter if there is no param, put null.
Method method = aClass.getMethod("method_name", String.class);
Object returnValue = method.invoke(null, "parameter-value1");
在上面的示例中,null参数是要对其调用方法的对象。如果方法是静态的,则提供null。如果该方法不是静态的,那么在调用时需要提供有效的MyObject实例而不是null。
反射还允许您访问类的私有成员/方法:
public class A{
private String str= null;
public A(String str) {
this.str= str;
}
}
.
A obj= new A("Some value");
Field privateStringField = A.class.getDeclaredField("privateString");
//Turn off access check for this field
privateStringField.setAccessible(true);
String fieldValue = (String) privateStringField.get(obj);
System.out.println("fieldValue = " + fieldValue);
为了检查类(也称为内省),不需要导入反射包(java.lang.reflect)。可以通过java.lang.Class访问类元数据。
反射是一个非常强大的API,但如果过度使用,它可能会降低应用程序的速度,因为它在运行时解析所有类型。