`
想学跑的猪
  • 浏览: 15241 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

黑马程序员_Java高新技术_之篇二_反射

阅读更多

 

            ------ android培训java培训、java基础学习技术总结、期待与您交流! ----------

      反射

        1.  反射的基石--> Class类-->
   * java程序中的各个类属于同一类事物,描述这类事物的Java类名就是Class
   * 对比提问:众多的人用一个什么类表示?众多的Java类用一个什么类表示?
   * 人-->Person
   * Java--> Class
   * 对比问题:Person类代表人,它的实例对象就是张三,李四这样一个个具体的人,
   * Class类代表Java类,它的各个实例对象又分别对应什么呢?
   * 对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的字节码,等等。
   * 一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容是不同的
   * 这一个个的空间可分别用一个个的对象来表示,这些对象显然具有
   * 相同的类型,这个类型是什么呢?
   * 如何得到各个字节码对应的示例对象(Class类型)
   * 类名.class,例如,System.class
   * 对象.getClass(),例如,new Date().getClass()
   * Class.forName("类名"),例如,class.forName("java.util.Date");
   * 九个预定义Class实例对象
   * 参看Class.isPrimitive方法的帮助
   * int.class==Integer.TYPE

        示例1:

public class ReflectTest {
	public static void main(String[] args) throws ClassNotFoundException {
		
         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());      //判断是否为数组类型
	}
} 

 
   * 数组类型的Class示例对象
   * Class.isArray()
   * 总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[]
   * 反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的
   * 对象来表示,一个类中的组成部分:成员变量,方法,构造方法,
   * 包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个
   * 的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造函数,
   * 修饰符,包等信息,这些信息就是用相应的类的实例对象来表示,它们是Field\
   * Method、Constructor、Package等等。
   * 一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的
   * 方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?
   *怎么用呢? 这正是学习和应用反射的要点。
   *Constructor类
   *Constructor类代表某个类中的构造方法
   *得到某个类所有的构造方法
   *     例子:Constrcutor[] constructors=
   *     Class.forName("java.lang.String").getConstructors();
   *     得到某一个构造方法:Constructor constructor=
   *     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();
   *     该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
   *     该方法内部的具体代码是这样写的呢?用到了缓存机制来
   *     保存默认构造方法的实例对象
   *     class-->constructor-->new object

      示例2:

public class ReflectTest2 {
	public static void main(String[] args) throws SecurityException, NoSuchMethodException, 
IllegalArgumentException, InstantiationException, 
IllegalAccessException, InvocationTargetException {
         
	Constructor constructor1=String.class.getConstructor((StringBuffer.class));
	String str2=(String) constructor1.newInstance(new StringBuffer("abc"));// 需要产生同样类型的对象
	System.out.println(str2.charAt(2));
	}

}

 
   *     Field类
   *     Field类代表某个类中的一个成员变量
   *     演示用eclipse自动生成Java类的构造方法
   *     问题:得到的Field对象是对应到类上面的成员变量,
   *     还是对应到对象上的成员变量?类只有一个,而该类的
   *     实例对象有多个, 如果是与对象关联,哪关联的是哪一个对象呢?
   *     所以字段FieldX代表的是x的定义,而不是具体的x变量。

     示例1:

public class ReflectPoint {
      private int x;
      private int y;
      Date birthday=new Date();
      
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	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 ReflectPoint(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}
	public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
		// TODO Auto-generated method stub
       ReflectPoint pt1=new ReflectPoint(3,5);
       Field fieldY =pt1.getClass().getField("y"); 
       //fielY的值是多少呢?是5,错!fieldY不是对象身上的变量,而是类上,要用它
      System.out.println( fieldY.get(pt1)); 
      Field fieldX=pt1.getClass().getDeclaredField("x");
     fieldX.setAccessible(true);
     System.out.println(fieldX.get(pt1));
	}
	@Override
	public String toString() {
		return "ReflectPoint [x=" + x + ", 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;
	}
}

 
   *    作业:将任意String变量中的'b'改成'a'.

    *      Method类
   *      Method类代表某一个类中的一个成员方法
   *      得到类中的某一个方法:
   *      例子:   Method charAt=
   *      Class.forName("java.lang.String").getMethod("charAt",int.class);
   *      调用方法:
   *      通常方式:System.out.println(str.chatAt(1));
   *      反射方式: System.out.println(charAt.invoke(str,1));
   *      如果传递给method对象的invoke()方法的一个参数为null,
   *      这有着什么样的意义呢?说明该Method对象对应的是一个
   *      静态方法!
   *      jdk 1.4和jdk 1.5的invoke方法的区别:
   *      Jdk1.5:public Object invoke(Object obj,Object... args)
   *      Jdk 1.4 public Object invoke(Object obj,Object[] args),
   *      即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法是,数组中的
   *      每一个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的
   *      代码也可以用jdk 1.4改写为charAt.invoke("str",new Object[]{1}形式。
   *      用反射的方式执行某个类中的main方法
   *      目标
   *      写一个程序,这个程序能够根据用户提供的类名,去执行类中的main方法。

   *      问题:
   *      启动Java程序的main方法的参数是一个字符串数组,即public static void
   *      main(String[] args),通过反射的方式来调用这个main方法时,如何为
   *      invoke方法传递参数呢?按jdk1.5的语法,整个数组是一个参数,而按jdk 1.4的语法,
   *      数组中的每一个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法
   *      时,javac会到底按照那种语法进行处理,及把数组打散成为若干个单独的参数
   *      。所以,在main方法传递参数时,不能使用代码
   *      mainMethod.invoke(null,new String[]{"xxx"});,javac只把它当作jdk 1.4的语法进行
   *      理解,而不把它当成jdk 1.5的语法解释,因此会出现参数类型不对的问题。
   *      解决办法:
   *      mainMethod.invoke(null,new Object[]{new String[]{"xxx"});
   *      mainMethod.invoke(null,(Object)new String[]{"xxx"});,编译器会作特殊处理,
   *      编译时不把参数当作数组看待,也就不会数组打散成若干个参数了

     示例2:

public class ReflectPoint2 {
     private int x;
     private int y;
     public String str1="ball";
     public String str2="basketball";
     public String str3="itcast";
	public ReflectPoint2(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}
	public String toString(){
		return str1+"::"+str2+"::"+str3;
	}
	public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
		// TODO Auto-generated method stub
		String str1="abc";
       ReflectPoint2 pt2=new ReflectPoint2(3,5);
		changeStringValue(pt2);
       System.out.println(pt2);     
       Method methodCharAt= String.class.getMethod("charAt",int.class);
       System.out.println(methodCharAt.invoke(str1, 1)); 
       System.out.println(methodCharAt.invoke(str1, new Object[]{2})); 
       //TestArguments.main(new String[]{"abc","xyz","123"});
       String startingClassName=args[0]; 
      Method mainMethod=Class.forName(startingClassName).getMethod("main", String.class);
      mainMethod.invoke(null, (Object)new String[]{"abc","xyz","123"});
 	} 
     private static void changeStringValue(Object obj) throws IllegalArgumentException, IllegalAccessException{
    	 Field[] fields=obj.getClass().getFields();
    	 for(Field field:fields){
    		 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); 
		}
	}
}

 
   *      数组的反射
   *      具有相同的维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
   *      代表数组的Class实例对象的getSuperClass()方法返回的父类
   *      为Object类对应的Class。
   *      基本类型的一位数组可以当作Object类型使用,不能当作
   *      Object[]类型使用;非基本类型的一位数组,即可以当作Object类型使用
   *      ,又可以当作Object[]类型使用。
   *      Arrays.asList()方法处理int[]和String[]时的差异。
   *      Array工具类用于完成对数组的反射操作。
   *      思考题:怎么得到数组中的元素类型?

          示例3:

public class ReflectPoint3 {
	public static void main(String[] args) {
        int[] a1=new int[3];
        int[] a2=new int[4];
        int[][] a3=new int[2][3];
        String[] a4=new String[3];
        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(Arrays.asList(a1)); 
	    System.out.println(Arrays.asList(a4)); 
	    Object obj=null;
	    printObject(obj);
	    
	}
	public 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); 
		}
	}
}

 
   *      反射的作用-->实现框架功能
   *      框架与框架要解决的核心问题
   *      我做房子卖给住户,由用户自己安装门窗和空调,我做的房子就是框架,
   *      用户需要使用我的框架,把门窗插入我提供的框架中,框架与工具有区别,
   *      工具类被用户的类调用,而框架则是调用用户提供的类
   *      框架要解决的核心问题
   *      我在写框架(房子)时,你这个用户可能还在上学,还不会写程序呢?
   *      我写的框架程序怎样能调用你以后写的类(门窗)呢?
   *      因为在写程序时无法知道要被调用的类名,所以,在程序中无法直接new某个类
   *      的实例对象了,而要用发射方式来做。
   *      综合案例
   *      先直接用new语句创建ArrayList和HashSet的实例对象,演示用eclipse自动生成
   *      ReflectPoint类的equals和hashcode方法,比较两个集合的运行结果差异。

     
   *      然后改为采用配置文件加反射的方式创建ArrayList和HashSet的实例对象,比较
   *      观察运行结果差异。

  *      引入了eclipse对资源文件的管理方式的讲解
   *       内省       -->IntroSpector-->对JavaBean进行操作-->特殊的Java类-->javaBean的属性根据方法取出来
   *          符合   int getAge()
   *             void setAge(int age)  这样规则的类叫做JavaBean。
   *             Age  -->如果第二个字母是小的,则把第一个字母变成小的--age
   *             gettime-->time
   *             setTime-->time
   *             setCPU-->CPU
   *             isLast()-->last
   *             JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省

          示例6:

 public class ReflectTest3 {


	public static void main(String[] args) throws IOException, InstantiationException, IllegalAccessException, ClassNotFoundException {
		// TODO Auto-generated method stub
		//InputStream ips=new FileInputStream("config.properties");
		//InputStream ips=ReflectTest3.class.getClassLoader().getResourceAsStream("cn/itcast/study2/config.properties");
		InputStream ips=ReflectTest3.class.getResourceAsStream("config.properties");
		Properties props=new Properties();// 
		props.load(ips);   
		ips.close(); 
		String className=props.getProperty("className");
		Collection collections=(Collection)Class.forName(className).newInstance();
            //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);  
              System.out.println(collections.size());
	}
} 

     示例7:

public class IntroSpectorTest {

	public static void main(String[] args) throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
		// TODO Auto-generated method stub
           ReflectPoint pt1=new ReflectPoint(3,5);
           String propertyName="x"; 
               //"x"-->"X"-->"getX"-->MethodX--> 
           Object retVal;
           PropertyDescriptor pd = getProperty(pt1, propertyName); 
           Object value=7; 
	       setProperty(pt1, pd, value);
	  
	       System.out.println(BeanUtils.getProperty(pt1, "x").getClass()); 
	       BeanUtils.setProperty(pt1, "x", "9");
	       /*Map map={name:"zxx",age:18};
	       BeanUtils.setProperty(map, "name", "1hm");
	       BeanUtils.setProperty(map, "name", "111");*/ 
	       BeanUtils.setProperty(pt1, "birthday.time", "111"); 
	       System.out
				.println(BeanUtils.getProperty(pt1, "birthday.time")); 
	       PropertyUtils.setProperty(pt1, "x",9);
	       System.out.println(PropertyUtils.getProperty(pt1, "x"));  
	}

	private static void setProperty(ReflectPoint pt1, PropertyDescriptor pd,
			Object value) throws IllegalAccessException,
			InvocationTargetException {  
		Method methodSetX=pd.getWriteMethod();
		   methodSetX.invoke(pt1, value); 
		   System.out.println(pt1.getX());
	} 

	private static PropertyDescriptor getProperty(ReflectPoint pt1,
			String propertyName) throws IntrospectionException,
			IllegalAccessException, InvocationTargetException, NoSuchMethodException {
		Object retVal;
		PropertyDescriptor pd=new PropertyDescriptor(propertyName,pt1.getClass());
	   Method methodGetX=pd.getReadMethod();
	   retVal=methodGetX.invoke(pt1);
	   System.out.println(retVal);

		return pd;
	} 

}

 
 

 

 

            ------ android培训java培训、java基础学习技术总结、期待与您交流! ----------

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics