黑马程序员_基础加强(反射)
来源:互联网 发布:我的世界0.15.4枪械js 编辑:程序博客网 时间:2024/05/20 17:28
---------------------- ASP.Net+Android+IO开发S、.Net培训、期待与您交流! ----------------------
反射
反射基石--->Class类
Java程序中的各个Java类同属于同一类事物,描述这类事物的Java类名就是Class。
对比提问:众多的人用一个什么类表示?众多的Java类用一个什么类来表示。
人----->Person
Java类----->Class
对比提问:Person类代表人,他 的实例对象就是张三,李四这样一个个具体的人,Class类代表Java类,它的各个实例对象又分别是什么呢?
它的实例对象对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的字节码,等等。
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以他们在内存中的内容是不同的,这一个个的空间
可分别用一个个对象来表示,这些对象显然具有相同的类型,这个类型是什么呢?
Java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例对象来确定的,不同的实例对象有不同的属性值。
Java程序中的各个Java类,它们是否属于同一类事物?是不是可以用一个类来描述这类事物呢?这个类的名字就是Class,要注意与小写class的区别。Class类描述了那些方
面的信息呢?类的名字,类的访问属性,类所属的包名,字段名称的列表,方法名称的列表,等等。学习反射,首先要明白Class类。
Java中类的实例化是:
Person p1 = new Person();
那么Class如何实例化呢?
Class cls1 = 字节码1;
如何得到各个字节码对应的实例对象(Class类型)
1.类名.class。例如:System.class。
2.对象.getClass()。例如:new Date().getClass。
3.Class.forName(“类名”)。例如:Class.forName(“java.util.Date”)//主要用这种方法。
返回这个类的字节码有两种情况:
第一种,这个类的字节码已经加载到内存中,直接返回字节码;第二种,如果JVM中没有这个字节码,类加载器先加载,然后再返回字节码。
九种预定义的Class实例对象:表示八个基本类型和void。这些类对象由 Java 虚拟机创建,与其表示的基本类型同名,即boolean、byte、char、short、int、long、float 和double。
数组的Class实例对象:类型[ ].class,可以用isArray()方法判断一个Class实例是否为数组。
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void...
反射就是把Java类中的各种成分映射成相应的Java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等信息也用一个个Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Filed、method、Contructor、Package等等。
一个类中的每个成员都可用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。
Constructor类
Constructor类代表某个类中的一个构造方法。
得到某个类中所有的构造方法:
举例:Constructor[] constructors = Class.forName("java.lang.String").getConstructors();
得到某个构造方法:
举例:Constructor constructors = 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()
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
该方法内部内部的具体代码是怎样写成的呢?用到了缓存机制来保存默认构造方法的实例对象。
File类File类代表某个类中的一个成员变量。
问题:得到的Filed对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而该类的实例对象有多个,如果是与对象关联,那关联的是哪个对象呢?
所以字段filedX代表的是X的定义,而不是具体的X变量。
练习:将任意一个对象中的所有的String类型的成员变量所对应的字符串内容的“b”改成“a”。
Method类
Method类代表某个类中的一个成员方法。
得到类中的某个方法:
MethodcharAt = Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);
调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式:System.out.println(charAt.invoke(str,1));
`如果传递给Method对象的invoke()方法的一个参数null,这有什么样的意义呢?说明该Method对象对应一个静态方法。
Jdk1.4 和jdk1.5的invoke方法的区别:
Jdk1.5:publicObject invoke(Object obj,Object...args)
Jdk1.4:publicObject invoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用jak1.4改写为charAt.invoke(“str”,new Object[]{1});
用反射方式执行某个类中的main方法。
目标:写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法。
用反射的用处是:将类名也作为参数传递。
问题:
启动Java程序的main方法的参数是一个字符串数组,即public static void main(String[] args),
通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按照jdk1.5的语法,整个数组的一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac会按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按jdk1.4的语法进行处理,即把数组打散成为若干个单独的参数。所以,在给mian方法传递参数时,不能使用代码mainMethod.invoke(null,new String[]{“xxx”});
Javac 只是把它当做jdk1.4的语法进行理解,而不是把它当做jdk1.5的语法解释。因此会出现参数类型不对的问题。
解决办法:
mainMethod.invoke(null,new Object[]{“xxx”});
mainMethod.invoke(null,(Object)newStirng[]{“XXX”}),编译器会作特殊处理,编译时不把参数当作数组看待,也就不会讲数组打散成若干个参数了。
数组的反射
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
基本类型的一维数组可以被当作Object类型使用,不能当做Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Objcet[]类型使用。
Arrays.asList()方法处理int[]和String[]时的差异:public static List asList(Object[] a)//接受一个Object类型的数组。
如果是int类型的数组,把它当成一个Object对象。
而String类型的数组,可以当做Objcet类型的数组使用。
Array工具类用于完成对数组的反射操作。
思考题:怎么得到数组中的元素类型?
只能获取非基本类型数组或Objcet类型数组中某个元素的类型:a[0].getClass().getName()。
不能获取基本类型数组中某个元素的类型。(因为基本数据类型只会被作为一个Object对象传递,而不是一个数组。)
能获取非基本类型数组(例如String类型)中某个元素的类型,并依此判断数组的类型。
如果是Object类型的数组,只能获取其某个元素的类型。
import java.lang.reflect.*;import java.util.*;class ReflectPoint {private int x;public int y;public String str1 = "ball";public String str2 = "bag";public String str3 = "it";ReflectPoint(int x ,int y){//super();this.x = x;this.y = y;}public String toString(){return str1 + ":" + str2 + ":" + str3;}}class ReflectDemo{public static void main(String[] args) throws Exception{ReflectPoint pt1 = new ReflectPoint(3,5);Field fieldY = pt1.getClass().getField("y");/*field 不是对象上的变量,而是类上,而要用它去取某个对象对应的值。getField()只能发现公有的参数。getDeclaredField()可以发现所有的参数。*/Field fieldX = pt1.getClass().getDeclaredField("x");fieldX.setAccessible(true);//设置x可以被获取。System.out.println(fieldY.get(pt1));System.out.println(fieldX.get(pt1));System.out.println(pt1);changeStringValue(pt1);System.out.println(pt1);//method类调用String str1 = "abc";//实例化一个String对象str1 引用字符串abc。//调用string类中的CharAt方法。Method methodCharAt = String.class.getMethod("charAt",int.class);//通过Method类实例化对象调用CharAt方法。System.out.println(methodCharAt.invoke(str1,1));//通过String实例化对象调用String中的CharAt方法。System.out.println(str1.charAt(1));System.out.println(methodCharAt.invoke(str1,new Object[]{2}));System.out.println(str1.charAt(2));//用静态方法调用main函数中并遍历传递的字符串数组的值。TestArguments.main(new String[]{"111","222","333"});//通过反射的方式。//String startingClassName = args[0];//Method mainMethod = Class.forName(startingClassName).getMethod("main",String[].class);//mainMethod.invoke(null,new Object[]{new String[]{"111","222","333"}});//将数组封装成一个数组对象作为参数传递。//数组的反射int[] a1 = new int[3];int[] a2 = new int[4];int[][] a3 = new int[2][3];String[] a4 = new String[3];int[] a5 = new int[]{1,2,3};String[] a6 = new String[]{"a","b","c"};Object[] a7 = new Object[]{"a",1};System.out.println(a1.getClass() == a2.getClass());System.out.println(a1);System.out.println(a1.getClass());System.out.println(a3.getClass());//System.out.println(a1.getClass() == a3.getClass());System.out.println(a1.getClass().getName());System.out.println(a1.getClass().getSuperclass().getName());System.out.println(Arrays.asList(a5));System.out.println(Arrays.asList(a6));printObject(a5);printObject("xyz");System.out.println(a5[1]); // System.out.println(a5[1].getClass().getName());}//打印语句,如果打印的是数组,运用了数组的反射。private 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);}}/*作业:将任意一个对象中的所有String类型的成员变量所对应的字符串内容的“b”改成“a”。*/private static void changeStringValue(Object obj)throws Exception{Field[] fields = obj.getClass().getFields();for (Field field : fields ){if (field.getType() == String.class)//比较是否为String类型的字节码{String oldValue = (String)field.get(obj);String newValue = oldValue.replace('b','a'); field.set(obj,newValue);//将制定对象obj变量上的值换成newValue。}}}}class TestArguments{public static void main(String[] args){for (String arg : args ){System.out.println(arg);}}}
反射的作用
实现框架功能。框架要解决的核心问题:因为在写框架时,你无法知道要调用的类名,所以无法直接new某个类的实例对象,而要用反射的方式来做了
ArrayList 和HashSet:一个无序,一个有序(位置顺序)
注意:HashCode作用。 //使用类加载器的getResourceAsStream()方法InputStream ips=ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");//上边这句是从执行文件的根目录(bin目录,也即package所在的目录)下去找资源文件。
2.绝对路径 获取资源文件
//使用类的getResourceAsStream()方法加载时,如果配置文件前没有"/"表示在在包中与.class同级,如果有"/”则表示与包同级,在根目录。InputStream ips = ReflectTest2.class.getResourceAsStream("config.properties");InputStream ips = ReflectTest2.class.getResourceAsStream("/resource/config.properties");
---------------------- ASP.Net+Android+IO开发S、.Net培训、期待与您交流! ----------------------
- 黑马程序员_基础加强(反射)
- 黑马程序员_基础加强_反射
- 黑马程序员_基础加强_反射
- 黑马程序员_基础加强(3) 反射
- 黑马程序员_<<基础加强---反射>>
- 黑马程序员_基础加强之反射
- 黑马程序员_Java基础加强_反射
- 黑马程序员_Java基础加强_反射
- 黑马程序员_基础加强之反射
- 【黑马程序员】java基础加强_反射
- 黑马程序员_张孝祥_Java基础加强_反射
- 黑马程序员-------(基础加强)反射
- 黑马程序员--基础加强(反射)
- 黑马程序员---java基础加强_成员变量的反射
- 黑马程序员基础加强---反射
- 《黑马程序员》基础加强---反射
- 黑马程序员--基础加强反射
- 黑马程序员-----基础加强-反射
- JS压缩与CSS压缩
- 在sharepoint2010中如何让AD域账号跟sharepoint账号同步
- 更改Eclipse下Tomcat的部署目录
- 直接拿来用!最火的iOS开源项目
- Design Pattern_Interpreter(解释器模式)
- 黑马程序员_基础加强(反射)
- Javascript做模糊查询-数组无双(一)-循环不能不重视
- xcode 无法识别iPad,iPhone真机的问题
- 打开eclipse突然ADT不见了
- 为android的HttpClient添加请求超时 .并作相应处理
- java泛型
- 第一天, C++的初步知识
- HTML中
- 10308 - Roads in the North