黑马程序员——高薪技术——反射


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



 第一部分 Java反射基础


1.1 如何得到字节码

    1、类名.class  ,列入System.class

    2、对象.getClasss(),得到对象所属的字节码

    3、Class.forName("类名")(面试题)
    Class.forName("java.lang.String"),
    加载字节码
方式:

    (1)这份字节码曾经被加载过,已经存在于JDK(JAVA 虚拟机)中,可以直接返回

    (2)JDK还没有这份字节码,用类加载器加载,加载后缓存在虚拟机,

1.2 八个基本类型加上void.class构成九个预定义Class对象
      只要是在源程序中出现的类型,都有自己的Class实例对象,例如,int[], void...

1.3 反射就是把java中的各种成分映射成响相应的java类

1.4 反射会导致性能下降

代码示例:

<span style="font-size:18px;">		 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());</span>

运行结果:

true
true
false
true
false
true
false
true




                                                   第二部分 Java反射的基本应用

2.1 构造方法的反射 

代码示例:

<span style="font-size:18px;">                  //用反射方式实现,new Strig(new StingBuffer("abc"))
		 //注意:编译的时候只是翻译成二进制代码,只看代码的定义,不看代码的执行
		 Constructor constructor1 = String.class.getConstructor(StringBuffer.class); //注意:得到方法时需要类型
		 //以下代码错误,因为会导致argument type mismatch,因为constructor1接受的是StringBuffer类型的变量
		 //String str2 = (String)constructor1.newInstance("abc");
		 String str2 = (String)constructor1.newInstance(/*"abc"*/new StringBuffer("abc"));//注意:调用方法,需要传递同样类型的对象
		 System.out.println(str2.charAt(2));</span>
运行结果:

c
 

2.2 成员变量的反射

    经典比喻;人在黑板上画圆(圆的动作);司机刹车(车的动作);人关门(门的动作)
    静态方法调用不需要对象,因此看到不需要对象调用的方法(第一个参数为null,method为静态方法),为静态方法

    注意:jdk1.4 需要没有可变参数方法,需要将参数打包成参数数组

代码示例:

<span style="font-size:18px;"><span style="font-size:18px;">		 ReflectPoint pt1 = new ReflectPoint(3,5);
		 //只能获取共有变量
		 Field fieldY = pt1.getClass().getField("y");
		 //fieldY的值是多少?是5,错!fieldY不是对象身上的变量,而是类上,
		 //要用他去取某个对象上对应的值
		 System.out.println(fieldY.get(pt1));
		 
		 //可以获取共有和私有变量
		 Field fieldX = pt1.getClass().getDeclaredField("x");
		 //暴力反射,
		 fieldX.setAccessible(true);
		 System.out.println(fieldX.get(pt1));</span></span>

运行结果:

5

3


2.3 成员方法的反射


代码示例:

<span style="font-size:18px;"><pre name="code" class="java" style="font-size:18px;">                 changeStringValue(pt1);
		 System.out.println(pt1);</span>

 
<span style="font-size:18px;"><pre name="code" class="java">                 Method methodCharAt = String.class.getMethod("charAt", int.class);
		 System.out.println(methodCharAt.invoke(str1,1));
		 //jdk1.4版本写法
		 System.out.println(methodCharAt.invoke(str1,new Object[]{2}));</span>

 
<span style="font-size:18px;">//应用反射,替换字符串中的某个字符</span>
<span style="font-size:18px;">private static void changeStringValue(Object obj) throws Exception{
			 Field[] fields = obj.getClass().getFields();
			 for(Field field : fields){
				 //如果使用equals,则语意上不准确
				//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);
		          }  	 
		      }
	      }<pre name="code" class="java">
</span>

 
运行结果: 

<span style="font-size:18px;"><pre name="code" class="java">aall:aasketaall:itcast
b
c</span>

 

2.4 对接受数组参数的成员方法进行反射

    自己写程序,调用封装的main方法

代码示例:

<span style="font-family:SimSun;">                  //使用静态代码调用静态方法
		 //TestArguments.main(new String[] {"111","222","333"});
		 String startingClassName = args[0];</span>
<span style="font-family:SimSun;">                 <span style="color:#ff0000;">//反射方法调用,右键—Run As—Run Configuration—Arguments,添加类的完整名称,此处为TestArguments</span>
		 Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
		 //下面这句话错误,JDK1.5,为了兼容1.4,将数组看成是三个参数
		 //mainMethod.invoke(null, new String[] {"111","222","333"});
		 
		 //第一种解决方案
		// mainMethod.invoke(null, new Object[] {new String[] {"111","222","333"}});
		 
		//第二种解决方案,不要拆包
		 mainMethod.invoke(null,(Object)new String[] {"111","222","333"});
		 </span>

<span style="font-size:18px;"><span style="font-family:SimSun;">class TestArguments{
	public static void main(String[] args){
		for (String arg : args){
			System.out.println(arg);
		}
	}</span><span style="font-family:FangSong_GB2312;">
}</span></span>
运行结果:

111
222
333

2.5 数组与Object的关系及其反射类型

代码示例:

                 int [] a1 = new int[3];
		 int [] a2 = new int[4];
		 int [][] a3 = new int[2][4];
		 String [] a4 = new String[] {"a","b","c"};
		 //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(a1);
		 System.out.println(a4);
		 System.out.println(Arrays.asList(a1));
		 System.out.println(Arrays.asList(a4));
		 
运行结果:

[I
java.lang.Object
java.lang.Object
[I@7852e922
[Ljava.lang.String;@4e25154f
[[I@7852e922]
[a, b, c]


第九讲 数组的反射应用

    要求:将数拆分打印

代码示例:

                 printObject(a4);		 
		 printObject("xyz");
 private static void printObject(Object obj){
			 Class clazz = obj.getClass();
			 //Array为数组反射类
			 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);
			 }				
		 }
运行结果:

a
b
c
xyz

                                       


                             第三部分 反射的其他应用                                                                       


3.1 ArrayList_HashSet的比较以及Hastcode分析

***面试题:hashCode方法的作用 (java中有内存泄露么,有)

泄露,例如某对象没有在被使用,但是却一直占用内存

注意:


 (1)通常来说,一个类的两个实例对象用equals()方法比较的结果相等时,它们的哈希码也必须相等,但反之
则 不成立,即equals方法比较结果不相等的对象可以有相同的哈希码,或者说哈希码相同的两个对象的equals方法比较
结果可以不等,例如,字符串“BB”和"Aa"的equals方法比较结果肯定不相等,但它们的hashCode方法返回值却相等。
 (2)当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,
对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,这种情况下,即使在contains方法使用该对象的
当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HasheSet集合中单独删除当前对象,
从而造成内存泄露。




3.2 框架的概念及用反射技术开发框架的原理
    框架已经建好,需要调用别人写的类,如何实现:
    1、自己去调用别人的类2、别人的类来调用你举例:(1)我盖房子卖给用户住,由用户自己安装门窗和空调,
我做的房子就是框架,用户需要使用我的框架,把门窗插入我提供的框架中。框架与工具类有区别,工具类被用户的类
调用,而框架则是调用用户提供的类。
    2、我在写框架(房子)时,你这个用户可能还在上小学,还不会写程序呢?我写的框架程序怎样能调用到
你以后写的类(门窗)呢?因为在写程序是无法知道要被调用的类名,所以,在程序中无法直接new某个类的石磊对象了,
而要用反射方式来做。
    综合案列:
    先直接用new语句创建ArrayList和HashSet的实例对象,演示用eclipse自动生成ReflecPoint类的equals和
hashcode方法,比较两个集合的运行结果差异。然后改用采用配置文件夹反射的方式创建ArrayList和HashSet的实例对象,
比较观察结果差异。引入eclipse对资源文件的管理方式的讲解即不要出现具体的类的名字HashSet框架一:
将程序要调用的类,放到配置文件中去

<span style="font-size:18px;">import java.util.Collection;
import java.util.HashSet;
import java.util.Properties;
</span>
<span style="font-size:18px;">public class ReflectTest2 {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub
	
		//加载操作文件
		InputStream ips = new FileInputStream("config.properties");
		//在Package Explorer——config.properties添加className= java.util.HashSet
		Properties props = new Properties();
		props.load(ips);
		//关闭对象关联的系统资源,而不是关闭对象,对象是由垃圾回收机管理
		ips.close();
		String className = props.getProperty("className");
		Collection collections = (Collection)Class.forName(className).newInstance();
		
		//ArrayList打印结果为4
		//Collection collections = new ArrayList();
		//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);
		//修改hashCode值,无法删除,程序运行结果
		//pt1.y = 7;
		//collections.remove(pt1);	
		System.out.println(collections.size());	

	}

}
</span>

运行结果:

2

在Package Explorer——config.properties添加className= java.util.ArrayList,运行结果为4


附录 程序完整代码

</pre><pre name="code" class="java"><span style="font-size:18px;"><strong>ReflectTest.java</strong></span>
<pre name="code" class="java"><span style="font-size:18px;">import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;


public class ReflectTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub
		 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());
		 
		 //用反射方式实现,new Strig(new StingBuffer("abc"))
		 //编译的时候只是翻译成二进制代码,只看代码的定义,不看代码的执行
		 Constructor constructor1 = String.class.getConstructor(StringBuffer.class);//注意:得到方法时需要类型
		 //以下代码会导致argument type mismatch,因为constructor1接受的是StringBuffer类型的变量
		 //String str2 = (String)constructor1.newInstance("abc");
		 
		 String str2 = (String)constructor1.newInstance(/*"abc"*/new StringBuffer("abc"));//注意:调用方法,需要传递同样类型的对象
		 System.out.println(str2.charAt(2));
		 
		 ReflectPoint pt1 = new ReflectPoint(3,5);
		 //只能获取共有变量
		 Field fieldY = pt1.getClass().getField("y");
		 //fieldY的值是多少?是5,错!fieldY不是对象身上的变量,而是类上,
		 //要用他去取某个对象上对应的值
		 System.out.println(fieldY.get(pt1));
		 //可以获取共有和私有变量
		 Field fieldX = pt1.getClass().getDeclaredField("x");
		 //暴力反射,
		 fieldX.setAccessible(true);
		 System.out.println(fieldX.get(pt1));
		 
		 changeStringValue(pt1);
		 System.out.println(pt1);
		 
		 Method methodCharAt = String.class.getMethod("charAt", int.class);
		 System.out.println(methodCharAt.invoke(str1,1));
		 //jdk1.4版本写法
		 System.out.println(methodCharAt.invoke(str1,new Object[]{2}));
		  
		 //使用静态代码调用静态方法
		 //TestArguments.main(new String[] {"111","222","333"});
		 String startingClassName = args[0];
		 Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
		 //下面这句话错误,JDK1.5,为了兼容1.4,将数组看成是三个参数
		 //mainMethod.invoke(null, new String[] {"111","222","333"});
		 
		 //第一种解决方案
		// mainMethod.invoke(null, new Object[] {new String[] {"111","222","333"}});
		 
		//第二种解决方案,不要拆包
		 mainMethod.invoke(null,(Object)new String[] {"111","222","333"});
		 
		 
		 //第八讲 数组与Object的关系及其反射类型
		 int [] a1 = new int[3];
		 int [] a2 = new int[4];
		 int [][] a3 = new int[2][4];
		 String [] a4 = new String[] {"a","b","c"};
		 //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(a1);
		 System.out.println(a4);
		 System.out.println(Arrays.asList(a1));
		 System.out.println(Arrays.asList(a4));
		 
		 printObject(a4);
		 
		 printObject("xyz");
		 
	     }
	     
        //数组反射,如何得数组中元素的类型,(目前没有办法),但可以得到某一个元素的类型
	    //做框架时,可以引用到以上知识
		 private static void printObject(Object obj){
			 Class clazz = obj.getClass();
			 //Array为对数组反射类
			 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);
			 }
				
		 }
	
	 
		 private static void changeStringValue(Object obj) throws Exception{
			 Field[] fields = obj.getClass().getFields();
			 for(Field field : fields){
				 //如果使用equals,则语意上不准确
				//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);
		          }  	 
		      }
	      }
		 
}

class TestArguments{
	public static void main(String[] args){
		for (String arg : args){
			System.out.println(arg);
		}
	}
}
</span>


 
<pre name="code" class="java"><span style="font-size:18px;"><strong>ReflectPoint.java</strong></span>
<span style="font-size:18px;">public class ReflectPoint {
	private int x;
	public int y;
	public String str1 = "ball";
	public String str2 = "basketball";
	public String  str3 = "itcast";
	
	public ReflectPoint(int x, int y) {
		super();
		this.x = x;
		this.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;
	}

	@Override
	public String toString(){	
		return str1 + ":" + str2 + ":" + str3;
	}

}
</span>


 
<span style="font-size:18px;"></span><pre name="code" class="java"><strong>ReflectText2.java</strong>
import java.io.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.Properties;


public class ReflectTest2 {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub
	
		//加载操作文件
		InputStream ips = new FileInputStream("config.properties");
		Properties props = new Properties();
		props.load(ips);
		//关闭对象关联的系统资源,而不是关闭对象,对象是由垃圾回收机管理
		ips.close();
		String className = props.getProperty("className");
		Collection collections = (Collection)Class.forName(className).newInstance();
		
		//ArrayList打印结果为4
		//Collection collections = new ArrayList();
		//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);
		//修改hashCode值,无法删除
		pt1.y = 7;
		collections.remove(pt1);	
		System.out.println(collections.size());	

	}

}
































































































































































































































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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值