创建对象有哪几种:
new 工厂模式 克隆 以及反射
今天我们来学习一下什么是反射。
反射
什么是反射
反射Reflection是能够让运行于JVM中的程序检测和修改运行时的行为。
内省(Introspection):用于在运行时检测某一个对象的类型和其包含的属性;
反射:用于在运行时检测和修改某一个对象的结构和行为。
C++支持内省,不支持反射。
内省示例:instanceof 运算符用于检测某个对象是否属于特定的类。
if (obj instanceof Dog) {
Dog d = (Dog) obj;
d.bark();
}
反射示例:Class.forName()方法可以通过类或接口的名称(一个字符串或完全限定名)来获取对应的Class对象。forName方法会触发类的初始化。
// 使用反射
Class<?> c = Class.forName("classpath.and.classname");
Object dog = c.newInstance();
Method m = c.getDeclaredMethod("bark", new Class<?>[0]);
m.invoke(dog);
在Java中,反射更接近于内省,因为你无法改变一个对象的结构。虽然一些API可以用来修改方法和属性的可见性,但并不能修改结构。
反射的作用
应用:
JUnit通过反射来遍历包含@Test注解的方法,并在运行单元测试的时候调用他们。
Spring通过反射获取Bean元素中的对象或者方法
<bean id="someID" class="com.programcreek.Foo">
<property name="someField" value="someValue" />
</bean>
当Spring容器处理<bean元素时,会使用Class.forName(“com.programcreek.Foo”)来初始化这个类,并再次使用反射获取property元素对应的setter方法,为对象的属性赋值。
Servlet
<servlet>
<servlet-name>someServlet</servlet-name>
<servlet-class>com.programcreek.WhyReflectionServlet</servlet-class>
<servlet>
反射的使用
-
获取对象的类型名称
Student stu=new Student();
stu.getClass().getName(); -
调用未知对象的方法
package myreflection;
import java.lang.reflect.Method;
public class ReflectionHelloWorld {
public static void main(String[] args){
Foo f = new Foo();
Method method;
try {
method = f.getClass().getMethod("print", new Class<?>[0]);
method.invoke(f);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Foo {
public void print() {
System.out.println("abc");
}
}
输出:abc
- 创建对象
package myreflection;
public class ReflectionHelloWorld {
public static void main(String[] args){
// 创建Class实例
Class<?> c = null;
try{
c=Class.forName("myreflection.Foo");
}catch(Exception e){
e.printStackTrace();
}
// 创建Foo实例
Foo f = null;
try {
f = (Foo) c.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
f.print();
}
}
class Foo {
public void print() {
System.out.println("abc");
}
}
- 获取构造函数并创建对象
package myreflection;
import java.lang.reflect.Constructor;
public class ReflectionHelloWorld {
public static void main(String[] args){
// 创建Class实例
Class<?> c = null;
try{
c=Class.forName("myreflection.Foo");
}catch(Exception e){
e.printStackTrace();
}
// 创建Foo实例
Foo f1 = null;
Foo f2 = null;
// 获取所有的构造函数
Constructor<?> cons[] = c.getConstructors();
try {
f1 = (Foo) cons[0].newInstance();
f2 = (Foo) cons[1].newInstance("abc");
} catch (Exception e) {
e.printStackTrace();
}
f1.print();
f2.print();
}
}
class Foo {
String s;
public Foo(){}
public Foo(String s){
this.s=s;
}
public void print() {
System.out.println(s);
}
}
- 通过反射来修改数组的大小
package myreflection;
import java.lang.reflect.Array;
public class ReflectionHelloWorld {
public static void main(String[] args) {
int[] intArray = { 1, 2, 3, 4, 5 };
int[] newIntArray = (int[]) changeArraySize(intArray, 10);
print(newIntArray);
String[] atr = { "a", "b", "c", "d", "e" };
String[] str1 = (String[]) changeArraySize(atr, 10);
print(str1);
}
// 修改数组的大小
public static Object changeArraySize(Object obj, int len) {
Class<?> arr = obj.getClass().getComponentType();
Object newArray = Array.newInstance(arr, len);
// 复制数组
int co = Array.getLength(obj);
System.arraycopy(obj, 0, newArray, 0, co);
return newArray;
}
// 打印
public static void print(Object obj) {
Class<?> c = obj.getClass();
if (!c.isArray()) {
return;
}
System.out.println("\nArray length: " + Array.getLength(obj));
for (int i = 0; i < Array.getLength(obj); i++) {
System.out.print(Array.get(obj, i) + " ");
}
}
}