在Java运行时环境中,对于任意一个类,可否知道这个类的哪些属性和方法?对于任意一个对象,可否调用它的任意一个方法?答案是确定的。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java语言的反射(Reflection)机制。 反射给java提供了,运行时获取一个类实例的可能,这一点很是灵活,你仅仅传一个类的全限定名,就能经过反射,来获取对应的类实例,咱们通常会用Class类,来调用这个被反射的Objcet类下的:构造方法,属性,或方法等。 反射在一些开源框架里用的很是之多,Spring,Struts,Hibnerate,MyBatics都有它的影子,反射虽然很灵活,可以使得写的代码,变的大幅精简,因此在用的时候,必定要注意具体的应用场景。 反射的优缺点以下: 优势: A:可以运行时动态获取类的实例,大大提升系统的灵活性和扩展性。 B:与Java动态编译相结合,能够实现无比强大的功能 缺点: A:使用反射的性能较低 B:使用反射相对来讲不安全 C:破坏了类的封装性,能够经过反射获取这个类的私有方法和属性 任何事物,都有两面性,反射的优势,也同是就是它的缺点,因此,没有好与坏,只有最合适的场景,一阴一阳,才是天道平衡的条件。 在反射API中咱们重点关注一下几个类: Class -- 表明类 Field -- 表明属性(成员变量) Method -- 表明方法 Constructor -- 表明构造方法 1、Class Java中不论一个类产生了多少个对象,这些对象的Class对象都始终是一个。Class对象中含有该类的任何信息(属性,方法,类名,父类,包等),在Java中获取Class对象的方法有三种: // 第一种方法:类名.class Class cla = Student.class; Class as =int.class; // 基本数据类型惟一能点出的就是class // 第二种方法:经过对象调用.getClass() Student stu =newStudent(); Class c = stu.getClass(); // 第三种方法:经过类的全限定名获取 try{ Class c1 = Class.forName("entity.Student"); }catch(ClassNotFoundException e) { e.printStackTrace(); } System.out.println(cla.getName()); // 全限定名 System.out.println(Modifier.toString(cla.getModifiers())); System.out.println(cla.getSimpleName()); System.out.println(cla.getPackage().getName()); 能够经过Class对象产生该类的对象,以下: // 获取Class对象 Class cla = Student.class; /* 1. 直接建立对象(调用默认无参构造方法),类里必需要有默认构造方法 / Object obj1 = cla.newInstance(); System.out.println(obj1); 2、Constructor 若是想经过有参构造方法来建立对象,那么这时候就得先获取有参构造方法,再经过有参构造方法来建立对象: // 获取Class对象 Class cla = Student.class; / 1. 直接建立对象(调用默认无参构造方法),类里必需要有默认构造方法 / Object obj1 = cla.newInstance(); System.out.println(obj1); / 2. 经过无参构造方法建立对象,和第一种方法效果同样 / Constructor no = cla.getConstructor(); // 先获取无参构造方法 Object obj2 = no.newInstance(); System.out.println(obj2); / 3. 经过有参构造方法建立对象 */ Constructor has = cla.getDeclaredConstructor(String.class,int.class); // 形参 Object obj3 = has.newInstance("老李", 23); // 传入的是实参 System.out.println(obj3); 3、Field Field表明是类中的属性,咱们能够获取属性,并修改其值(注:先得有对象才能修改值,另:修改没权限的属性时,须要先打开该属性的权限)。 // 获取Class对象 Class cla =newStudent().getClass(); // 获取构造方法 Constructor con = cla.getConstructor(String.class,int.class); // 建立对象 Object obj = con.newInstance("如来", 222); // 获取要操做的属性 Field name = cla.getDeclaredField("name"); // 反射操做private属性的时候,须要打开权限 name.setAccessible(true); // 获取obj的name属性值 System.out.println(name.get(obj)); // 把obj的name属性值改成:菩提 name.set(obj, "菩提"); System.out.println(name.get(obj)); // 把id设置为10086 Field id = cla.getDeclaredField("id"); id.set(obj, 10086); System.out.println(id.get(obj)) 4、Method Method表明类中的方法,和Field操做类型: // 获取Class对象 Class cla = Student.class; // 建立对象 Object obj = cla.getDeclaredConstructor(String.class,int.class).newInstance("达摩", 666); // 获取要操做的方法 Method showNo = cla.getDeclaredMethod("show"); Method showHas = cla.getDeclaredMethod("show", String.class); Method calc = cla.getDeclaredMethod("calc",int.class,double.class); calc.setAccessible(true); // 调用方法 showNo.invoke(obj); showHas.invoke(obj, "老衲"); Object value = calc.invoke(obj, 10086, Math.PI); System.out.println(value); 咱们能够用反射来改进简单工厂模式: packagedemo08; importjava.io.FileInputStream; importjava.util.Properties; publicclassPetFactory { publicstaticvoidmain(String[] args) { System.out.println(getInstance("dog")); // demo08.Dog@67a9b034 } // 工厂方法 publicstaticPet getInstance(String tag) { Properties p =newProperties(); try{ p.load(newFileInputStream("conf/pet.properties")); }catch(Exception e) { System.out.println("加载配置文件错误!"); } String className = p.getProperty(tag); try{ // 利用反射建立对象 Class cla = Class.forName(className); return(Pet)cla.newInstance(); }catch(ClassNotFoundException e) { System.out.println("没法识别您的标识!"); }catch(InstantiationException e) { e.printStackTrace(); }catch(IllegalAccessException e) { e.printStackTrace(); } returnnull; } } classPet {} classDogextendsPet {} classCatextendsPet {} classPenguinextendsPet {} conf/pet.properties文件内容以下: dog=demo08.Dog cat=demo08.Cat penguin=demo08.Penguin 这里的配置文件为.properties,称做属性文件。经过反射读取里边的内容。这样代码是固定的,可是配置文件的内容咱们能够改,这样使咱们的代码灵活了不少! 综上JAVA反射的再次学习,灵活的运用它,可以使咱们的代码更加灵活,可是它也有它的缺点,就是运用它会使咱们的软件的性能下降,复杂度增长,因此还要咱们慎重的使用它。 更多内容关注微信公众号mjw-java或访问www.moliying.comjava