一.反射:
反射机制就是java程序在运行时拥有自观能力,能知晓类中的所有属性和方法。
通过反射能得到类中的任何属性和方法,也就是说反射可以打破类的封装特性,可以通过反射来调用私有方法。
让我们看个小例子:
public class Test {
public static void main(String[] args) throws Exception {
Class<?> classType = MethodTest.class;
Method[] method = classType.getDeclaredMethods();
for(Method m :method){
System.out.println(m);
}
}
}
public class MethodTest extends MethodTest2 {
public MethodTest(){}
public void methodOne(){
}
private void methodTwo(){
}
private String methodThree(){
return null;
}
public int methodFour(){
return 0;
}
}
打印:
public void Reflection3.MethodTest.methodOne()
private void Reflection3.MethodTest.methodTwo()
private java.lang.String Reflection3.MethodTest.methodThree()
public int Reflection3.MethodTest.methodFour()
这个小例子为我们显示MethodTest类中的所有方法,其中包括了私有方法和普通方法。要想使用反射就必须获得待处理类的class对象。
除了我上面MethodTest.class获取Class对象的方法还有两种,加上我用的一共三种方式:
1).使用Class类的静态方法forName:Class.forName("java.lang.String");
例子:
public>
会打印出String中的所有方法。
2).就是使用我第一个例子中的方法。类.class的方法。
3).使用对象的getClass()方法。
例子:
public class Test {
public static void main(String[] args) throws Exception {
String str = "abc";
Class<?> classType = str.getClass();
Method[] method = classType.getDeclaredMethods();
for(Method m :method){
System.out.println(m);
}
}
}
这个将会打印出String类中所有的方法。
如何通过反射使用类中的public类型方法:
public class Test {
public int sum(int a,int b){
return a + b;
}
public String Course(String str){
return "课程名:" + str;
}
public static void main(String[] args) throws Exception{
Class<?> classType = Test.class;
//通过classType.newInstance()来返回Test的实例对象,只能调用无参构造。
Object obj = classType.newInstance();
//第一个参数指定类中的方法名称,第二个参数指定其方法的参数类型,为什么会有第二个参数,因为类中会有重载的方法,用此来进行区分。
Method sumMethod = classType.getMethod("sum",int.class,int.class);
Object sum = sumMethod.invoke(obj,1,2);
System.out.println((Integer)sum);
System.out.println("==========================================");
Method courseMethod = classType.getMethod("Course",String.class);
Object course = courseMethod.invoke(obj,"Java");
System.out.println(course);
}
}
打印:
3
==========================================
课程名:Java
上面的例子中通过classType.newInstance()来获得Test的实例,但是这个方法只能调用无参的构造方法。使用方法时用通过invoke(传入方法存在类的实例,传入方法的参数)。
有参的构造方法使用格式:先获得Class对象,然后通过该对象获得相应的Constructor对象,再通过该Constructor对象的newInstance()方法生成。
如果想通过类的带参构造方法生成对象,只能使用下面例子中的格式。
例子:
public class Test {
public static void main(String[] args) throws Exception {
Class<?> classType = People.class;
/*
* Constructor con = classType.getConstructor(new Class[]{});
* Object obj = con.newInstance(new Object[]{});
* 也可以创建不带参数的对象。
*/
Constructor con = classType.getConstructor(String.class);
Object obj = con.newInstance("zhangsan");
System.out.println(obj);
}
}
class People {
private String name;
public People(){}
public People(String name){
this.name = name;
}
public String getName(){
return name;
}
}
如何通过反射使用类中的属性和方法:
例子:
public class ReflectionTest {
//执行对一个对象的copy操作。
public Object copy(Object o) throws Exception{
Class<?> cs = Student.class;
Object obj = cs.getConstructor(new Class[]{}).newInstance(new Object[]{});
Field[] field = cs.getDeclaredFields();
for(Field f:field){
String name = f.getName();
String firstLetter = name.substring(0,1).toUpperCase();
//获得对应属性的set和get方法的字符串。
String getMethodName = "get"+firstLetter+name.substring(1);
String setMethodName = "set"+firstLetter+name.substring(1);
//获得对应属性的set和get方法。
Method getMethod = cs.getMethod(getMethodName,new Class[]{});
Method setMethod = cs.getMethod(setMethodName,new Class[]{f.getType()});
//获得属性的返回值。
Object value = getMethod.invoke(o,new Object[]{});
//添加到要返回的对象中去。
setMethod.invoke(obj,new Object[]{value});
}
return obj;
}
public static void main(String[] args) throws Exception{
Student t = new Student("zhangsan",1,2);
ReflectionTest r = new ReflectionTest();
Student s = (Student)r.copy(t);
System.out.println(s.getAge()+" "+s.getName()+" "+s.getNumber());
}
}
class Student {
public String name;
private int number;
public int age;
public Student(){}
public Student(String name,int age,int number){
this.age = age;
this.name = name;
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
反射应用于数组:
例子:
public class Test {
public static void main(String[] args) throws Exception {
Class<?> classType = Class.forName("java.lang.String");
//第一个参数设置数组的类型,第二个设置数组的大小。
Object array = Array.newInstance(classType,10);
//第一个参数目标数组,第二个参数指定存放位置,第三个参数要存入的元素。
Array.set(array,5,"java");
//打印
System.out.println((String)Array.get(array,5));
}
}
打印: java
对于多维数组的创建:
例子:
public class Test {
public static void main(String[] args) throws Exception {
//Integer.TYPE返回原生数据类型,Integer.class返回类的类型,第一个参数设置数组的类型,第二个设置数组的大小。
Object array = Array.newInstance(Integer.TYPE,3,3,3);
Object array2 = Array.get(array,2);
array2 = Array.get(array2,2);
Array.setInt(array2,2,10);
int[][][] a = (int[][][])array;
//打印
System.out.println(a[2][2][2]);
}
}
打印: 10
使用反射调用类中的私有方法:
例子:
public class PrivateTest {
public static void main(String[] args) throws Exception{
A a = new A();
Class<?> classType = a.getClass();
Method method = classType.getDeclaredMethod("getHello",String.class);
method.setAccessible(true);//压制Java的访问权限
String str = (String)method.invoke(a,"java");
System.out.println(str);
}
}
class A{
private String getHello(String str){
return "你好!"+str;
}
}
打印:你好!java
如何访问私有属性:
public class Reflection2 {
public static void main(String[] args) throws Exception{
Private2 p = new Private2();
Class<?> cs = p.getClass();
Field f = cs.getDeclaredField("name");
f.setAccessible(true);//压制Java对方问修饰符的检查
f.set(p,"lisi");
System.out.println(p.getName());
}
}
class Private2 {
private String name ;
public String getName(){
return name;
}
}
打印:lisi
通过子类获得父类的Class对象:
public class Test {
public static void main(String[] args) {
Class<?> classType = Child.class;
System.out.println(classType);
classType = classType.getSuperclass();
System.out.println(classType);
classType = classType.getSuperclass();
System.out.println(classType);
}
}
class Child extends Parent{
}
class Parent{
}
打印:
class Reflection1.Child
class Reflection1.Parent
class java.lang.Object