首页 > 代码库 > Java 之 反射
Java 之 反射
1.反射
a.意义:允许运行中的Java程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性
b.概括:运行时探究和使用编译时未知的类
c.反射的核心原理:
①JVM在加载一个类的时候,会把该类的信息存放到一个Class对象中。该对象又被称之为类模板对象。JVM可以通过检索该对象,
得到这个类所拥有的各种信息(名字、所在包、父类、实现接口、属性、构造、行为......)
②JDK提供API,允许程序员获取到类的Class对象,导致程序员也可以检索到这个类的这些信息,即便这个类不是这个程序(或程序员)所实现的。
d.三步骤:
①获取到Class对象
②探究类的信息
③使用探究到的信息
2.获取到Class对象
a.通过类型名获取Class对象
Class stuClass = StudentBean.class;//类 Class strClass = String.class; Class runnableClass = Runnable.class;//接口 Class intArrayClass = int[].class;//数组 Class intClass = int.class;//基本数据类型---JDK1.5以后才有的 Class intClass0 = Integer.TYPE;//JDK1.5之前使用对应包装类.TYPE获取基本类型的Class对象 Class voidClass = void.class;
特点:①所有的类型都可以获得到Class对象
②因为在编写代码时已知类型名,所以没有动态性
b.通过实例对象获取Class对象
StudentBean stu = new StudentBean(); Class stuClass1 = stu.getClass(); Class strClass1 = "hello".getClass(); int[] intArray = new int[5]; Class intArrayClass1 = intArray.getClass();
特点:①只有非抽象类类型和数组类型可以通过该方式获取到Class对象
②抽象类、接口、基本数据类型、void都不可以
③因为在编写代码时已得到实例对象,所以也没有动态性
c.通过类型名的字符串形式获取Class对象
String className = JOptionPane.showInputDialog("请输入你要加载的类的类名");
Class stuClass2 = Class.forName(className);
特点:①类和接口可以通过该方式获取Class对象,细节:1、必须填写类全名(包含包名);2、先完成主动加载,然后返回Class对象
②这是唯一一种动态性的体现,以后会大量使用,表现在各种框架中书写配置文件
3.通过Class对象探究类的信息
a.探究类的基本信息
String className = stuClass.getName();//得到类全名 String classSimpleName = stuClass.getSimpleName();//类的简单名 String packageName = stuClass.getPackage().getName();//类的包名 String superClassName = stuClass.getSuperclass().getName();//得到该类父类类名 Class[] allInterfaces = stuClass.getInterfaces();//得到该类实现的接口 String classMod = Modifier.toString(stuClass.getModifiers());//得到修饰符
b.探究属性——Field
Field[] allFields = stuClass.getFields();//探究所有的公共属性(包括从父类继承而来的) Field[] allDeclaredFields = stuClass.getDeclaredFields();//探究所有被声明的属性(不包括从父类继承而来的) Field theField = stuClass.getField("name");//探究指定的公共属性(包括从父类继承而来的) Field theDeclaredField = stuClass.getDeclaredField("name");//探究指定的被声明的属性(不包括从父类继承而来的) String fieldName = field.getName();//属性名 String fieldMod = Modifier.toString(field.getModifiers());//修饰符 String fieldType = field.getType().getName();//类型名
c.探究构造——Constructor(基本同上)
Class[] conParams = con.getParameterTypes();//形参类型 Constructor theDeclaredCon = stuClass.getDeclaredConstructor(String.class,int.class);//探究指定的被声明的构造
d.探究行为——Method(基本同上)
String methRrturnParams = meth.getReturnType().getName();//返回类型 Class[] methThrow = meth.getExceptionTypes();//异常类型 Method theDeclaredCon = stuClass.getDeclaredMethod("study");//探究指定的被声明的方法
4.使用探究到的信息
a.探究到Constructor,就可以产生实例对象
StudentBean theStu = null; Constructor theDeclaredCon = stuClass.getDeclaredConstructor(String.class,int.class); theStu = (StudentBean)theDeclaredCon.newInstance("张三",28);
b.探究到Method,就可以调用方法
Method m = stuClass.getDeclaredMethod("study", int.class); m.invoke(theStu, 5);
c.探究到Field,就可以赋值/取值
Field f = stuClass.getDeclaredField("name"); f.setAccessible(true); f.set(theStu, "王小二"); System.out.println(f.get(theStu));
5.在使用探究到的信息时,有一些细节:
a.反射产生实例对象,是Java中我们学到的第三种产生对象的方式(new, 反序列化,反射)
b.在反射产生实例对象时,可以直接调用Class对象的newInstance方法获得实例对象;
但它只能调用公共无参构造!这就是JavaBean的第一规范的原因。
c.私有属性在反射中操作,都是调用它公共的get和set方法。这是JavaBean第二规范的原因
d.反射是Java的底层实现,其实是可以破坏封装性直接操作任意访问修饰符的构造/属性/方法的;
但是这违背了OO的设计思想,不准用!
StudentBean stu0 = (StudentBean) stuClass.newInstance();
Java 之 反射