转自:http://www.cnblogs.com/nerxious/archive/2012/12/24/2829446.html
Class类
如果要完成反射,那么必须了解Class类
实例1:通过对象取得包名和类名
package org.siu;
class Test {
}
public class Demo {
public static void main(String[] args) {
Test t = new Test();
System.out.println(t.getClass());
System.out.println(t.getClass().getName());
}
}
编译结果如下,注意包的编译方式即可
此处的getClass()方法是默认继承自Object类的
实例2:Class类的实例化
由于Class类没有构造方法,所以实例化Class类的方式有点特殊,有三种方式:
- 对象.getClass( )
- 类.Class
- forName( )
class Test {
}
public class Demo {
public static void main(String[] args) {
//方式一:
Test t = new Test();
Class<? extends Test> c1 = t.getClass();
System.out.println(c1);
//方式二:
//为了避免特殊性,这里不用Test类,而用java库中的String类
Class<String> c2 = String.class;
System.out.println(c2);
//方式三:
//forName()方法会抛出异常
Class<?> c3 = null;
try {
c3 = Class.forName("Test");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(c3);
}
}
其中,forName( )方法需要重点掌握,因为它可以在类不确定的情况下实例化Class,更具灵活性
Class类的应用
Class类中有一个方法叫做newInstance( ),它可以用来创建一个Class类对象的新实例
怎么说呢?Class对象包含的内容就是反射好的那个类,我们要构造那个类的新实例(新对象)
实例3:Class类的无参构造对象
public class Demo {
public static void main(String[] args) {
//实例化Class对象,forName()方法会抛异常
Class<?> c = null;
try {
//这里需要完整的包名和类名
c = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//生成一个字符串的引用
String s = null;
try {
//将构造好的对象向下转型为String类
//newInstance()方法会抛异常
s = (String) c.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
System.out.println("字符串长度: " + s.length());
}
}
这样就通过无参数的形式构造了一个新的对象,如同正常模式中
通过无参构造方法来构造新对象一样
我们知道,类中除了有无参构造方法,还会存在有参数的构造方法
那在反射中如何通过有参数的形式构造对象呢?接着看
实例4:Class类的有参构造对象
import java.lang.reflect.Constructor;
public class Demo {
//下面的几个方法抛出来的异常太多,为了代码的紧凑性,这里就直接抛给虚拟机了
public static void main(String[] args) throws Exception {
Class<?> c = null;
try {
c = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
char[] ch = {'h','e','l','l','o'};
String s = null;
//获得Class类对象的有参构造方法,括号里面参数的写法是:类型.class
Constructor<?> con = c.getConstructor(char[].class);
//用此构造方法构造一个新的字符串对象,参数为一个char数组
s = (String) con.newInstance(ch);
System.out.println("构造的字符串:" + s);
}
}
我们还是使用String类做例,因为String类用的比较多,便于理解
这里需要注意的是,构造方法需要使用getConstructor( )方法获得
至于参数类型则是:原有类型.class
还有一点,无论是有参还是无参,这里所使用的构造方法,原本的类里面必须对应存在
那么,如何才能知道原有类里面的构造方法,普通方法,继承的父类等详细信息呢?接着看
获取类的结构
要通过反射获取类的结构我们这里要导入一个新的包java.lang.reflect
实例5:取得类的构造方法
import java.lang.reflect.Constructor;
import java.util.Arrays;
public class Demo {
//下面的几个方法抛出来的异常太多,为了代码的紧凑性,这里就直接抛给虚拟机了
public static void main(String[] args) throws Exception {
Class<?> c = null;
try {
c = Class.forName("java.lang.Boolean");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//这里的getConstructors()方法返回的是一个Constructor数组
Constructor<?>[] cons = c.getConstructors();
//打印的方式你可以自己写,为了方便我用Arrays.toString(),凑合着看
System.out.println(Arrays.toString(cons));
}
}
实例6:取得类所实现的接口
import java.util.Arrays;
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> c = null;
try {
c = Class.forName("java.lang.Boolean");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Class<?>[] in = c.getInterfaces();
System.out.println(Arrays.toString(in));
}
}
实例7:取得父类
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> c = null;
try {
c = Class.forName("java.lang.Boolean");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//注意了,这里不会是数组,why?
Class<?> su = c.getSuperclass();
System.out.println(su);
}
}
别忘了,java中是单继承,父类只有一个
实例8:取得类的全部方法
import java.lang.reflect.Method;
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> c = null;
try {
c = Class.forName("java.lang.Boolean");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Method[] m = c.getMethods();
//好吧,这次我就大发慈悲的写个打印列表出来
for (int i = 0; i < m.length; i++) {
System.out.println(m[i]);
}
}
}
实例9:取得本类的全部属性
import java.lang.reflect.Field;
class Person {
private String name;
private int age;
}
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> c = null;
try {
c = Class.forName("Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Field[] f = c.getDeclaredFields();
for (int i = 0; i < f.length; i++) {
System.out.println(f[i]);
}
}
}
getDeclaredFielsd()方法可以获取全部属性,getFields()只能获取公共属性
实例10:获取本类中属性的值
import java.lang.reflect.Field;
class Person {
public String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Demo {
public static void main(String[] args) throws Exception {
Person p = new Person("zhangsan",12);
Class<?> c = p.getClass();
//获取公共属性的值
Field f1 = c.getField("name");
//get(p)表明要获取是哪个对象的值
String str = (String) f1.get(p);
System.out.println("姓名: " + str);
//获取私有属性的值
Field f2 = c.getDeclaredField("age");
//age是私有属性,所以要设置安全检查为true
f2.setAccessible(true);
int age = (int) f2.get(p);
System.out.println("年龄: " + age);
}
}
要注意的是:setAccessible()方法可以设置是否访问和修改私有属性
反射的应用
实例11:通过反射修改属性
import java.lang.reflect.Field;
class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String toString() {
return "姓名: " + this.name;
}
}
public class Demo {
public static void main(String[] args) throws Exception {
Person p = new Person("王二狗");
System.out.println(p);
Class<?> c = p.getClass();
//定义要修改的属性
Field f = c.getDeclaredField("name");
f.setAccessible(true);
//修改属性,传入要设置的对象和值
f.set(p, "张二蛋");
System.out.println(p);
}
}
实例12:通过反射调用方法
import java.lang.reflect.Method;
class Person {
public void print(int i) {
System.out.println("我在写数字: " + i);
}
public static void say(String str) {
System.out.println("我在说: " + str);
}
}
public class Demo {
public static void main(String[] args) throws Exception {
Person p = new Person();
Class<?> c = p.getClass();
//getMethod()方法需要传入方法名,和参数类型
Method m1 = c.getMethod("print", int.class);
//invoke()表示调用的意思,需要传入对象和参数
m1.invoke(p, 10);
Method m2 = c.getMethod("say", String.class);
//这里的null表示不由对象调用,也就是静态方法
m2.invoke(null, "你妹");
}
}
这里演示了一个普通的有参方法和一个静态方法
既然有参数的都写出来了,那么无参的就更简单了,直接传入一个对象即可
实例13:通过反射操作数组
import java.lang.reflect.Array;
public class Demo {
public static void main(String[] args) throws Exception {
int[] arr = {1,2,3,4,5};
Class<?> c = arr.getClass().getComponentType();
System.out.println("数组类型: " + c.getName());
int len = Array.getLength(arr);
System.out.println("数组长度: " + len);
System.out.print("遍历数组: ");
for (int i = 0; i < len; i++) {
System.out.print(Array.get(arr, i) + " ");
}
System.out.println();
//修改数组
System.out.println("修改前的第一个元素: " + Array.get(arr, 0));
Array.set(arr, 0, 3);
System.out.println("修改后的第一个元素: " + Array.get(arr, 0));
}
}
这里要注意一点,getComponentType( )返回的是数组元素的Class