------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
反射
1:反射机制:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
2:学习反射需要有以下步骤
A:首先学习字节码文件
B:第二学习 获取字节码文件的构造方法 并创建对象
C:有了对象了,就要学会获取对象中的成员变量
D:能获取对象中的成员变量了,那么还要学习成员方法
1)字节码文件的三种获取方式
①:Object类的getClass()方法:对象.getClass()
Person p = new Person();
Class c = p.getClass();
注意所有同一个类的字节码文件对象(实例)都是同一个(因为一个类就有唯一的字节码文件)
比如: Person p = new Person();
Class c = p.getClass();
Person p2 = new Person();
Class c2 = p2.getClass();
System.out.println(p == p2);// false
System.out.println(c == c2);// true
②:数据类型的静态的class属性:类名.class
Class c3 = Person.class;
③:通过Class类的静态方法forName(String className)(一般只用最后一种)
Class c4 = Class.forName("cn.itcast_01.Person");
2)反射获取类的构造方法
public Constructor<?>[] getConstructors():所有公共构造方法
public Constructor<?>[] getDeclaredConstructors():所有构造方法 包括私有
public Constructor<T> getConstructor(Class<?>... parameterTypes):获取单个构造方法
比如:
Class c = Class.forName("cn.itcast_01.Person");
Constructor con = c.getConstructor();//获取无参构造,因为没有参数
Object obj = con.newInstance();//用无参构造方法创建对象
System.out.println(obj);
Constructor con = c.getConstructor(String.class, int.class);//获取有参构造,因为有参数
Object obj = con.newInstance("aaa", 20);//用有参构造方法创建对象
System.out.println(obj);
注意:
可变参数:
public static void main(String[] args) {
int a = 10;
int b = 20;
int result = sum(a, b);//随意传任意个参数
System.out.println(result);
int c = 30;
result = sum(a, b, c);//随意传任意个参数
System.out.println(result);
int d = 40;
result = sum(a, b, c, d);//随意传任意个参数
System.out.println(result);
int e = 50;
result = sum(a, b, c, d, e);//随意传任意个参数
System.out.println(result);
}
public static int sum(int... x) {
int result = 0;
for (int i : x) {//底层就会把参数们封装层成一个数组,所以x是个数组
result += i;
}
return result;
}
3)反射获取类的成员变量
Field[] fields = c.getFields();// 获取所有公共的成员变量
Field[] fields = c.getDeclaredFields();// 获取所有的成员变量
Field field = c.getField("age");// 获取单个的成员变量
比如:获取非私有的单个成员变量
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");
//获取构造器对象
Constructor con = c.getConstructor();
Object obj = con.newInstance();
// 获取单个的成员变量
Field field = c.getField("age");
field.set(obj, 20);//给obj对象的field字段赋值为20
System.out.println(obj);
获取私有的单个成员变量
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");
// 创建对象
Constructor con = c.getConstructor();
Object obj = con.newInstance();
Field nameField = c.getDeclaredField("name");
nameField.setAccessible(true);//这个地方是暴力访问,是Field父类的方法
nameField.set(obj, "aaa");
4)反射获取类的成员方法
Method[] methods = c.getMethods();// 所有公共方法,包括父类的
Method[] methods = c.getDeclaredMethods();// 本类的所有方法
Method m1 = c.getMethod("show", null);//无参数无返回值
m1.invoke(obj, null);
Method m2 = c.getMethod("function", String.class);//带参数无返回值
m2.invoke(obj, "aaa");
Method m3 = c.getMethod("reutrnValue", String.class,int.class);//带多个参数有返回值
Object ooo = m3.invoke(obj, "aaa",26);// ooo就是返回的值
Method m4 = c.getDeclaredMethod("hello", null);//私有方法的调用
m4.setAccessible(true);//暴力访问
m4.invoke(obj, null);
例题:
动态创建某个配置文件中提供的一个类的名字的这个类的对象,并执行其方法
Properties prop = new Properties();
FileReader fr = new FileReader("test.properties");
prop.load(fr);
fr.close();
//获取类名
String className = prop.getProperty("className");
//获取方法名
String methodName = prop.getProperty("methodName");
//获取字节码文件对象
Class c = Class.forName(className);
Constructor con = c.getConstructor();
Object obj = con.newInstance();
Method m = c.getMethod(methodName, null);
m.invoke(obj, null);
泛型只是在编译期间(或者是你在写代码期间)强制要求你的做的一些规范,
等编译通过生成了字节码文件后,泛型就会被擦除,运行期间就没有泛型了
ArrayList<Integer> array = new ArrayList<Integer>();
// 获取字节码文件对象
Class c = array.getClass();
Method m = c.getMethod("add", Object.class);
m.invoke(array, "hello");
m.invoke(array, "world");
m.invoke(array, "java");
System.out.println(array);