黑马程序员——反——射

来源:互联网 发布:雅思网络课程百度云 编辑:程序博客网 时间:2024/05/17 02:33

---------------------- 黑马程序员 Android培训、期待与您交流! ----------------------

Class类

 

/*

 * 对比提问:众多的人用一个什么类表示?众多的Java类用一个什么类表示?

 * class

 * Class-->代表一类什么样的事物?

 *

 * Person p1 = new Person();

 * Person p2 = new Person();

 *

 * Date

 *

 * Math

 *

 *

 * Class cls1 = Date.class//字节码1--->获取Date数据类的字节码

 * Class cls2 = Person.class//字节码2--->获取Person类的字节码

 *

 * //获取p1这个对象的字节码

 * p1.getClass(); 

 *

 * //通过指定路径获取字节码

 * Class.forName("java.lang.String");

 *

 * 面试题:Class.forName的作用?

 * 答:它的作用是返回字节码,返回的方式有两种:

 *     1.第一种是这个字节码曾经被加载过,已经待在Java虚拟机里面了,直接返回

 *     2.第二种是Java虚拟机里面还没有这份字节码,则用加载器加载,

 *       把加载进来的代码缓存到虚拟机里面,以后要得到这份字节码就不用加载了

 *      

 * 如何得到各个字节码对应的实例对象( Class类型)

 * 类名.class,例如,System.class

 * 对象.getClass(),例如,new Date().getClass()

 * Class.forName("类名"),例如,Class.forName("java.util.Date");

 *

 * 总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[]void…

* isPrimitive:判断数据是否为基本数据类型:大概自己的理解。例如:132,如果是基本数据类型,那就定义一个int接收它。

 * 判断基本类型的字节码是否为同一基本类型

 * 基本数据类型只有那么8种而已: byte,short,int,long,float,double,char,boolean

 */

public class _05_Class类概述 {       public static void main(String[]args)throws Exception{             String str = "abc";             //获取字节码       Class cls1 = str.getClass();       Class cls2 = String.class;       Class cls3 = Class.forName("java.lang.String");             System.out.println("cls1与cls2的字节码相同吗?"+(cls1==cls2));       System.out.println("cls1与cls3的字节码相同吗?"+(cls1==cls3));       //总结:获取到的String类的字节码是相同的             //判断基本类型的字节码是否为同一基本类型       //基本数据类型只有那么8种而已: byte,short,int,long,float,double,char,boolean       System.out.println("cls1获取的字节码是一个基本类型吗?"+cls1.isPrimitive());       System.out.println("int类型的字节码是一个基本类型吗?"+int.class.isPrimitive());       System.out.println("int类字节码和Integer类字节码是一个基本类型吗?"+(int.class == Integer.class));       System.out.println("int类字节码和Integer.TYPE包装类的基本类型字节码是一个基本类型吗?"+(int.class == Integer.TYPE));       System.out.println("int数组类型的字节码是一个基本类型吗?"+int[].class.isPrimitive());       System.out.println("一个int[]类型的数组,是一个数组文件吗?"+int[].class.isArray());          } }


反射

l反射就是把Java类中的各种成分映射成相应的java类。
例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。
l

lConstructor

lConstructor类代表某个类中的一个构造方法
/*
 * Constructor的两个步骤(记住)
 * 1. 获取方法(获取参数类型的字节码) :指定参数类型
 *    Constructor constructor = String.class.getConstructor(StringBuffer.class);
 * 2. 调用方法:newInstance实例化,并指定参数类型的具体参数:如向StringBuffer中添加参数
 *  String str = (String)constructor.newInstance(new StringBuffer("abc"));
 * ----------------------------------------------------------------------------
 * 记住::::反射会导致程序性能严重下降
 * ----------------------------------------------------------------------------
 * Class.newInstance方法与constructor.newInstance构造方法的区别?
 * Class.newInstance方法并不影响Java开发和应用,但是为什么提供这个方法呢?
 * 是提供一个便利,我们创建对象步骤是:class-->constructor--new Object
 * Constructor constructor = String.class.getConstructor(StringBuffer.class);
 * 
 * 它帮我们将中间的步骤省略了,直接帮我们在内部完成了new Object对象
 * 举例:你想喝可乐,每天找我买,那么我就想我直接卖你可乐
 * 
 * Class.newInstance()方法,它就是在找那个不带参数的构造方法。Instance-->实例、实体
 * 然后用那个构造方法去创建实例对象(假如我们正好用那个不带参数的构造方法,
 * 那么我就可以直接用class.newInstance()方法,这样可以省点事儿)
 * 
 * 该方法内部的具体代码是怎样写的呢?
 * 用到了缓存机制来保存默认构造方法的实例对象。
 */

public class _05_1Constructor构造方法 {public static void main(String[]args)throws Exception{//new String(new StringBuffer("abc"));//调取String类的哪个构造方法(参数类型...)JDK1.5新特性,可接受可变参数类型Constructor constructor = String.class.getConstructor(StringBuffer.class);//Constructor constructor = String.class.newInstance("这里放无参数构造方法");//传进去一个对象。//(上面的StringBuffer是调用哪个构造方法,下面的是往调用的对象里面传入一个对象,上下必须保持一致)//注意:需要对接收类型进行强转。因为newInstance的返回值类型是ObjectString str = (String)constructor.newInstance(new StringBuffer("abc"));//求String的第2个字符System.out.println(str.charAt(2));}}

Field类(成员变量)

lField类代表某个类中的一个成员变量
l

/*

 * 反射:解析

 * 例如一个对象中,有很多String类型的成员变量。我们想对String类型变量进行某个字符替换(如将所有String类型的'b'字母替换成'a')

 * 那么我们就用反射,获取这个对象中Field类中的String成员变量,通过数组接收,得到类的字节码

 * 然后进行遍历,先判断,获取到的field数组是否为String.class类型的,

 * 如果是,通过(String)Sfield.get(obj)方法获取字节码,

 * 然后,进行替换,再将替换后的,通过field.set方法进行更新

 *

 *

 * Field类代表某个类中的一个成员变量

 * getClass();得到类的字节码

 * getField();得到类中的某个成员字段

 * getDeclaredField();对私有的x变量,进行获取

 * setAccessible(true);强行设置访问(这就叫做暴力反射”)

 */

import java.lang.reflect.Field;import java.lang.reflect.Method;public class _06_Field反射 {private static Object str1;public static void main(String[]args)throws Exception{ReflectPoint p = new ReflectPoint(3,5);//获取Person类中的某个成员变量的字段//1.先得到类的字节码p.getClass()//2.然后再得到类中的某个成员字段.getField("y");Field fY = p.getClass().getField("y");//fY的值是多少?是5,错!!//fY获取的不是对象身上的变量,而是类上,要用它去取某个对象上对应的值//fY不代表具体变量的值,它只是获取到对象的字段//想要获取对象的具体值,System.out.println(fY.get(p));//通过get获取具体对象身上的值//Field fX = p.getClass().getField("x");//通过getDeclaredField()方法,对私有的x变量,进行获取Field fX = p.getClass().getDeclaredField("x");fX.setAccessible(true);//强行设置访问(这就叫做“暴力反射”)System.out.println(fX.get(p));/* ------------------------------------- * 通过反射,将字符串中所有的b 替换成 a * ------------------------------------- */changStringValue(p);//传进来一个对象System.out.println(p);}private static void changStringValue(Object obj) throws Exception{//通过成员变量数组,获取传入对象的变量      Field[] fields = obj.getClass().getFields();//进行迭代for(Field field : fields){//使用equals与==的区别//field.getType().equals(String.class)//通过字段本身类型与String类型相比较,因为都是字节码,所以使用==if(field.getType()==String.class){String oldValue = (String)field.get(obj); //获取对象中的字节码String newValue = oldValue.replace('b', 'a');//进行替换field.set(obj, newValue);//通过field进行更新}}}}

Method类(方法)

lMethod类代表某个类中的一个成员方法
l
l调用方法:
Ø通常方式:System.out.println(str.charAt(1));
Ø反射方式: System.out.println(charAt.invoke(str, 1));
•如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法!
ljdk1.4和jdk1.5的invoke方法的区别:
ØJdk1.5:public Object invoke(Object obj,Object... args)
ØJdk1.4:public Object invoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, new Object[]{1})形式。
l
public class _07_反射Method {public static void main(String[]args) throws Exception{/* ------------------------------------- * 通过反射,获取方法Method * ------------------------------------- */String str = "abc";Method methodCharAt = String.class.getMethod("CharAt",int.class);System.out.println(methodCharAt.invoke(str, 1));//如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?//  说明该Method对象对应的是一个静态方法!System.out.println(methodCharAt.invoke(null, 1));//System.out.println(methodCharAt.invoke(str, new Object[](2)));}}

数组的反射

l具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
l代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
l
package cn.itcast.day1;import java.lang.*;import java.lang.reflect.Array;import java.util.Arrays;public class _09_Array数组 {public static void main(String[] args) throws Exception{int[] a1 = new int[]{1,2,3};int[] a2 = new int[4];int[][] a3 = new int[2][3];String []a4 = new String[]{"a","b","c"};System.out.println(a1.getClass()==a2.getClass());System.out.println(a1.getClass()==a2.getClass());//System.out.println(a1.getClass()==a3.getClass());System.out.println(a1.getClass().getName());//结果:[I  [代表数组 I代表整数intSystem.out.println(a1.getClass().getSuperclass().getName());//父类名System.out.println(a4.getClass().getSuperclass().getName());Object o1 = a1;Object o2 = a4;//Object[] o3 = a1;错误Object[] o4 = a3;Object[] o5 = a4;System.out.println(a1);System.out.println(a4);//数组转成集合进行输出System.out.println(Arrays.asList(a1));System.out.println(Arrays.asList(a4));//数组的反射应用printObject(a4);printObject("ab");}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);}}}

内省

lJavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。
l

定义一个可以用JavaBean操作的类

public class ReflectPoint {private int x;public int y;private Date birthday = new Date();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 String str1 = "basket";public String str2 = "badseber";public String str3 = "itcast";public ReflectPoint(int x, int y) {super();this.x = x;this.y = y;}//覆盖toString方法public String toString(){return str1+"::"+str2+"::"+str3;}}

JavaBean代码块

/* * 内省:IntroSpector --> JavaBean --> 特殊的Java类 * JavaBean的属性是根据其中的setter和getter方法来确定的, * 而不是根据其中的成员变量。如果方法名为setId,中文意思即为设置id * 去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的, * 则把剩余部分的首字母改成小的。 *  * class Person * { * private int x; * public int getAge(){return x;} * public void setAge(int age){return this.x = age} * } * setId 属性名 Id * setCPU 属性名 CPU *  * PropertyDecriptor: 属性描述 *  * 小技巧:使用重构 *  *  */public class _12_内省IntroSpector {public static void main(String[] args)throws Exception {// TODO Auto-generated method stubReflectPoint pt1 = new ReflectPoint(3,5);String propertyName = "x";//x-->X--getX--MethodGetX//使用内省方式获取,接收的参数为:属性名,获取某个类的属性信息xxx.getClass()PropertyDescriptor pd = new PropertyDescriptor(propertyName,pt1.getClass());//得到了JavaBeen属性信息,就可以得到getSet方法Method methodGetX = pd.getReadMethod();//只读方法//通过反射Method.invoke方法获取类型Object retValue = methodGetX.invoke(pt1);System.out.println(retValue);//Set方法,为X重新赋值Method  methodSetX = pd.getWriteMethod();methodSetX.invoke(pt1,7);System.out.println(pt1.getX());}//内省复杂方法public static void JavaBean() throws IntrospectionException{ReflectPoint pt1 = new ReflectPoint(3,5);String str = "x";//1.获取Bean内省的所有字段信息BeanInfo info = Introspector.getBeanInfo(pt1.getClass());//2.接收所有信息的属性PropertyDescriptor[] pds = info.getPropertyDescriptors();//3.进行遍历for(PropertyDescriptor pd : pds){if(pd.getClass().equals(str.getClass())){Method m = pd.getReadMethod();Object obj = m.invoke(pt1);break;}}}

使用BeanUtils包

* Jar包为我们提供了方便,可以直接调用里面的功能。

 * 怎么找工具包?

 * 找到里面最大的Jar包就是我们需要的工具包。

 *

 * 如何导入Jar包?

 * 最好将Jar包放到工程内部,以免发给其它人导致缺包的现象。

 * 1.在工程项目上点击右键,选择Folder-->命名lib

 * 2.将选中的Jar包粘贴到lib文件夹中

 * 3.选中工具包创建Build Path路径(Add to Build Path

 *

 * 4.将工具包日志也粘贴到lib文件夹中


public class _13_使用BeanUtils工具包操作JavaBean {public static void main(String[] args) throws Exception {// TODO Auto-generated method stubReflectPoint pt1 = new ReflectPoint(3,5);//参数解析(操作哪个对象,对象的某个属性,要替换的值)//注意:要替换的类型为String类型"9"//BeanUtils是将对象以字符串的形式操作的BeanUtils.setProperty(pt1, "x","9");/* * java7的新特性   Map集合可以这样定义 * Map map = {name :"zxx",age:18}; *///将Map集合中的name属性,替换为lhm//BeanUtils.setProperty(map,"name","lhm");//将对象中的生日的时间,替换为111毫秒//birthday.time;相当于人有脑袋,脑袋上有眼珠,眼珠的颜色是黄色BeanUtils.setProperty(pt1, "birthday.time", "111");//System.out.println(BeanUtils.getProperty(pt1,"birthday.time"));BeanUtils.getProperty(pt1, "x").getClass();//获取对象属性类型PropertyUtils.setProperty(pt1,"x",9);System.out.println(PropertyUtils.getProperty(pt1,"x").getClass());/* * 总结: * BeanUtils是将对象以字符串的形式操作的 * 而PropertyUtils是以对象本身属性形式操作 */}}




---------------------- 黑马程序员 Android培训、期待与您交流! ----------------------


0 0
原创粉丝点击