---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------
今天学习了张老师高新技术里面的反射,因为以前没有接触过反射机制,所以学起来感觉有些费劲,而且很多地方都是反复看了好几遍,不过好在终于看明白了。
1:反射的定义:
反射可以理解为一种动态技术,它可以将类中的组成部分在运行阶段将其抽取出来,映射成一个个Java对象,通过这些对象可以完成功能。
2:反射的作用:反射用于简化代码,提高代码的复用性。反射一般用于框架中,写出复用性高的通用代码。
3:映射对象的分类:
类是由构造方法,成员变量和成员方法组成的,所以在映射的过程中,类也被映射成三种对象,构造方法被映射成Constructor对象,成员变量被映射成Field对象,成员方法被映射成Method对象。
抽取出来的Constructor对象用于创建对象,Field对象用于封装数据,Method对象用于调用,完成功能。
4:获取方式:
Constructor,Field,Method都是通过Class获取的。
Class类:
Class类的实例表示正在运行的Java应用程序中的接口和类,简单理解就是字节码文件对象。
获取Class的方式有三种,分别是:
类名.Class;
new对象().getClass();
Class.("类名.包名");
在一般的开发中,推荐使用第三种方式获取,因为这种方式耦合度低。
5:Constructor类:
Constructor类代表的是构造器对象,得到构造器就可以创建对象。
Constructor类对象的获取方式:
A:获取public修饰的构造器:
Constructor c = Class.getConstructor(Class ... c);
参数代表的是构造方法的参数类型的Class,返回的是一个构造其对象。
Constructor[] c = Class.getConstructors();
获取所有的构造器对象。返回的是一个Constructor类型的数组。
B:获取非公共的构造器:
Constructor c = Class.getDeclaredConstructors(Class...c);
Constructor c = Class.getDeclaredConstructors();
Constructor对象的使用:
getName(); 获取构造器的名称
newInstance(Object...obj); 创建实例对象
注意:如果是非公共的构造器,我们可以通过getDeclaredConstructor()去获取构造器对象,但是不能直接使用。
如果在Constructor,Field,Method中所使用的操作是有权限范围的(非公有的),这是 可以通过从父类:AccessibleObject继承的setAccessible(true)这样的方式,将权限检查取消。
例如:
package cn.itcast;
public class Person {
public String name = "哈哈";
//定义类的构造方法
public Person(){
System.out.println("person");
}
public Person(String name) {
System.out.println(name);
}
public Person(String name,int age) {
System.out.println(name + "---" + age);
}
}
// 反射构造方法:public Person(String name){}
@Test
public void test2() throws Exception {
// 1:先加载类
Class c = Class.forName("cn.itcast.Person");
// 2:获取构造方法
Constructor ct = c.getConstructor(String.class);
// 3:调用已经获取到的构造方法创建对象
Person p = (Person)ct.newInstance("王璐");
// 4:访问创建的对象
System.out.println(p.name);
}
这个例子中就是利用反射获取类构造器,然后进行创建对象的。
6:Field类:
A:获取Field类的对象:
获取public修饰的Field:
Field f = Class.getField(String name);
Filed[] f = Class.getFields(); 返回的是一个Field类型的数组
获取非公有的Field类的的对象:
Field f = Class.getDeclaredField(String name);
Field[] f = Class.getDeclaredFields();
其中的参数name代表的是成员变量的名称,是一个字符串类型。
B:对成员变量进行赋值操作:
set(Object obj,Object value) 赋值操作
其中的obj是要进行操作的对象,value是要给指定对象赋的值。
get(Object obj)
这是对获取到的成员变量进行取值。
例如下面就是一个对Field进行反射的例子:
package cn.itcast.field;
public class Student {
public String name;
public String sex;
private int age;
public Student() {
super();
}
public Student(String name,String sex,int age) {
super();
this.name = name;
this.sex = sex;
this.age = age;
}
public Student(int age) {
super();
this.age = age;
}
public Student(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package cn.itcast.field;
import java.lang.reflect.Field;
import org.junit.Test;
public class StudentTest {
@Test
public void test2() throws Exception {
Student s = new Student();
//获取Class类对象
Class c = Class.forName("cn.itcast.field.Student");
//获取Field对象
Field f = c.getField("sex");
Field f1 = c.getField("name");
Field f2 = c.getDeclaredField("age");
//对非公有变量的Field对象进行暴力反射(取消权限检查)
f2.setAccessible(true);
//对Field对象进行赋值
f.set(s, "男");
f1.set(s, "王璐");
f2.set(s,20);
System.out.println(f.get(s));
System.out.println(f1.get(s));
System.out.println(f2.get(s));
}
}
7:Method类:
A:获取Method类的对象:
getMethod(String s,Class...c);
用于获取指定名称的public修饰的方法。
getDeclaredMethod(String s,Class c);
用于获取指定名称的方法,不考虑方法的权限。
getMethods();
得到所有的方法,包括从父类继承的方法,返回的是一个方法的集合。
getDeclaredMethods();
获取本类的所有方法。
B:调用Method对象:
Object invoke(Object obj,Objevt...args);
其中obj代表的是执行当前方法的对象,args是该方法的参数。
注意:invoke()方法返回的是Method对象代表的方法执行后的结果。
通过反射调用一个静态方法时,它的调用者可以是null。
在调用invoke()方法时,如果传入的参数是一个数组,那么在传参数时,会将数组中的元素拆分开来,这样传入参数的参数类型和所需的参数类型就不匹配了,就会报错。解决方法是在数组外面再报一层数组,就相当于一个二维数组,或者将要传入的数组强转成Object类型。
例如下面就是一个获取Method对象并进行调用的例子:
package cn.itcast.field;
public class Student {
public String name;
public String sex;
private int age;
public Student() {
super();
}
public Student(String name,String sex,int age) {
super();
this.name = name;
this.sex = sex;
this.age = age;
}
public Student(int age) {
super();
this.age = age;
}
public Student(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package cn.itcast.field;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.junit.Test;
public class StudentTest {
@Test
public void test3() throws Exception {
Student s = new Student();
//获取Class对象
Class c = Class.forName("cn.itcast.field.Student");
//获取Method对象
Method m_set = c.getDeclaredMethod("setName", String.class);
Method m_get = c.getDeclaredMethod("getName");
//调用Method对象完成功能
String name = (String) m_set.invoke(s, "haha");
System.out.println(m_get.invoke(s));
}
}
在反射中,Method类是最重要的,也是最难理解的,尤其是后面的出入参数是数组的内容,感觉非常的绕,思维很难转过那个弯,多看了好几遍,以后还要多多理解啊
---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------详细请查看:<a href="http://www.itheima.com" target="blank">www.itheima.com</a>