------ android培训、java培训、java基础学习技术总结、期待与您交流! ----------
反射
1. 反射的基石--> Class类-->
* java程序中的各个类属于同一类事物,描述这类事物的Java类名就是Class
* 对比提问:众多的人用一个什么类表示?众多的Java类用一个什么类表示?
* 人-->Person
* Java--> Class
* 对比问题:Person类代表人,它的实例对象就是张三,李四这样一个个具体的人,
* Class类代表Java类,它的各个实例对象又分别对应什么呢?
* 对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的字节码,等等。
* 一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容是不同的
* 这一个个的空间可分别用一个个的对象来表示,这些对象显然具有
* 相同的类型,这个类型是什么呢?
* 如何得到各个字节码对应的示例对象(Class类型)
* 类名.class,例如,System.class
* 对象.getClass(),例如,new Date().getClass()
* Class.forName("类名"),例如,class.forName("java.util.Date");
* 九个预定义Class实例对象
* 参看Class.isPrimitive方法的帮助
* int.class==Integer.TYPE
示例1:
public class ReflectTest { public static void main(String[] args) throws ClassNotFoundException { String str1="abc"; Class cls1=str1.getClass(); Class cls2=String.class; Class cls3=Class.forName("java.lang.String"); System.out.println(cls1==cls2); System.out.println(cls1==cls3); System.out.println(cls1.isPrimitive()); System.out.println(int.class.isPrimitive()); System.out.println(int.class==Integer.class); System.out.println(int.class== Integer.TYPE); // System.out.println(int[].class.isPrimitive()); //判断是否是原始类型 System.out.println(int[].class.isArray()); //判断是否为数组类型 } }
* 数组类型的Class示例对象
* Class.isArray()
* 总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[]
* 反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的
* 对象来表示,一个类中的组成部分:成员变量,方法,构造方法,
* 包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个
* 的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造函数,
* 修饰符,包等信息,这些信息就是用相应的类的实例对象来表示,它们是Field\
* Method、Constructor、Package等等。
* 一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的
* 方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?
*怎么用呢? 这正是学习和应用反射的要点。
*Constructor类
*Constructor类代表某个类中的构造方法
*得到某个类所有的构造方法
* 例子:Constrcutor[] constructors=
* Class.forName("java.lang.String").getConstructors();
* 得到某一个构造方法:Constructor constructor=
* Class.forName("java.lang.String").getConStructor(StringBuffer.class);
* //获得方法时要用到类型
* 创建实例对象:
* 通常方式:String str=new String(new StringBuffer("abc"));
* 反射方式:String str=
* (String)constructor.newInstance(new StringBuffer("abc"));
* Class.newInstance()方法:
* 例子:String obj=
* (String)Class..forName("java.lang.String").newInstance();
* 该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
* 该方法内部的具体代码是这样写的呢?用到了缓存机制来
* 保存默认构造方法的实例对象
* class-->constructor-->new object
示例2:
public class ReflectTest2 { public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { Constructor constructor1=String.class.getConstructor((StringBuffer.class)); String str2=(String) constructor1.newInstance(new StringBuffer("abc"));// 需要产生同样类型的对象 System.out.println(str2.charAt(2)); } }
* Field类
* Field类代表某个类中的一个成员变量
* 演示用eclipse自动生成Java类的构造方法
* 问题:得到的Field对象是对应到类上面的成员变量,
* 还是对应到对象上的成员变量?类只有一个,而该类的
* 实例对象有多个, 如果是与对象关联,哪关联的是哪一个对象呢?
* 所以字段FieldX代表的是x的定义,而不是具体的x变量。
示例1:
public class ReflectPoint { private int x; private int y; Date birthday=new Date(); public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public ReflectPoint(int x, int y) { super(); this.x = x; this.y = y; } public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { // TODO Auto-generated method stub ReflectPoint pt1=new ReflectPoint(3,5); Field fieldY =pt1.getClass().getField("y"); //fielY的值是多少呢?是5,错!fieldY不是对象身上的变量,而是类上,要用它 System.out.println( fieldY.get(pt1)); Field fieldX=pt1.getClass().getDeclaredField("x"); fieldX.setAccessible(true); System.out.println(fieldX.get(pt1)); } @Override public String toString() { return "ReflectPoint [x=" + x + ", y=" + y + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + x; result = prime * result + y; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ReflectPoint other = (ReflectPoint) obj; if (x != other.x) return false; if (y != other.y) return false; return true; } }
* 作业:将任意String变量中的'b'改成'a'.
* Method类
* Method类代表某一个类中的一个成员方法
* 得到类中的某一个方法:
* 例子: Method charAt=
* Class.forName("java.lang.String").getMethod("charAt",int.class);
* 调用方法:
* 通常方式:System.out.println(str.chatAt(1));
* 反射方式: System.out.println(charAt.invoke(str,1));
* 如果传递给method对象的invoke()方法的一个参数为null,
* 这有着什么样的意义呢?说明该Method对象对应的是一个
* 静态方法!
* jdk 1.4和jdk 1.5的invoke方法的区别:
* Jdk1.5:public Object invoke(Object obj,Object... args)
* Jdk 1.4 public Object invoke(Object obj,Object[] args),
* 即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法是,数组中的
* 每一个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的
* 代码也可以用jdk 1.4改写为charAt.invoke("str",new Object[]{1}形式。
* 用反射的方式执行某个类中的main方法
* 目标
* 写一个程序,这个程序能够根据用户提供的类名,去执行类中的main方法。
* 问题:
* 启动Java程序的main方法的参数是一个字符串数组,即public static void
* main(String[] args),通过反射的方式来调用这个main方法时,如何为
* invoke方法传递参数呢?按jdk1.5的语法,整个数组是一个参数,而按jdk 1.4的语法,
* 数组中的每一个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法
* 时,javac会到底按照那种语法进行处理,及把数组打散成为若干个单独的参数
* 。所以,在main方法传递参数时,不能使用代码
* mainMethod.invoke(null,new String[]{"xxx"});,javac只把它当作jdk 1.4的语法进行
* 理解,而不把它当成jdk 1.5的语法解释,因此会出现参数类型不对的问题。
* 解决办法:
* mainMethod.invoke(null,new Object[]{new String[]{"xxx"});
* mainMethod.invoke(null,(Object)new String[]{"xxx"});,编译器会作特殊处理,
* 编译时不把参数当作数组看待,也就不会数组打散成若干个参数了
示例2:
public class ReflectPoint2 { private int x; private int y; public String str1="ball"; public String str2="basketball"; public String str3="itcast"; public ReflectPoint2(int x, int y) { super(); this.x = x; this.y = y; } public String toString(){ return str1+"::"+str2+"::"+str3; } public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException { // TODO Auto-generated method stub String str1="abc"; ReflectPoint2 pt2=new ReflectPoint2(3,5); changeStringValue(pt2); System.out.println(pt2); Method methodCharAt= String.class.getMethod("charAt",int.class); System.out.println(methodCharAt.invoke(str1, 1)); System.out.println(methodCharAt.invoke(str1, new Object[]{2})); //TestArguments.main(new String[]{"abc","xyz","123"}); String startingClassName=args[0]; Method mainMethod=Class.forName(startingClassName).getMethod("main", String.class); mainMethod.invoke(null, (Object)new String[]{"abc","xyz","123"}); } private static void changeStringValue(Object obj) throws IllegalArgumentException, IllegalAccessException{ Field[] fields=obj.getClass().getFields(); for(Field field:fields){ if(field.getType()==String.class){ String oldValue=(String)field.get(obj); String newValue=oldValue.replace('b', 'a'); field.set(obj, newValue); } } } } class TestArguments{ public static void main(String[] args){ for(String arg:args){ System.out.println(arg); } } }
* 数组的反射
* 具有相同的维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
* 代表数组的Class实例对象的getSuperClass()方法返回的父类
* 为Object类对应的Class。
* 基本类型的一位数组可以当作Object类型使用,不能当作
* Object[]类型使用;非基本类型的一位数组,即可以当作Object类型使用
* ,又可以当作Object[]类型使用。
* Arrays.asList()方法处理int[]和String[]时的差异。
* Array工具类用于完成对数组的反射操作。
* 思考题:怎么得到数组中的元素类型?
示例3:
public class ReflectPoint3 { public static void main(String[] args) { int[] a1=new int[3]; int[] a2=new int[4]; int[][] a3=new int[2][3]; String[] a4=new String[3]; System.out.println(a1.getClass()==a2.getClass()); /* System.out.println(a1.getClass()==a4.getClass()); System.out.println(a1.getClass()==a3.getClass()); */ System.out.println(a1.getClass().getName()); System.out.println(a1.getClass().getSuperclass().getName()); System.out.println(a4.getClass().getSuperclass().getName()); Object aObj1=a1; Object aObj2=a4; //Object[] aObj3=a1; Object[] aObj4=a3; Object[] aObj5=a4; System.out.println(Arrays.asList(a1)); System.out.println(Arrays.asList(a4)); Object obj=null; printObject(obj); } public static void printObject(Object obj){ Class clazz=obj.getClass(); if(clazz.isArray()){ int len=Array.getLength(obj); for(int i=0;i<len;i++){ System.out.println(Array.get(obj, i)); } }else{ System.out.println(obj); } } }
* 反射的作用-->实现框架功能
* 框架与框架要解决的核心问题
* 我做房子卖给住户,由用户自己安装门窗和空调,我做的房子就是框架,
* 用户需要使用我的框架,把门窗插入我提供的框架中,框架与工具有区别,
* 工具类被用户的类调用,而框架则是调用用户提供的类
* 框架要解决的核心问题
* 我在写框架(房子)时,你这个用户可能还在上学,还不会写程序呢?
* 我写的框架程序怎样能调用你以后写的类(门窗)呢?
* 因为在写程序时无法知道要被调用的类名,所以,在程序中无法直接new某个类
* 的实例对象了,而要用发射方式来做。
* 综合案例
* 先直接用new语句创建ArrayList和HashSet的实例对象,演示用eclipse自动生成
* ReflectPoint类的equals和hashcode方法,比较两个集合的运行结果差异。
* 然后改为采用配置文件加反射的方式创建ArrayList和HashSet的实例对象,比较
* 观察运行结果差异。
* 引入了eclipse对资源文件的管理方式的讲解
* 内省 -->IntroSpector-->对JavaBean进行操作-->特殊的Java类-->javaBean的属性根据方法取出来
* 符合 int getAge()
* void setAge(int age) 这样规则的类叫做JavaBean。
* Age -->如果第二个字母是小的,则把第一个字母变成小的--age
* gettime-->time
* setTime-->time
* setCPU-->CPU
* isLast()-->last
* JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省
示例6:
public class ReflectTest3 { public static void main(String[] args) throws IOException, InstantiationException, IllegalAccessException, ClassNotFoundException { // TODO Auto-generated method stub //InputStream ips=new FileInputStream("config.properties"); //InputStream ips=ReflectTest3.class.getClassLoader().getResourceAsStream("cn/itcast/study2/config.properties"); InputStream ips=ReflectTest3.class.getResourceAsStream("config.properties"); Properties props=new Properties();// props.load(ips); ips.close(); String className=props.getProperty("className"); Collection collections=(Collection)Class.forName(className).newInstance(); //Collection collections=new HashSet(); ReflectPoint pt1=new ReflectPoint(3,3); ReflectPoint pt2=new ReflectPoint(5,5); ReflectPoint pt3=new ReflectPoint(3,3); collections.add(pt1); collections.add(pt2); collections.add(pt3); collections.add(pt1); System.out.println(collections.size()); } }
示例7:
public class IntroSpectorTest { public static void main(String[] args) throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { // TODO Auto-generated method stub ReflectPoint pt1=new ReflectPoint(3,5); String propertyName="x"; //"x"-->"X"-->"getX"-->MethodX--> Object retVal; PropertyDescriptor pd = getProperty(pt1, propertyName); Object value=7; setProperty(pt1, pd, value); System.out.println(BeanUtils.getProperty(pt1, "x").getClass()); BeanUtils.setProperty(pt1, "x", "9"); /*Map map={name:"zxx",age:18}; BeanUtils.setProperty(map, "name", "1hm"); BeanUtils.setProperty(map, "name", "111");*/ BeanUtils.setProperty(pt1, "birthday.time", "111"); System.out .println(BeanUtils.getProperty(pt1, "birthday.time")); PropertyUtils.setProperty(pt1, "x",9); System.out.println(PropertyUtils.getProperty(pt1, "x")); } private static void setProperty(ReflectPoint pt1, PropertyDescriptor pd, Object value) throws IllegalAccessException, InvocationTargetException { Method methodSetX=pd.getWriteMethod(); methodSetX.invoke(pt1, value); System.out.println(pt1.getX()); } private static PropertyDescriptor getProperty(ReflectPoint pt1, String propertyName) throws IntrospectionException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { Object retVal; PropertyDescriptor pd=new PropertyDescriptor(propertyName,pt1.getClass()); Method methodGetX=pd.getReadMethod(); retVal=methodGetX.invoke(pt1); System.out.println(retVal); return pd; } }
相关推荐
黑马程序员_毕向东_Java基础视频教程第18天-14-IO流(拷贝文本文件图例).zip
Java 8是Java语言发展的一个重要里程碑,引入了许多创新性的特性和改进,...黑马程序员的Java8新特性详解笔记和源码提供了深入学习这些概念的资源,结合实际的代码示例,将有助于你更好地理解和掌握Java 8的核心特性。
在"黑马程序员_Java基础辅导班教程课件[第01期]第13天"中,我们聚焦于Java编程语言的基础知识,这是一门面向初学者的课程,旨在帮助学员快速掌握Java开发的基本技能。第13天的课程通常会涵盖上一天(第12天)所学...
《黑马程序员_Java基础辅导班教程课件[第01期]第15天》是针对初学者设计的一堂深入浅出的Java编程课程,旨在帮助学员巩固和深化Java基础知识。这堂课件涵盖的内容广泛且实用,对于想要在IT行业中开启Java开发旅程的...
《黑马程序员_hibernate框架开发2016版讲义...通过对黑马程序员提供的这门课程的学习,开发者不仅能掌握Hibernate的核心概念和技术,还能提升在实际项目中的数据库操作效率,为构建高效、稳定的Java应用打下坚实基础。
黑马程序员__移动商城项目实战 包括黑马程序员乐淘商城实战和慕课React+Antd
【标题】"01_黑马程序员_张孝祥_Java基础加强_课程价值与目标介绍.zip" 提供的是一门由黑马程序员机构推出的Java基础强化课程,由讲师张孝祥主讲,旨在深入讲解Java编程的基础知识并进行能力提升。 【描述】中提到...
总的来说,黑马程序员的Java基础辅导班教程旨在通过第14天的课程,使学员对Java语言有更深入的理解,掌握核心概念和技术,为进一步的Java学习打下坚实的基础。通过不断的实践和练习,学员将能够运用所学知识解决实际...
黑马程序员_张孝祥_Java多线程与并发库,老师讲的非常仔细,老师很有耐心.欢迎大家下载学习.
黑马程序员_毕向东_Java基础视频教程第18天-09-IO流(文件的续写)
这个名为“黑马程序员_毕向东_Java基础源码.rar”的压缩包文件,包含了丰富的Java基础源代码实例,对于初学者来说,是深入了解Java编程的良好资源。 一、Java基本语法 Java语言以其严格的类型检查和面向对象特性...
"黑马程序员_Java基础辅导班教程课件[第01期]第11天"是一个专门为初学者设计的培训课程,旨在帮助学员深入理解和掌握Java的核心概念。这个课程可能是通过视频形式进行的,结合了理论讲解和实际操作,以便让学习者能...
《Hibernate框架深度解析——基于黑马程序员2016版教学资料》 Hibernate,作为一个强大的对象关系映射(ORM)框架,极大地简化了Java开发者在数据库操作中的工作。它通过提供数据持久化的对象模型,使得开发者可以...
马程序员_黎活明__Spring如何装配各种集合类型的属性.ppt )
在本视频教程“黑马程序员_毕向东_Java基础视频教程第22天-06-GUI(Action事件)”中,讲师毕向东深入讲解了Java GUI中的Action事件处理机制,这是构建用户友好界面的关键部分。 首先,我们要理解什么是GUI。GUI,...
Java是世界上最流行的编程语言之一,尤其在企业级应用开发领域占据主导地位。对于初学者来说,选择合适的资源来学习Java是非常重要的。"黑马程序员_(适合初学者入门的Java基础视频)"是一套专为初学者设计的Java...
黑马程序员毕向东java基础视频教程全套
在"黑马程序员_Java基础辅导班教程课件[第01期]第5天"中,我们主要聚焦于Java编程语言的基础知识。这是一份专为初学者设计的教学资源,旨在帮助学员扎实地掌握Java编程的基本概念和技能。第5天的课程可能涵盖了变量...
【Java基础辅导班教程课件】是针对初学者设计的一系列教学资源,旨在帮助学习者扎实掌握Java编程语言的基础知识。第01期第8天的课程内容可能涵盖了上一阶段的学习总结,以及新的概念和技术的引入。在这个阶段,学员...
黑马程序员_毕向东_Java基础视频教程第05天-01-面向对象(概述).avi