1、反射含路径问题部分笔记源文件来自Y2笔记 反射(Reflect)反射即将Class类中的所有的成员映射为相应的对象。要学习反射那么需要先了解和掌握以下几个类:类描述Class描述所有的Class文件的共性Filed描述的是Class文件的中的属性的共性Constructor描述的是Class文件中的构造函数的共性Method描述的是Class文件中的函数的共性1. 获取指定类的Class对象方式一: 类名.class方式二: 对象名.getClass() 方式三: forName(String className) 该方法是Class类的静态方法 推荐举例1: 获取字符串类的Class对象。
2、public static void main(String args)throws Exception / 使用不同的方式会过去Class对象 Class clazz1 = String.class; Class clazz2 = new String(zhangsan).getClass(); / 参数必须指定类的全名(类的全限定名) Class clazz3 = Class.forName(java.lang.String); / class文件时候独一无二的,那么Class对象也应该是单例的 System.out.println(clazz1 = clazz2); / true Sys
3、tem.out.println(clazz2 = clazz3); / true 以上的方式都可以获取指定类的Class对象,在实际的开发中到底要使用哪一个?一般的情况下我们都需要在不知道类名的情况下获取类的Class对象并进而获取类中包含的成员进行操作。大家可以参考Tomcat的一个基本的server.xml文件2. 将Class对象中的属性进行反射为Filed对象常用的获取属性字段的方法方法描述Field getDeclaredFields()获取所有声明的字段数组对象Field getFields()获取所有的声明的共有字段数组对象Field getDeclaredField(Strin
4、g name)获取指定名称的声明的字段对象Field getField(String name)获取指定名称的声明的共有字段对象举例1:获取所有的声明字段数组对象。 public static void main(String args)throws Exception / 获取Shape类的Class对象 Class clazz = Class.forName(cn.sve.bean.Shape); / 获取所有的属性 Field fs = clazz.getDeclaredFields(); System.out.println(fs.length); / 2 / 获取所有共有的属性 fs
5、 = clazz.getFields(); System.out.println(fs.length); / 1 / 获取指定名字的私有的属性 Field field = clazz.getDeclaredField(x); System.out.println(field); / 获取指定名字的共有的属性 field = clazz.getField(y); System.out.println(field); 举例2:调用Field类的方法进行字段对象的操作。 public static void main(String args)throws Exception / 获取Shape类的C
6、lass对象 Class clazz = Class.forName(cn.sve.bean.Shape); / 获取所有的属性 Field fs = clazz.getDeclaredFields(); System.out.println(fs.length); / 2 / 获取所有共有的属性 fs = clazz.getFields(); System.out.println(fs.length); / 1 Shape shape = new Shape(); / 20 / 获取指定名字的私有的属性 Field field = clazz.getDeclaredField(x); Sys
7、tem.out.println(field); / 操作私有的属性x System.out.println(属性名: +field.getName(); / 获取x的属性值,需要暴力的反射 field.setAccessible(true); System.out.println(设置之前的x值:+field.get(shape); / 设置x的属性值 field.set(shape, 20); System.out.println(设置之后的x值:+field.get(shape); / 获取指定名字的共有的属性 field = clazz.getField(y); System.out.p
8、rintln(field); / 给属性y进行设置值 System.out.println(属性名: +field.getName(); / 获取设置属性值之前的值 System.out.println(设置之前的y值:+field.get(shape); / 20 field.set(shape,30); / 30 System.out.println(设置之后的y值: +shape.y); / 30以上的代码可以通过程序进行反射类中的属性字段并操作,但是没有进行静态属性的反射和操作。举例3:反射静态的成员属性。public static void main(String args)thro
9、ws Exception / 获取Shape类的Class对象 Class clazz = Class.forName(cn.sve.bean.Shape); / 获取共有的静态属性 Field field = clazz.getField(z); System.out.println(设置之前的z值: +field.get(null); field.set(null, 40); System.out.println(设置之后的z值: +field.get(null);3. 将Class对象中的方法进行反射为Method对象。public static void main(String arg
10、s)throws Exception / 获取Shape类的Class对象 Class clazz = Class.forName(cn.sve.bean.Shape); / 获取所有的声明的方法 Method ths = clazz.getDeclaredMethods(); System.out.println(ths.length); / 2 / 获取私有的带参数的sayHello方法 Method sayHello = clazz.getDeclaredMethod(sayHello, String.class); System.out.println(sayHello); / 调用私
11、有的方法 sayHello.setAccessible(true); sayHello.invoke(new Shape(), zhangsan); / 获取所有的共有的方法 ths = clazz.getMethods(); System.out.println(ths.length); / 10 / 获取带参数的共有的 方法 Method greet = clazz.getDeclaredMethod(greet, String.class); System.out.println(greet); / 方法的调用 greet.invoke(new Shape(), zhangsan);4.
12、 将Class对象中的构造函数进行反射为Constructor对象。public static void main(String args)throws Exception / 获取Shape类的Class对象 Class clazz = Class.forName(cn.sve.bean.Shape); / 获取所有的声明的构造函数 Constructor cons = clazz.getDeclaredConstructors(); System.out.println(cons.length); / 3 / 获取带参数的私有的构造函数对象 Constructor con = clazz.
13、getDeclaredConstructor(int.class,int.class); System.out.println(con); / 暴力反射私有的构造函数创建对象 con.setAccessible(true); Shape myshape = (Shape) con.newInstance(400,500); System.out.println(myshape.getX()+,+myshape.y); / 获取所有的共有的构造函数 cons = clazz.getConstructors(); System.out.println(cons.length); / 2 con =
14、 clazz.getConstructor(int.class); System.out.println(con); / 调用构造函数创建对象 Shape shape = (Shape) con.newInstance(100); System.out.println(shape.getX();面试题:请简单的叙述出你所可以创建的对象的几种方式?第一种:直接使用new关键字第二种:Construnctor.newInstance第三种:枚举第四种:单例、工厂模式 内省(Introspect)其实在以上的反射技术体验中我们发现其实反射的对象一般是一个具有特定功能的一个类。引入一个基本的概念:Ja
15、vaBean如果一个类提供了封装好的属性、构造函数(无参数)、共有的get和set方法以及简单的业务逻辑方法那么将这样的一个类称之为JavaBean类。对于一个javaBean的操作无非就是给属性值进行操作或函数的调用。使用反射比较繁琐,那么SUN就提供了内省的技术方便大家进行JavaBean类的操作。类描述BeanInfo对JavaBean进行描述的接口Introspector描述所有的JavaBean的成员类PropertyDescriptor描述的是JavaBean的属性类举例1:使用属性描述器类操作JavaBean属性。创建一个Book的javabean类public class Bo
16、ok private String name; / null private String author; / null private double price; / 0.0 private Date date; / null public Book() super(); public Book(String name, String author, double price, Date date) super(); this.name = name; this.author = author; this.price = price; this.date = date; / 省略get和se
17、t方法使用内省技术进行简单的属性的操作。public static void main(String args) throws Exception / 获取一个属性的描述器对象就相当于获取了属性的名、set和get方法 PropertyDescriptor pd = new PropertyDescriptor(name,Book.class); / 获取set方法 Method set = pd.getWriteMethod(); / 调用该方法设置属性的值 Book book = new Book(); System.out.println(设置前获取name属性值:+book.getNa
18、me(); set.invoke(book, JavaSE进阶); System.out.println(设置后获取name属性值:+book.getName(); / 获取get方法 Method get = pd.getReadMethod(); System.out.println(get.invoke(book, null);以上的代码每次都只能操作一个属性,这样就比较繁琐。可以使用其他的类直接获取所有的属性描述器通过循环来直接操作。public static void main(String args) throws Exception / 获取指定的BeanInfo对象 BeanI
19、nfo info = Introspector.getBeanInfo(Book.class); / 获取Book类中的所有的属性的描述器对象 PropertyDescriptor pds = info.getPropertyDescriptors(); / 输出长度 System.out.println(pds.length); / 查看数组的第一个属性描述器是谁 PropertyDescriptor pd = pds0; / 作者 System.out.println(pd.getName(); Book book = new Book(); / 给书设置作者信息 pd.getWriteM
20、ethod().invoke(book, zhangsan); System.out.println(pd.getReadMethod().invoke(book, null);总结:其实发现在使用内省进行属性操作的时候要结合反射一起使用。面试题:一个JavaBean中为什么必须要提供一个无参数的构造函数?原因一:为了可以做父类。原因二:为了可以使用反射创建对象。 BeanUtils工具在实际的开发中我们经常需要将用户的录入的数据进行封装为对象,那么如果使用反射和内省技术就会变得吃力。因此本节主要给大家讲解一个开源的操作JavaBean的一个工具即BeanUtils。下载: http:/www
21、.apache.org beanutils-1.8.0.zipcommons-logging.jar包的引入:在项目中创建一个文件夹如libs,然后将整个项目需要的第三方的jar包可以直接拷贝带该目录,随后打开该目录全选右键Build path add path 看到奶瓶子即可举例1:使用BeanUtils工具封装用户提交的数据。public static void main(String args)throws Exception / 模拟用户的输入的数据如下 String name = XML基础; String author = zhangsan; String price = 99.9
22、9; String date = 2016-07-07; Book book = new Book(); / 任务是将以上的属性设置给指定的Book对象 BeanUtils.setProperty(book, name, name); BeanUtils.setProperty(book, author, author); BeanUtils.setProperty(book, price,price ); / 查看属性是否封装好 System.out.println(book);发现使用上面的代码可以省略基本数据类型的转型的问题。进而提高代码的开发效率。举例2:自定义一个类型转换器类。pub
23、lic static void main(String args)throws Exception / 模拟用户的输入的数据如下 String name = XML基础; String author = zhangsan; String price = 99.99; String date = 2016-07-07; Book book = new Book(); / 注册一个自己的转换器 /* * converter指定具体的转换器 * clazz遇到什么类型调用上面的转换器 */ ConvertUtils.register( new Converter() / 回调方法 Override
24、public Object convert(Class type, Object value) if(value = null) return null; / 转换为String String data = (String)value; / 将指定格式的字符串转换为Date SimpleDateFormat format = new SimpleDateFormat(yyyy-MM-dd); Date date = null; try date = format.parse(data); return date; catch (ParseException e) e.printStackTra
25、ce(); return null; , Date.class); / 任务是将以上的属性设置给指定的Book对象 BeanUtils.setProperty(book, name, name); BeanUtils.setProperty(book, author, author); BeanUtils.setProperty(book, price,price ); BeanUtils.setProperty(book, date,date ); / 查看属性是否封装好 System.out.println(book);如果每次遇到一个复杂类型都需要自定义转换器,那样的话实在麻烦。大家看在
26、开发的时候可以先查看该接口是否提供了有效的实现类。ConvertUtils.register(new DateLocaleConverter(), Date.class);其实真正的封装好的数据需要存储在数据库中,那么javabean的数据类型应该和数据库的数据类型保持一致,那么在声明持久化javabean的时候需要全部为数据库的基本数据类型。因此大家在JavaBean中需要导入的是java.sql.Date类,这样就直接可以将日期自动转换了。举例3:实现封装好的JavaBean对象的属性拷贝。/ 实现属性封装数据的一个拷贝Book copy = new Book();System.out.p
27、rintln(copy);PropertyUtils.copyProperties(copy, book);System.out.println(copy);思考:如果使用BeanUtils封装用户的数据,那么也就是一个一个设置啊?岂不是也很麻烦?其实在真是的环境中我们可以直接获取用户提交的所有的数据信息,只需要进行遍历即可,但是为了方便快速的设置,那么可以将javabean中的属性名和用户提交的数据名保持一致。框架体验其实所谓的框架就是通过一些配置文件来将需要运行的模块以及类、方法在软件启动的时候自动运行。如果将需要运行类以及模块配置在文件中那么便于后期的一个维护。1. 创建一个配置文件如下
28、run=cn.sve.service.UserServiceme=autoRunvalue=jack,lucy2. 创建两个实现接口的服务类UserService.javapublic class UserService implements Service / 提供自动运行的方法 public void autoRun(String names) / 使用,号切割用户列表 String ns = names.split(,); / 遍历 for(String name:ns) System.out.println(姓名: +name); StartService.javapublic class StartService implements Service / 提供自动运行的方法 public void autoRun(String names) / 使用,号切割用户列表 String ns = names.split(,); / 遍历 f
copyright@ 2008-2023 冰点文库 网站版权所有
经营许可证编号:鄂ICP备19020893号-2