`
bingzhen66
  • 浏览: 36722 次
文章分类
社区版块
存档分类
最新评论

57.黑马程序员-反射

 
阅读更多

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

一、反射概念
  • 反射就是把Java类中的各种成分映射成相应的Java类。
    • 例如,一个Java类中用一个Class类的对象来表示,
    • 一个类中的组成部分:成员变量,方法,构造方法,包等信息也用一个个Java类来表示。
    • 就像汽车是一个类,其中的发动机,变速箱等等也是一个类。
    • 表示Java类的Class类显然要提供一系列的方法,来获取其中的变量,方法,构造方法,修饰符,包等信息。这些信息就是用相应类的实例对象来表示,他们是Field、Method、Contructor、Package等等。
  • 一个类中的每一个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象有什么用?怎么用?这正是学习和应用反射的要点。
  • 理解:
    • Java的类进入内存,变成一份份Java字节码文件,每一份字节码文件就是Class类的实例对象(因为Class类就是描述这些字节码文件的类,是所有字节码文件的类)。
    • 字节码文件就是把所有类的字节码文件抽取出的共性(属性、方法、各种信息)封装为一个统一的Class类,而每个字节码文件就是这个Class类的一个实例对象,所以这些对象可以调用Class类的方法,如getMehod(),isPrimitive(),getConstructor()等等。
    • 反射把这些组成部分封装起来
    • 组成部分的字节码文件: Field、Method、Contructor、Package等,这些字节码文件是Class类的实例对象,这些实例对象提供了一些方法暴露自己的信息。
    • 疑问?
      • 这些字节码文件与要反射的类有什么关系呢?
      • 比如说String.class.getConstructor();这一句是String的字节码字节码文件(Class类的实例对象)使用了 Contructor字节码文件 (Class类的实例对象)的 getConstructor()方法?
    • 牢记:
      • 字节码文件是对象,是Class类的实例对象。
    • 得到Class的三种方法:
		String str1 = "abc";
		//得到Class的三种方法:对象.getClass,类.class,Class.forName("类名")
		Class cls1 = str1.getClass();
		Class cls2 = String.class;
		Class cls3 = Class.forName("java.lang.String");


三、Field的反射

  • 		ReflectPoint pt1 = new ReflectPoint(3,5);
    		//通过字节码,得到Field类对象
    		Field fieldY = pt1.getClass().getField("y");
    		System.out.println(fieldY.get(pt1));//
    		
    		//得到private的字段
    		Field fieldX = pt1.getClass().getDeclaredField("x");//private�����ɼ�
    		fieldX.setAccessible(true);//private�������Է���
    		System.out.println(fieldY.get(pt1));

四、Method的反射

  • 		Method methodCharAt = String.class.getMethod("charAt", int.class);
    		System.out.println(methodCharAt.invoke(str1,1));
    		System.out.println(methodCharAt.invoke(str1, new Object[]{2}));//JDK1.4

五、用反射调用其他类的main 方法。

  • 		//用反射调用其他的main方法
    		String startingClassName = args[0];
    		Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
    		mainMethod.invoke(null, new Object []{new String[]{"111","222","333"}});
    		mainMethod.invoke(null, (Object)new String[] {"111","222","333"});

六、数组与Object及其反射类型

  • 具有相同维度、相同类型的数组,它们使用同一份字节码。
  • 基本数据类型不是对象,也不是Object的子类。
  • 使用Arrarys的asList()转为List结合,可以打印出元素。
    • 如果参数是Object的之类,那么按照JDK1.4可以打印出元素。
    • 如果参数是基本数据类型,那么按照JDK1.5的传递一个可变参数,只打印数组的[I@65656。对于这段话,疑问··~
  • 	private static void printObject(Object obj)
    	{
    		Class<? extends Object> 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);
    	}
    	

七、反射的作用-举例

  • 例子来源:http://www.cnblogs.com/zxl-jay/archive/2011/09/25/2190585.html
  • 需求:设计一个主板,为了提高后期的扩展性,也就是为了后期提高电脑的额功能,对外提供了PCI的接口。以方便电脑功能的扩展。

  • interface PCI{
     void open();
     void close();
     }
     class MainBoard{
     public void usePCI(PCI p){
     p.open();
     p.close();
     }
     }
     class MainBoardDemo{
     public static void main(String[] args){
     MainBoard mb=new MainBoard();
     //mb.usePCI(null);
     mb.usePCI(NetCard);
     }
     } 

    后期,要进行电脑功能的扩展,需加入一个网卡,只需要定义一个网卡类实现PCI接口,只要覆盖这个规则,主板就可以使用该板卡。

  • class NetCard implements PCI{
     public void open();{
     system.out.println("open");
     }
     public void close();{
     system.out.println("close");
     }
     } 
    

    那么为了使用其网卡,还需要做一个步骤就是在已定义好的应用程序中,建立网卡对象,并作为参数传入,那么就是对原有的程序进行修改。这样不利于程序的健壮性。

    可不可以在不修改源码的基础上运行后期出现的这些子类对象呢?

    只要在前期设计时,将后期指定的类进行对象的建立,这样后期的子类对象就不需要再建立对象,只要将子类名称告知即可。

    为了获取后期对象,并在前期可以使用,或对外提供了一个配置文件。前期程序可以直接操作该配置文件,后期的子类只需要将子类名称存入配置文件即可。

    这时就需要动态的获取指定的类并预先创建对象

  • 就用到了反射机制。重新修改一下应用程序。
                class MainBoardDemo{
                         public static void main(String[] args){
                             MainBoard mb=new MainBoard();
                             File file=new File("conf.txt");
                             BufferenReader buff = new BufferenReader(new FileReader(file));
                             String className = buff.readLine();
                             Class clazz = Class.forName(className);
                             PCI p = (PCI)clazz.newInstance();
                             mb.usePCI(p);
                             }
                     }

  • 配置文件conf.txt

    当后期出现网卡或者声卡的时候,只需要将该子类的全类名存入配置文件即可, 源程序不需要进行修改

    在该例中,可以了解,反射给我们的程序带来了很强的扩展性。

八、反射的作用-框架的概念

  • 比如在反射中,调用一个未知类的main(),未知类是后来的。这个反射就实现了一个小框架。
  • 框架是提前做好的,框架调用用户的类,就像房子是框架,新门是用户类。
  • 反射做的框架有个好处:将来的类可以调用以前的类。框架不需要知道将来的类叫什么。

一、反射概念
  • 反射就是把Java类中的各种成分映射成相应的Java类。
    • 例如,一个Java类中用一个Class类的对象来表示,
    • 一个类中的组成部分:成员变量,方法,构造方法,包等信息也用一个个Java类来表示。
    • 就像汽车是一个类,其中的发动机,变速箱等等也是一个类。
    • 表示Java类的Class类显然要提供一系列的方法,来获取其中的变量,方法,构造方法,修饰符,包等信息。这些信息就是用相应类的实例对象来表示,他们是Field、Method、Contructor、Package等等。
  • 一个类中的每一个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象有什么用?怎么用?这正是学习和应用反射的要点。
  • 理解:
    • Java的类进入内存,变成一份份Java字节码文件,每一份字节码文件就是Class类的实例对象(因为Class类就是描述这些字节码文件的类,是所有字节码文件的类)。
    • 字节码文件就是把所有类的字节码文件抽取出的共性(属性、方法、各种信息)封装为一个统一的Class类,而每个字节码文件就是这个Class类的一个实例对象,所以这些对象可以调用Class类的方法,如getMehod(),isPrimitive(),getConstructor()等等。
    • 反射把这些组成部分封装起来
    • 组成部分的字节码文件: Field、Method、Contructor、Package等,这些字节码文件是Class类的实例对象,这些实例对象提供了一些方法暴露自己的信息。
    • 疑问?
      • 这些字节码文件与要反射的类有什么关系呢?
      • 比如说String.class.getConstructor();这一句是String的字节码字节码文件(Class类的实例对象)使用了 Contructor字节码文件 (Class类的实例对象)的 getConstructor()方法?
    • 牢记:
      • 字节码文件是对象,是Class类的实例对象。
    • 得到Class的三种方法:
		String str1 = "abc";
		//得到Class的三种方法:对象.getClass,类.class,Class.forName("类名")
		Class cls1 = str1.getClass();
		Class cls2 = String.class;
		Class cls3 = Class.forName("java.lang.String");
三、Field的反射
  • 		ReflectPoint pt1 = new ReflectPoint(3,5);
    		//通过字节码,得到Field类对象
    		Field fieldY = pt1.getClass().getField("y");
    		System.out.println(fieldY.get(pt1));//
    		
    		//得到private的字段
    		Field fieldX = pt1.getClass().getDeclaredField("x");//private�����ɼ�
    		fieldX.setAccessible(true);//private�������Է���
    		System.out.println(fieldY.get(pt1));
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics