JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
反射就是把java类中的各种成分映射成一个个的Java对象。
例如:一个类有成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把各个组成部分映射成一个个对象。
一个类的所有的对象共享同一个Class对象
举例: Student stu1=new Student()
Student stu2=new Student();
stu1与stu2共享同一个Student类的Class对象。
Class类被创建后的对象就是Class对象。注意,Class对象表示的是自己手动编写类的类型信息。比如创建一个Shapes类,那么,JVM就会创建一个Shapes对应Class类的Class对象,该Class对象保存了Shapes类相关的类型信息。
在Java中每个类都有一个Class对象,每当编写并且编译一个新创建的类时就会产生一个对应的Class对象,并且这个Class对象会被保存在同名.class文件里(编译后的字节码文件保存的就是Class对象)。
当我们new一个新对象或者引用静态成员变量时,JVM中的类加载器子系统会将对应的Class对象加载到JVM中,然后JVM再根据这个类型信息相关的Class对象创建我们需要的实例对象或者提供静态变量的引用值。
需要特别注意的是,手动编写的每个class类,无论创建多少个实例对象,在JVM中都只有一个Class对象,即在内存中每个类有且只有一个相对应的Class对象。
Class类的对象作用是运行时提供或获得某个对象的类型信息,这点对于反射技术很重要。
Class对象的加载
所有的类都是在对其第一次使用时动态加载到JVM中的,当程序创建第一个对类的静态成员引用时,就会加载这个被使用的类(实际上加载的就是这个类的字节码文件)。注意,使用new操作符创建类的实例对象也会被当作对类的静态成员的引用(构造函数也是类的静态方法)。
由此看来Java程序在它们开始运行之前并非被完全加载到内存,其各个部分是按需加载。所以在使用该类时,类加载器首先会检查这个类的Class对象是否已被加载,如果还没有加载,默认的类加载器就会先根据类名查找.class文件(编译后Class对象被保存在同名的.class文件中),在这个类的字节码文件被加载时,它们必须接受相关验证,以确保没有被破坏并且不包含不良Java代码(这是java的安全机制检测),完全没有问题后就会被动态加载到内存中,此时相当于Class对象也就被载入内存了,同时也就可以被用来创建这个类的所有实例对象。
获得Class对象的三种方式
public class FanShe02 {
public static void main(String[] args) throws ClassNotFoundException {
//使用字节码获取(类字面常量)
Class c1=Student.class;
System.out.println(c1);
//通过Class的静态方法forName获取
Class c2=Class.forName("cn.gakki.FanShe.Student");
System.out.println(c2);
//通过类的对象的成员方法getClass()获取,该方法为Object类的方法
Student student=new Student("小兰",18);
Class c3=student.getClass();
System.out.println(c3);
System.out.println(c1==c2);
System.out.println(c1==c3);
System.out.println(c2==c3);
}
}
注意:在运行期间,一个类,只有一个Class对象产生。
类字面常量更加安全、高效。
获取Student类的属性对象(Field)
public class FanShen03 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
//获取Student类的Class对象
Class c1= Class.forName("cn.gakki.FanShe.Student");
//根据Class对象,获取Student类的属性对象
//获取public属性
Field[] fields=c1.getFields();
for(Field field:fields){
System.out.println(field);
}
System.out.println();
//获取所有属性
Field[] fields1=c1.getDeclaredFields();
for(Field field:fields1){
System.out.println(field);
System.out.println("属性修饰符:"+field.getModifiers()+"--->"+ Modifier.toString(field.getModifiers()));
System.out.println("属性类型:"+field.getType());
System.out.println("属性名称:"+field.getName());
System.out.println();
}
//根据名称获取属性对象
Field field=c1.getDeclaredField("age");
System.out.println(field);
}
}
获取类的成员方法(Method)
public class FanShe05 {
public static void main(String[] args) throws Exception {
//获取Student类的Class对象
Class c=Class.forName("cn.gakki.FanShe.Student");
//获取Student类的成员方法
Method[] methods=c.getDeclaredMethods();
for(Method method:methods){
System.out.println(method);
}
System.out.println();
//获取所有方法(包括父类方法)
Method[] methods1=c.getMethods();
for(Method method:methods1){
System.out.println(method);
}
System.out.println();
//通过方法名称获取指定的方法对象
Method method=c.getMethod("getAge");
System.out.println(method);
System.out.println("方法的权限:"+ Modifier.toString(method.getModifiers()));
System.out.println("方法的返回值类型:"+method.getReturnType());
System.out.println("方法的名称:"+method.getName());
System.out.println();
//获取setAge()方法
Method method1=c.getMethod("setAge", int.class);
System.out.print("方法的参数:");
Class[] parm=method1.getParameterTypes();
System.out.println(parm[0]);
//获取show()方法
Method method2=c.getMethod("show", String.class, int.class);
Class[] parm1=method2.getParameterTypes();
System.out.println("方法的参数:");
for(Class p:parm1){
System.out.println(p);
}
System.out.println();
//方法的执行invoke
//创建Student对象
Student student=(Student) c.newInstance();
//执行method1对象的方法(setAge()方法)
method1.invoke(student,18);
//执行method对象的方法(getAge()方法)
method.invoke(student);
//执行show()方法
method2.invoke(student,"三三",7);
}
}
获取Student的构造方法对象(Constructor)
public class FanShe04 {
public static void main(String[] args) throws Exception {
//获取Studeng类的Class对象
Class c=Class.forName("cn.gakki.FanShe.Student");
//获取Student类的构造方法对象
Constructor[] constructor=c.getConstructors();
for(Constructor constructor1:constructor){
System.out.println(constructor1);
}
System.out.println();
//获取指定的构造方法对象
//获取无参构造
Constructor constructor1=c.getConstructor();
//创建Student对象
Student student=(Student) constructor1.newInstance();
System.out.println(student);//默认调用Student的toString方法
System.out.println();
//获取带参构造
Constructor constructor2=c.getDeclaredConstructor(String.class,int.class);
//创建对象
Student student1=(Student) constructor2.newInstance("兰",20);
System.out.println(student1);
System.out.println();
//创建Student对象,可以使用Class对象的newInstance()方法
//默认调用无参构造方法
Student student2=(Student) c.newInstance();
System.out.println(student2);
}
}