黑马程序员——反——射

---------------------- 黑马程序员 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

l Constructor类代表某个类中的一个构造方法
/*
 * 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的返回值类型是Object
		
		String str = (String)constructor.newInstance(new StringBuffer("abc"));
		
		
		//求String的第2个字符
		
		System.out.println(str.charAt(2));
	}
}	

Field类(成员变量)

l Field类代表某个类中的一个成员变量
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类(方法)

l Method类代表某个类中的一个成员方法
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代表整数int
		System.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 stub
		
		ReflectPoint 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 stub
	
		ReflectPoint 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培训、期待与您交流! ----------------------


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值