黑马程序员--------反射
来源:互联网 发布:明道软件怎么使用 编辑:程序博客网 时间:2024/05/04 21:01
-------android培训、java培训、期待与您交流! ----------
反射的基石:Class类
Class 类表示java 类的字节码的类 (java类 本身也是一类事物)。
如何得到各个字节码对应的实例对象( Class类型)
类名.class,例如,System.class
对象.getClass(),例如,new Date().getClass()
Class.forName("类名"),例如,Class.forName("java.util.Date");(反射时主要用第三种变量名)
九个预定义Class实例对象:(void + 八种基本数据类型)
参看Class.isPrimitive方法的帮助
Int.class == Integer.TYPE
Class.isArray();
System.out.println(c1.isPrimitive());
System.out.println(int.class.isPrimitive());//返回ture
System.out.println(int[].class.isPrimitive());// 返回false
System.out.println(int.class==Integer.class);// 返回false
System.out.println(int.class==Integer.TYPE);// 返回true
System.out.println(int[].class.isArray());// 返回true
无论用什么方法得到字节码,得到的都是一份字节码(代码示例如下)
Class c1=String.class;
Class c2= new String().getClass();
Class c3=null;
try {
c3=Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(c1==c2);// 返回true
System.out.println(c1==c3);// 返回true
理解反射:
反射就是把Java类中的各种成分映射成相应的java类。
例如,一个Java类用一个Class类的对象来表示,一个类中的组成部分:
成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。
表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,
这些信息就是用相应类的实例对象来表示, 它们是Field、Method、Contructor、Package等等。
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,
通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?
这正是学习和应用反射的要点。
Constructor类
Constructor类代表某个类中的一个构造方法
得到某个类所有的构造方法:
例子:Constructor [] 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();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
Field类
Field类代表某个类中的一个成员变量
问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,
而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?所以字段fieldX 代表的是x的定义,而不是具体的x变 量。
示例代码:
ReflectPoint point = new ReflectPoint(1,7);
Field y = Class.forName("cn.itcast.corejava.ReflectPoint").getField("y");
System.out.println(y.get(point));
//Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getField("x");
Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x");
x.setAccessible(true);
System.out.println(x.get(point));
Method类:
Method类代表某个类中的一个成员方法
得到类中的某一个方法:
例子: Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式: System.out.println(charAt.invoke(str, 1));
如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态 方法!
jdk1.4和jdk1.5的invoke方法的区别:
Jdk1.5:public Object invoke(Object obj,Object... args)
Jdk1.4:public Object invoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法 时,数组中的每个 元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写 为 charAt.invoke(“str”, new Object[]{1})形式。
用反射方式执行某个类中的main方法:
class.forName("classname").getMethod("main",String[].class);
启动Java程序的main方法的参数是一个字符串数组,即public static void main(String[] args),
通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,
整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数
传递给invoke方法时,javac会到底按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,
会按jdk1.4的语法进行处理,即把数组打散成为若干个单独的参数。所以,在给main方法传递参数时,
不能使用代码mainMethod.invoke(null,new String[]{“xxx”}),
javac只把它当作jdk1.4的语法进行理解,而不把它当作jdk1.5的语法解释,
因此会出现参数类型不对的问题。
解决办法:
mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});
mainMethod.invoke(null,(Object)new String[]{"xxx"}); ,编译器会作特殊处理,编译时不把参数当作数组看待,也就不会数 组打散成若干 个参数了
数组的反射:
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
int[] a1=new int[]{1,2,3};
int[] a2=new int[]{1};
int[][] a3=new int[2][3];
String[] a4=new String["aa","bb"];
Class c1=a1.getClass();
Class c2=a2.getClass();
Class c3=a3.getClass();
Class c4=a4.getClass();
System.out.println(c1==c2); // 返回true
System.out.println(c1==c3); // 返回false
System.out.println(c4==c1); // 返回 false
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
System.out.println(c1.getSuperclass().getName());// 打印java.lang.Object
System.out.println(c4.getSuperclass().getName());// 打印java.lang.Object
基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型 使用,又可以 当做Object[]类型使用。
Arrays.asList()方法处理int[]和String[]时的差异:
System.out.println(Arrays.asList(a1));//打印[[I@dc8569]
System.out.println(Arrays.asList(a3)); // [ss, aa]
代码举例:Array工具类用于完成对数组的反射操作(打印一个对象,如果不是数组就打印一个,如果是对象就分变量打印)。
public void printObj(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的实例对象,比较观察运行结果差 异。
代码示例如下:
fis=new FileInputStream("config.properties"); // config.properties 文件中先后配置ArrayList和HashSet 查看结果的不同
Properties p=new Properties();
p.load(fis);
fis.close();
String className=p.getProperty("className");
Collection c=(Collection)Class.forName(className).newInstance();
c.add(p1);
c.add(p2);
c.add(p3);
c.add(p1);
System.out.println(c.size());// config.properties 配置HashSet 打印3 ArrayList 打印4.
-------android培训、java培训、期待与您交流! ----------
- 黑马程序员--java 反射
- 黑马程序员之反射
- 黑马程序员之反射
- 黑马程序员__java_反射
- 黑马程序员_反射
- 黑马程序员 反射
- 黑马程序员--Java反射
- 黑马程序员--反射
- 黑马程序员-java-反射
- 黑马程序员:反射技术
- 黑马程序员_java反射
- 黑马程序员---反射
- 黑马程序员-反射
- 黑马程序员---反射
- 黑马程序员_反射
- 黑马程序员_反射
- 黑马程序员:反射
- 黑马程序员_反射
- 图片缓存:ImageCache和ImageSdCache(一)
- 软件工程-第三章-软件需求分析
- CSS应用中十四个技巧精彩问答
- Stanford ML - Lecture 7 - Machine learning system design
- 第二次上机报告
- 黑马程序员--------反射
- android--JNI 实例备忘
- JAVA 泛型限定
- faith老师 Learn To Be Strong
- ZOJ Unrequited Love 图论+STL
- php写一个函数遍历文件夹下所有的文件和子文件
- Argus LA3135
- cs硕士妹子找工作经历【阿里人搜等互联网】
- 处理数据库置疑脚本