57.黑马程序员-反射,57黑马程序员反射
分享于 点击 32959 次 点评:235
57.黑马程序员-反射,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");
-
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); }
七、反射的作用-举例
-
-
需求:设计一个主板,为了提高后期的扩展性,也就是为了后期提高电脑的额功能,对外提供了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(),未知类是后来的。这个反射就实现了一个小框架。
- 框架是提前做好的,框架调用用户的类,就像房子是框架,新门是用户类。
- 反射做的框架有个好处:将来的类可以调用以前的类。框架不需要知道将来的类叫什么。
相关文章
- 暂无相关文章
用户点评