黑马程序员 -- Java基础学习(11)

------- android培训java培训、期待与您交流! ----------


反射

反射就是把Java类中各种成分映射成相应的Java类:Field Method Constructor Package

Constructor

	一个Constructor就代表字节码里的一个构造方法
	得到某个类所有方法
	  Constructor[] constructors = Class.forName(“java.lang.String”).getConstructors();
	得到某个方法
	  Constructor constructor = Class.forName(“jaga.lang.String”).getConstructor(StringBuffer.class);
	  用参数类型决定获得的是哪个构造方法(可变参数)
	  在1.5以前用数组传入参数
	创建对象:用获得的constructor对象的newInstance方法返回一个对象
	  编译时只知道constructor是一个Constructor对象,运行时才知道对应的是哪一个构造方法
	  在newInstance方法上传入对应类型的变量,由于constructor的参数类型是StringBuffer,所以要传入的是StringBuffer而不是String
	  由于newInstance返回的是Object对象,需要进行类型转换
	  String str = (String)constructor.newInstance(new StringBuffer(“abc”));
	Class类也有一个newInstance方法,该方法对应的是无参构造方法,提供一个便利方法
	  实际上源代码也是要建立一个Constructor对象并且缓存起来(因为反射比较耗时)
	  一般步骤:class->constructor->new object

Field

	代表某个类中的一个成员变量
	  先建立一个类:ReflectPoint
	先建立一个对象
	  ReflectPoint
	获得一个成员变量,先获得字节码
	  getField()参数传入变量名字符串
	  Field fieldY = pt1.getClass().getField(“y”);
	  此时fieldY的值不是5,因为没有对应到某个具体对象的成员
	get()获取具体的值,参数为对象
	  fieldY.get(pt1);
	如果成员变量为私有的,用getField方法无法获得
	  可以使用getDeclaredField()方法获得,但是此时仍然无法访问该成员变量
	  要使用setAccessible(true)设置,称为暴力反射
	  Field fieldX = pt1.getClass().getDeclaredField(“x”);
	  fieldX.setAccessible(true);
	练习:将任意一个对象中所有String类型的成员变量对应的字符串内容中的‘b’改成‘a’
	  private static void changeStringValue(Object obj);
		得到所有字段:Field[] fields = obj.getClass().getFields();
		遍历所有字段:for (Field field : fields)
		判断字段类型:getType()
		  不要用if(field.getType().equals(String.class)),同一份字节码的比较用==		  if(field.getType() == String.class)
		获得字符串的值:String oldValue = (String)field.get(obj);
		替换:String newValue = oldValue.replace(‘b’, ‘a’);    会有异常
		用替换后的新字符串复制给对象中的变量:field.set(obj, newValue)

Method

	某个类中的一个成员方法(是类)
	方法的一般调用方法:通过某个具体对象
	  str1.charAt(1);
	  circle.draw();
	获得方法:Mehod methodCharAt = String.class.getMethod(“charAt”, int.class);
	  由于方法可能有重载,需要确定具体的参数类型
	  第一个参数是方法名的字符串形式,第二个是表示参数类型的类
	调用方法:methodCharAt.invoke(str, 1);
	  第一个参数为要调用方法的对象,第二个是参数的值
	  如果第一个参数为null说明该方法为静态方法
	专家模式:谁拥有数据谁就是专家,那么方法就应该分配给他
	练习:用反射方式执行某个类中的main方法 -- TestArguments类
		一般调用方法:TestArguments.main(new String[] {“xxx”});
		为什么要用反射的方式调用:有可能程序不知道要调用的类的名字,通过参数传入,此时无法直接调用该类的方法,需要用反射方式
		String startingClassName = args[0]; 
		  Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
		jdk1.5中有自动装箱
		  在jdk1.4中可变参数用数组存放:new Object[] {参数列表}java会把数组解开获得其中的参数
		  为了向下兼容,jdk1.5也会把数组拆包
		  methodCharAt.invoke(str, new Object[] {1});
		两种传递参数的方法:
			mainMethod.invoke(null, new Object[]{new String[] {"1","2","3"}});
			  java会把String数组解开,当成3个参数,所以要再用一个数组包装起来
			mainMethod.invoke(null, (Object)new String[] {"1","2","3"});
			  把数组转换成Object,这样java就不会把它当成数组拆开

数组的反射

	相同类型和纬度的数组属于同一个类
	  int[] a1 = new int[] {1, 2, 3};
	  System.out.println(a1.getClass().getName());   输出的是:[I [表示数组I表示整数
	  System.out.println(a1.getClass().getSuperclass().getName());    输出的是java.lang.Object
	Object[] obj3 = a1; 会编译错误,因为a1中的成员类型是int,不是Object
	  Arrays.asList() 接收的参数是Object[]a1的成员类型是int,使用该方法只会把整个数组看成一个对象,打印结果是a1的地址
	利用反射操作数组:自定义打印数组的方法
		getClass()
		  isArray()
		  Array.getLength(obj)
		  Array.get(obj, i)
	 	 • 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);
			  }
		  }
	思考:能否得到数组中元素的类型?不能,只能得到每个具体元素的类型,但是无法确定数组定义时的类型,因为该数组可能是Object数组,这样数组中可以存放不同类型的元素
	  a[0].getClass().getName();

ArrayListHashSet的比较

	  ReflectTest2.java
	ArrayList是有顺序的集合,存放的是引用变量,不同引用变量可以引用同一个对象
	  HashSet添加对象时如果集合中已经有相同对象则不会放入
	HashSet存放对象时调用equals方法,比较的是HashCode
	  如果有两个对象值相同,由于HashCode不同,不会当成相同的对象
	  如果要让HaseSet认为两对象相等,要重写equalshashCode方法
	  注意hashCode方法只在HashSet中才有价值,如果在ArrayList中则没有用
	当对象存入HashSet后,不要改变对象的字段,因为字段改变了hashCode也变了,这样如果要remove该对象,由于哈希值不同,remove会失败
	  这样对象没有删除成功,还会存在内存中,会造成内存泄露 ———— 面试:java有内存泄露!HashSetremove对象失败
	  而ArrayList就没有这个问题

反射的作用 -> 实现框架功能

	框架的类比用户写的类先存在
	框架:调用我写的类
	  工具:我调用工具类
	在配置文件(config.properties)中读取类名,再用反射调用该类(Collection		config.properties中存储的是键值对
		Propertiesload方法通过InputStream读取文件:
		  InputStream ups = new FileInputStream(“”);
		  props.load(ips);
		PropertiesgetPropertiy()方法获取属性
		  String className = prop.getProperty(“className”);
		  Collection collection = (Collection)Class.forName(className).newInstance();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值