黑马程序员_高新技术Java反射机制
2014-01-23 23:32
246 查看
一、反射的基石-----Class类(JDK1.2)
在介绍反射的时候,必须了解反射最基本的Class类,要注意小心class关键字的区别。class是一个关键字,用来定义类的.
java程序中的各个Java类都属于同一个事物,表述这类事物的Java类名就是Class.例如:
众多的人------Person(类的实例)
众多的java类------Class(java类,代表一份字节码文件)
Java类用于描述一类的事物的共性,该类事物有什么属性,没有什么属性,至于该属性是什么,是由这个类的实例对象来确定的,不同的实例对象有不同的属性值.
Java程序中的各个类,他们属于同一类事物,用一个类可以来描述它们,这个类就是Class.
Class描述了类的名字,类的访问属性,类所属的包名,字段名称的列表、方法名称的列表等.
Class.forName()的作用:得到一个类的字节码
方式有两种:1.已经加载过:直接获得类的字节码
2.没有加载过:则先通过类加载器将字节吗放入虚拟机内存中,再获取.
得到各字节码对应的实例对象三种方式:
String str = "abc";
1. Class clazz = str.getClass(); ------------对象名.getClass();
2. Class clazz = String.class; ------------类名.class;
3. Class clazz = Class.forName("java.ang.String"); ------------反射都用这种方式
九个预定义Class实例对象:八个基本类型+void 它们都有对应的Class对象;
二、反射机制的概念
反射机制就是把一个Java类中的各个成分映射成相应的Java类。例如:一个Java类是用一个Class对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等信息,它们也是由一个Java类来表示的。就像汽车是一个类,汽车中有发动机,变速箱等也是一个类。
表示Java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是:Field、Method、Contructor、Packpage等等。
1.构造方法的反射应用(Constructor类)
4000
2.成员变量的反射(Field类)和成员方法的反射(Method类)
3.数组的反射
4.ArrayList---HashSet的比较以及HashCode的作用(并且利用实现框架的原理)
框架的概念以及用反射技术开发框架的原理,把我们要调用的类,放在配置文件中,在源程序中不出现类名.以动态方式获取.
在介绍反射的时候,必须了解反射最基本的Class类,要注意小心class关键字的区别。class是一个关键字,用来定义类的.
Class没有公共构造方法。
Class对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的
defineClass方法自动构造的。
java程序中的各个Java类都属于同一个事物,表述这类事物的Java类名就是Class.例如:
众多的人------Person(类的实例)
众多的java类------Class(java类,代表一份字节码文件)
Java类用于描述一类的事物的共性,该类事物有什么属性,没有什么属性,至于该属性是什么,是由这个类的实例对象来确定的,不同的实例对象有不同的属性值.
Java程序中的各个类,他们属于同一类事物,用一个类可以来描述它们,这个类就是Class.
Class描述了类的名字,类的访问属性,类所属的包名,字段名称的列表、方法名称的列表等.
Class.forName()的作用:得到一个类的字节码
方式有两种:1.已经加载过:直接获得类的字节码
2.没有加载过:则先通过类加载器将字节吗放入虚拟机内存中,再获取.
得到各字节码对应的实例对象三种方式:
String str = "abc";
1. Class clazz = str.getClass(); ------------对象名.getClass();
2. Class clazz = String.class; ------------类名.class;
3. Class clazz = Class.forName("java.ang.String"); ------------反射都用这种方式
九个预定义Class实例对象:八个基本类型+void 它们都有对应的Class对象;
public class ReflectTest_反射 { public static void main(String[] args) throws Exception { String str1 = "abc"; Class clazz1 = str1.getClass(); Class clazz2 = String.class; Class clazz3 = Class.forName("java.lang.String"); Object obj = clazz3.newInstance();//创建这个实例对象 System.out.println(clazz1+"----"+clazz2+"=========="+clazz3);//class java.lang.String System.out.println(clazz1==clazz2);//true System.out.println(clazz1==clazz3);//true System.out.println(clazz3.isPrimitive());//判定指定的 Class 对象是否表示一个基本类型 System.out.println(int.class.isPrimitive());//true System.out.println(int.class==Integer.class);//false 类型不同,字节码不同 System.out.println(int.class==Integer.TYPE);//true 类型相同 Integer.TYPE代表包装类型包装的基本类型字节码 System.out.println(int[].class.isPrimitive());//任何类型都有字节码,但是不是基本类型 //总之,只要在源程序中出现的类型,都有各自的Class实例对象,例如int[],void } }
二、反射机制的概念
反射机制就是把一个Java类中的各个成分映射成相应的Java类。例如:一个Java类是用一个Class对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等信息,它们也是由一个Java类来表示的。就像汽车是一个类,汽车中有发动机,变速箱等也是一个类。
表示Java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是:Field、Method、Contructor、Packpage等等。
1.构造方法的反射应用(Constructor类)
public class Constructor_构造方法的反射应用 { public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException { /*new String(new SringBuffer("abc")); 通过反射将得到String这个参数类型的构造方法 想到的String构造方法中参数类型是StringBuffer的构造方法 那么就得到String这个类,通过getConstructor()方法将参数写进去 */ //这个只是得到了一份字节码,还不知道是String类型 Constructor constructor = String.class.getConstructor(StringBuffer.class);//这里面的参数是可变参数 /*第一个是String这个类的字节码 第二个是拿着这个字节码创建出一个对象 现在只知道有一个constructor,到底是哪个构造方法我们还不知道 第一个StringBuffer表示选择哪个构造方法,是把你翻译成class,然后去运行 第二个StringBuffer是创建这个对象的参数 */ String str2 = (String) constructor.newInstance(/*"abc"*/new StringBuffer("abc")); System.out.println(str2.charAt(2)); //得到方法需要类型,去调用这个方法的时候也需要调用同样类型的实例对象(关键) //在这里Class也有一个newInstance()方法 String obj = (String) Class.forName("java.lang.String").newInstance(); /* 这个方法是简化了通过constructor去得到这个构造方法,直接先得到了 * 会发现这个对象创建,他没有参数,使用的是默认的构造方法. * 原理:该方法的内部先得到了默认的构造方法,用到了缓存机制将它缓存起来,下一次就 * 直接从缓存中得到,这个只适合无参的构造函数. * 这从侧面说明了一个问题:反射比较消耗性能,得到这个构造方法的过程比较慢,要不至于他不会缓存 * */ } }
4000
2.成员变量的反射(Field类)和成员方法的反射(Method类)
public class ReflectPoint_反射成员变量的测试 { private int x; public int y; public String str1= "ball"; public String str2 = "basketball"; public String str3 = "itcsat"; public ReflectPoint_反射成员变量的测试(int x, int y) { super(); this.x = x; this.y = y; } @Override public String toString() { return "ReflectPoint_反射成员变量的测试 [str1=" + str1 + ", str2=" + str2 + ", str3=" + str3 + ", 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; } }
public class Field_成员变量的反射应用 { public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { // 创建了该类的对象 ReflectPoint_反射成员变量的测试 pt1 = new ReflectPoint_反射成员变量的测试(3, 5); ReflectPoint_反射成员变量的测试 pt2 = new ReflectPoint_反射成员变量的测试(3, 6); /* * 想知道创建对象参数所对应的变量是什么 通过反射获得该对象变量的值是多少 */ Field fieldY = pt1.getClass().getField("y"); /* * fieldy的值是5吗??错!! fieldy不代表一个具体的值,只代表一个类身上的变量 * 用fieldy这个变量获得某个对象参数是"y"的值 */ System.out.println(fieldY.get(pt1));// 5 System.out.println(fieldY.get(pt2));// 6 /* * 同样是通过pt1这个引用对象获得,但获取的对象不同,值也不同 Field fieldX = * pt1.getClass().getField("x"); * 这里x这个成员变量时私有的,getField无法得到,有个方法getDeclaredField */ Field fieldAllX = pt1.getClass().getDeclaredField("x");// 返回这个x这个字段,只要是声明过的 /* * 但是得到了这个字段却依然无法访问,无法拿到 将这个变量对象设置成可以访问,就能取出来了,这个过程称之为暴力反射. */ fieldAllX.setAccessible(true); System.out.println(fieldAllX.get(pt1)); /* * 题目: 将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。 */ changeStringValue(pt1); System.out.println(pt1); // 方法的反射,调用某个类中的方法 // Method代表某个类中的成员方法,下面用反射去调用String类的charAt方法 char []str1 = {'6','5','5','1','1'}; Method method = String.class.getMethod("valueOf", char[].class);//方法名,方法参数类型字节码 // invoke对带有指定参数的指定对象调用由此 Method 对象表示的底层方法 System.out.println(method.invoke(null, str1));// 对象,方法参数....如果第一个参数为null说明该方法是静态的方法 } private static void changeStringValue(Object obj) throws IllegalArgumentException, IllegalAccessException { // 获得传来的对象的字节码文件,再得到所有的字段 Field[] fields = obj.getClass().getFields(); // 对得到的的字段迭代 for (Field field : fields) { // 获得这个字段的类型,并判断是否是String的 // 这里最好用"=="符号,不能用equels,如果获得类型是String,那么是同一份字节码用==比 if (field.getType() == String.class) { String oldValue = (String) field.get(obj); String newValue = oldValue.replace('b', 'a');// 替换字符串中所有b的字符 field.set(obj, newValue);// 对这个对象的值重新设置 } } } }
3.数组的反射
public class ArrayReflect_数组的反射 { public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException { //正常调用方法 TestArry.main(new String[]{"111","222"}); //用反射执行某个类中的main方法 String className = args[0]; System.out.println(className);//com.itcast.advanced.TestArry 在运行配置 自变量中写的参数传进来 Class clazz = Class.forName(className); Method method = clazz.getMethod("main",String[].class); method.invoke(null, (Object)new String[]{"111","222","333"}); //思考一下为什么要用反射的方式调用 /* * 因为我们一开始是不知道类名的,这个类名是变化的, * 通过别的地方获取到这个类的名称,获取其中的main方法 * 并执行main方法 */ int [] a = {1,12,1}; String [] a1= {"11","11"}; System.out.println(Arrays.asList(a)); System.out.println(Arrays.asList(a1)); //1.4jdk中接收的是Object[] a类型 1.5jdk中是T...a //String []符合1.4的,就把String每一个元素取出来放在Object中, //int[] 不符合1.4的,就找1.5的,结果将整个int[]都当做一个Object //那么就写一个对数组的反射 Object obj1 = new String[]{"1","2"}; Object obj2 = new int[]{11,11,22,33}; printObject(obj1); printObject(obj2); printObject("111"); //思考一下:如果想获得一个数组的类型怎么做?int[]目前没有办法,只能获得数组每个元素对应的类型 int [][] obj3 = {{1},{2},{3}}; Object [] obj4 = {"123",1}; printObjectType(obj3); printObjectType(obj4); } private static void printObjectType(Object[] obj) { int len = Array.getLength(obj); for (int i = 0; i <len; i++) { System.out.println(obj[i].getClass().getName());//循环每一个元素,并获得字节码,得到他们的类型 } } private 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); } } } class TestArry{ public static void main(String[] args) { for (int i = 0; i < args.length; i++) { System.out.println(args[i]); } } }
4.ArrayList---HashSet的比较以及HashCode的作用(并且利用实现框架的原理)
框架的概念以及用反射技术开发框架的原理,把我们要调用的类,放在配置文件中,在源程序中不出现类名.以动态方式获取.
public class ReflectTest_反射的框架原理 { public static void main(String[] args) throws IOException, InstantiationException, IllegalAccessException, ClassNotFoundException { InputStream input = new FileInputStream("config.properties");//通过字节流读取流读取配置文件信息 Properties properties = new Properties(); properties.load(input); //String className1 = properties.getProperty("className1");//通过配置文件的键获取对应的值---ArrayLiat String className2 = properties.getProperty("className2");//通过配置文件的键获取对应的值---HashSet Collection collection = (Collection) Class.forName(className2).newInstance();//创建这个字节码对象 ReflectPoint_反射成员变量的测试 point1 = new ReflectPoint_反射成员变量的测试(3, 4); ReflectPoint_反射成员变量的测试 point2 = new ReflectPoint_反射成员变量的测试(3, 5); ReflectPoint_反射成员变量的测试 point3 = new ReflectPoint_反射成员变量的测试(3, 6); ReflectPoint_反射成员变量的测试 point4 = new ReflectPoint_反射成员变量的测试(3, 4); /*当集合石HashSet时,这个对象在内存数组中就会通过一个哈希算法得到一个哈希值,当将这对象再存一遍的时候,会 找这个对象的哈希值是否存在,不存在,就将对象存入HashSet中,如果存在,就不存入这个对象 如果要判断对象的值也要唯一,那么就要覆盖HashCode方法和equels方法,自己去写equels方法,Objecj的equels默认比较的是内存地址*/ collection.add(point1); collection.add(point2); collection.add(point3); collection.add(point4);//覆盖了equels方法这个对象就无法存入HashSet集合中 /*着这里要注意,一但对象存入了Hash类型的集合后,他就有自己的一个哈希值, 如果将这个对象参数修改后,这个对象就会重新产生一个哈希值,也将无法返回这个对象的结果 例如:将一个值修改后,再将它去除,一开始结果是3,去除这个对象,应该是2,但是输出结果依然是3(重点细节)*/ point1.y = 7; point2.y = 7; point3.y = 7; collection.removeAll(collection); /* 我将这三个集合全部修改后,我直接移除这个集合所有的元素,可怕的的是结果依然是3 原因是:修改后的对象又会产生一个哈希值,存在集合中,那么这个对象在集合中存储的位置发生了变化, 而我们想删除的那个集合的哈希值已经不在了,调用删除方法的时候依然还是用的原来的哈希值在寻找这个集合 所以得出一个结论是:当对象存入Hash类型的集合当中时,这个对象就不能去修改 否则,导致内存泄露*/ System.out.println(collection.size());//输出结果是3 } }
相关文章推荐
- 黑马程序员-----Java高新技术-----Java反射机制深入详解
- 黑马程序员_高新技术之代理浅谈
- 黑马程序员 java反射机制
- 黑马程序员--20--高新技术(一)
- 黑马程序员-----高新技术-----动态代理详解
- 黑马程序员--java高新技术--反射的深入讲解
- 黑马程序员_高新技术_枚举
- 黑马程序员_java学习日记_Java高新技术_枚举
- 黑马程序员_高新技术加强_浅谈2
- 黑马程序员---Java高新技术学习笔记-1
- 黑马程序员——高新技术(二)
- 黑马程序员-【强哥笔记】系列之Java高新技术笔记之Java5新特性(第2天)
- 黑马程序员_高新技术
- 黑马程序员_Java高新技术--代理
- 黑马程序员——Java高新技术之枚举
- 黑马程序员——高新技术--泛型
- 黑马程序员——高新技术---反射
- 黑马程序员面试题Java高新技术之反射
- 黑马程序员-高新技术-反射
- 黑马程序员---java高新技术之注解