乌拉拉,今天我们来讲一个高大上的东西,反射。想必很多人都听说过了,今天我们就慢慢的来讲解其用法。
首先是反射的定义:(网上抄的)
在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法
Java反射机制主要提供了以下功能:
* 1.在运行时判断任意一个对象所属的类。
* 2.在运行时构造任意一个类的对象。
* 3.在运行时判断任意一个类所具有的成员变量和方法。
* 4.在运行时调用任意一个对象的方法。
Java Reflection API简介
在JDK中,主要由以下类来实现Java反射机制,这些类(除了第一个)都位于java.lang.reflect包中
Class类:代表一个类,位于java.lang包下。
Field类:代表类的成员变量(成员变量也称为类的属性)。
Method类:代表类的方法。
Constructor类:代表类的构造方法。
Array类:提供了动态创建数组,以及访问数组的元素的静态方法。(这个方法的放射今天不提,这个复杂)
Class对象
要想使用反射,首先需要获得待操作的类所对应的Class对象,我们都知道所有代码都最后被变成.class的文件,我们也是从这个class文件开始着手去方向去获取我们想要的东西。
首先我们要去获取我们的class对象,这里有3中法方法。
一:使用Class的静态方法来获取
相信用过JDBC的人都知道,要想用JDBC首先要注册我们的驱动,也就是
Class.forName("com.mysql.jdbc.Driver");
二:.class直接获取我们的class
eg: String.class 这样就获得了String的Class
三:getClass()方法获得,这个是建立在你已经得到这个对象的实例来获取
eg: A a = new A();
Class<?> c = a.getClass();
这样我们也可以获得A的Class对象.
下面就以几个例子用反射分别获取我们的构造函数,成员变量,方法。
获取构造函数:
一:获取公有的构造函数(public)
//定义我们要反射的类
这样我们就获得了我们的构造函数,但是这个构造函数是个公有的。完全没体现出反射的作用.下面我把构造函数定义成私有的,那么用常规的方法是无法获取到的。这就体现出反射的厉害了,但是用上面的代码还是不能获取到的。接着看;
class AA{
private int a;
private int b;
public AA() { System.out.println("放射获取成功");}
}
public class Refelect {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
//用第二种方法获取来获取
Class<?> c = AA.class;//这里可以写成Class c = AA.class; 因为他底层代码返回的是Class<?> 其实一样,最后有泛型擦除的效果,所以没事,但是还是标准的写比较好
AA aa = (AA) c.newInstance();
}
}
这里是可以直接调用newInsatace(),来构造默认的构造函数下面演示标准做法。
二:获取私有的构造函数(private)
class AA{
private int a;
private int b;
private AA() { System.out.println("放射获取成功");}
}
这样就棘手了,但是无妨.
public class Refelect {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
Class<?> c = AA.class;
// AA aa = (AA) c.newInstance();
/**
* 反射来获取构造函数(指定的构造函数)getDeclaredConstructor(param);
* 返回为所有构造函数仅本Class
* 参数含义就是对应构造函数的形参
* c.getConstructor(parameterTypes)
* 得到是包括父类的public的构造函数
*
*/
Constructor<?> constructor = c.getDeclaredConstructor(new Class[] {});
//修改得到的构造函数的方法权限
constructor.setAccessible(true);
//通过构造函数来实例化AA
AA aa = (AA) constructor.newInstance();
}
}
这样我们也能获取到AA这个对象。
获取成员变量:
一样的也分公有和私有,这里直接讲私有的获取方法.
class AA{
private int a;
private int b;
private AA() {
System.out.println("放射获取成功");
}
}
public class Refelect {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
Class<?> c = AA.class;
// AA aa = (AA) c.newInstance();
/**
* 反射来获取构造函数(指定的构造函数)getDeclaredConstructor(param);
* 返回为所有构造函数仅本Class
* 参数含义就是对应构造函数的形参
* c.getConstructor(parameterTypes)
* 得到是包括父类的public的构造函数
*
*/
Constructor<?> constructor = c.getDeclaredConstructor(new Class[] {});
//修改得到的构造函数的方法权限
constructor.setAccessible(true);
//通过构造函数来实例化AA
AA aa = (AA) constructor.newInstance();
//得到我们指定的变量,里面有好多方法,也可以返回集合
Field field = c.getDeclaredField("a");
//修改属性
field.setAccessible(true);
//设置值
field.set(aa,3);
//打印
System.out.println("a = "+field.get(aa));
}
}
结果:
反射获取成功
a = 3
a = 3
获取方法并调用:
这次我们以公有的方法来获取并且调用。
class AA{
private int a;
private int b;
private AA() {
System.out.println("反射获取成功");
}
public AA(int a,int b) {
this.a=a;
this.b=b;
}
public void add(int a,int b) {
System.out.println("a+b="+(a+b));
}
}
public class Refelect {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
Class<?> c = AA.class;
// AA aa = (AA) c.newInstance();
/**
* 反射来获取构造函数(指定的构造函数)getDeclaredConstructor(param);
* 返回为所有构造函数仅本Class
* 参数含义就是对应构造函数的形参
* c.getConstructor(parameterTypes)
* 得到是包括父类的public的构造函数
*
*/
Constructor<?> constructor = c.getDeclaredConstructor(new Class[] {});
//修改得到的构造函数的方法权限
constructor.setAccessible(true);
//通过构造函数来实例化AA
AA aa = (AA) constructor.newInstance();
//得到我们指定的变量,里面有好多方法,也可以返回集合
Field field = c.getDeclaredField("a");
//修改属性
field.setAccessible(true);
//设置值
field.set(aa,3);
//打印
System.out.println("a = "+field.get(aa));
/**
* 同上面一样c.getDeclaredMethod(name, parameterTypes)
* 返回的是所有本类的方法
* 参数一 调用的方法名
* 参数二 形参列表,要一一对应
*/
//得到我们的方法
Method method = c.getDeclaredMethod("add", new Class [] {int.class,int.class});
/**
* 调用我们的方法 method.invoke(obj, args)
* 参数- 为反射获取得到的实例,参数二 你要传递的参数
*/
method.invoke(aa, new Object[] {1,2});
}
}
getType(): 获取属性声明时类型对象(返回class对象)
getGenericType() : 返回属性声的Type类型
getName() : 获取属性声明时名字
getAnnotations() : 获得这个属性上所有的注释
getModifiers() : 获取属性的修饰
isEnumConstant() : 判断这个属性是否是枚举类
isSynthetic() : 判断这个属性是否是 复合类
等等....
这里下去可以自己试一下.
反射能干嘛:
可能听上面的东西,到头来还没弄明白反射用来干嘛的。
其实反射用处很多,开发Android的人一定会被一些SDK给烦恼住,因为有的地方标注了hide标签
eg:
UsageStats 包底下封装了我们app状态的一些方法,但是这些方法google不对外公开,他带了hide标签,这样我们学了反射我们也可以通过反射来获取。
Jdk也有一些被私有的构造函数.我们都无法正常获取他。
最后支持原创,转载请注明转载出处