版权声明:本文为 小异常 原创文章,非商用自由转载-保持署名-注明出处,谢谢!
本文网址:https://blog.csdn.net/sun8112133/article/details/89349362
文章目录
一、动态语言概述
动态语言: 在程序运行时,可以改变程序结构或变量类型。
如: Python, Ruby, JavaScript等都属于动态语言。
下面是一段 JS代码:
function test(){
var s="var a=3; var b=5; alert(a+b)";
eval(s); // 动态执行了s这个字符串,改变了整个程序的结构。
}
注: C、C++、Java不是动态语言,但是Java有一定的动态性,可以通过反射机制、字节码操作获得类似动态语言的特性,Java语言又可以称为 “准动态语言”。
二、反射概述
1、反射机制
Java反射机制 是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 Java语言的反射机制。
2、Class对象
Class对象 是内存中对应类的对象。一个类被加载后,JVM会创建一个对应类的Class对象,类的整个结构信息会放到对应的 Class对象 中。这个 Class对象 就像一面镜子一样,通过这面镜子我们可以看到对应类的全部信息。
加载完类之后,在堆内存中,就产生了一个Class类型的对象(一个类只有一个 Class对象)。这个对象也称为 反射对象。同一个类,它只会被加载一次,同一个类只会有一个反射对象。
三、获取Class对象的方式及其使用场景
1、对象名.getClass()
使用场景: 判断两个对象是否是同一个字节码文件
2、Class.forName(“全类名”)
使用场景: 读取配置文件
3、类名.class
使用场景: 锁对象
注: 数组也有Class对象,元素类型相同的数组,获取到的Class对象是同一个。
四、通过反射获取各种信息
1、获取类的名字
基本的数据类型的数组的类名: (getClass().getName())
byte : [B
short : [S
int : [I
long : [J
float : [F
double : [D
boolean : [Z
char : [C
1)全类名
c.getName();
2)类名
c.getSimpleName();
2、获取属性信息
1)本类及其父类中全部public的属性
Field[] fields = c.getFields();
2)本类全部的属性
Field[] fields = c.getDeclaredFields();
3)指定的public属性
Field[] field = c.getField("gender");
4)指定的属性
Field field = c.getDeclaredField("age");
3、获取方法信息
1)全部的方法
Method[] methods = c.getDeclaredMethods();
2)指定的方法
Method method = c.getDeclaredMethod("setName", String.class);
3)方法的名字
method.getName();
4)方法的注解
Annotation[] annos = method.getAnnotations();
5)方法的权限修饰符
String str = Modifier.toString(method.getModifies());
6)方法的返回值类型
Class returnType = method.getReturnType();
7)方法的参数列表类型
Class params = method.getParamerTypes();
8)方法的异常类型
Class exps = method.getExceptionTypes();
4、获取构造器信息
1)所有的构造器
Constructor[] constructors = c.getDeclaredConstructors();
2)指定的构造器
Constructor[] con = c.getConstructor(int.class, String.class);
5、获取父类信息
1)获取运行时的父类
Class superClass = c.getSuperclass();
2)获取带泛型的父类
Type type = c.getGenericSuperclass();
3)获取父类的泛型
Type type = c.getCenericSuperclass();
ParameterizedType param = (ParameterizedType) type;
Type[] args = param.getActualTypeArguments();
6、获取接口信息
Class[] interfaces = c.getInterfaces();
7、获取包信息
Package package = c.getPackage();
8、获取注解信息
Annotation[] annos = c.getAnnotations();
五、调用构造器、方法、属性
1、调用构造器
Teacher t = (Teacher) c.newInstance(); // 调用Teacher的无参构造器
Constructor con = c.getDeclaredConstructor(int.class, String.class);
Teacher t2 = (Teacher) con.newInstance(1, "sunkuan");
2、调用普通方法
Teacher t3 = (Teacher) c.newInstance();
Method m = c.getDeclaredMethod("sserName", String.class);
M.invoke(t3, "sun"); // 相当于t3.serName("sun");
3、操作属性
Teacher t4 = (Teacher) c.newInstance();
Field field = c.getDeclaredField("name");
field.serAccessible(true); // 设置访问权限为可见
field.ser(t4, "br"); // 为属性设置值
System.out.println(field.get(t4)); // 输出属性值
六、通过反射越过泛型
案例: ArrayList<Integer>
,在这个集合中添加一个字符串数据,如果实现呢?
注意: 泛型只在编译期有效,在运行期会被擦除。
main {
// 创建List集合
ArrayList<Integer> list = new ArrayList<Integer>();
// 添加数据
list.add(1111);
list.add(2222);
// 通过反射获取List集合的Class对象
Class clazz = Class.forName("java.util.ArrayList");
// 通过反射获取添加方法的反射对象
Method m = clazz.getMethod("add", Object.class);
// 调用添加方法添加数据
m.invoke(list, "abc");
}