12 反射
反射介绍:
“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”,如Python,Ruby是动态语言;显然C++,Java,C#不是动态语言,但是JAVA有着一个非常突出的动态相关机制:Reflection。 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制,很多优秀的开源框架都是通过反射完成的。
反射机制实现以下功能:
①在运行时判断任意一个对象所属的类;
②在运行时构造任意一个类的对象;
③在运行时判断任意一个类所具有的成员变量和方法;
④在运行时调用任意一个对象的方法;
⑤生成动态代理;
可变参数
当我们能够确定一系列参数的类型,类型必须是统一的, 但是我们确定不了参数的个数的时候,我们可以使用可变参数。可变代表个数可变[0,+),如果一个方法中带有可变参数,这个可变参数只能在参数列表最后。
获取Class类 class com.ppl.javase.thread.Test
所有类的对象其实都是Class的实例。这个 Class 实例可以理解为类的模子,就是包含了类的结构信息,类似于图纸。得到所属对象的容器。
三种方法获取:对象.calss 类.class Class.forName() getSuperClass() 获取父类。
public static void main(String[] args) throws ClassNotFoundException {
Test test = new Test();
System.out.println(Test.class);
System.out.println(test.getClass());
Class<?> aClass = Class.forName("com.ppl.javase.reflex.Test");
System.out.println(aClass);
}
类中的信息:
类的修饰符,{类的属性,类的方法,类的构造器} 还有这三种的修饰符
获取类的修饰符
获取修饰符,使用 getModifiers() 即可, Modifier类提供了 static 方法和常量来解码类和成员访问修饰符
Class<?> aClass = Class.forName("com.ppl.javase.reflex.Test");
//获得修饰符
int n=aClass.getModifiers();
//使用Modifier转换为相应的字符串
System.out.println(Modifier.toString(n));
获取类的构造器与创建类对象
Constructor
Constructor 提供了一个类的单个构造函数的信息和访问。
Constructor允许在将实际参数与newInstance()与底层构造函数的形式参数进行匹配时进行扩展转换,但如果发生缩小转换,则抛出 IllegalArgumentException 。
Class<?> aClass = Class.forName("com.ppl.javase.reflex.Test");
//public 权限下
//1、获取空构造器 ?可以放入Test在已知的情况下。
Constructor<Test> con=aClass.getConstructor();
//2、获取所有的public 权限的构造器
Constructor<?> []con=aClass.getConstructors();
//3, 实例化对象
Test test=(Test) con.newInstance();
//test 就是Test的对象可以使用了
//权限关闭需要使用getDeclaredConstructor()创建构造器,一样的功能。三连可写。
类中属性和方法
属性 Field
获取所有属性(包括父类或接口) ,使用 Field 即可操作, Field 作为描述属性的对象
Class<?> clz = Class.forName("com.shsxt.ref.simple.User");
//获取属性
System.out.println("===============本类属性 ==========");
// 取得本类的全部属性
Field[] field = clz.getDeclaredFields();
for (int i = 0; i < field.length; i++) {
// 1、权限修饰符
int mo = field[i].getModifiers();
String vis = Modifier.toString(mo);
// 2、属性类型
Class<?> type = field[i].getType();
//3、名字
String name = field[i].getName();
System.out.println(vis + " " + type.getName() + " "+ name + ";");
}
System.out.println("=========公开的属性包括接口或 者父类属性======");
field = clz.getFields();
for (int i = 0; i < field.length; i++) {
System.out.println(field [i]);
}
方法 method
获取所有方法(包括父类或接口),使用 Method 即可。Method 即作为描述方法的对象。
public static void test() throws Exception {
Class<?> clz = Class.forName("com.shsxt.ref.simple.User ");
//获取属性
System.out.println("===============本类方法 ===============");
// 取得全部公共方法
Method[] methods =clz.getMethods();
for(Method m:methods){
//1、权限
int mod=m.getModifiers();
System.out.print(Modifier.toString(mod)+" ");
//2、返回类型
Class<?> returnType=m.getReturnType();
System.out.print(returnType.getName()+" ");
//3、名字
String name =m.getName();
System.out.print(name +"(");
//4、参数
Class<?>[] para=m.getParameterTypes();
for(int i=0;i<para.length;i++){
Class<?> p =para[i]; System.out.print(p.getName() +" arg"+i);
if(i!=para.length-1){ System.out.print(",");
}
}
}
类加载器(待补充)
类的生命周期
在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开JVM。在程序执行中JVM通 过装载,链接,初始化这3个步骤完成。
从类的生命周期而言,一个类包括如下阶段: