黑马程序员之基础加强之反射
来源:互联网 发布:防伪软件哪个好 编辑:程序博客网 时间:2024/05/23 19:19
学习概述:深入学习Java反射概念和原理以及应用
学习目标:熟练掌握Java反射原理,比较流畅的在以后的开发中应用到反射,对于Java.lang.reflect包中的类例如Class,Method,Package等和类中的方法要熟练掌握
1.反射的基石-Class类
(1)首先我们必须理解什么叫做类。类到底是什么样的一种事物?
Java类用于描述一类事物的共性,该类有什么属性,没有什么属性,但是属性的具体值则有这个类的实例对象决定,不同的实例对象有不同的属性值。特别要注意大写Class与小写Class的区别
前面我们在介绍面向对象时提到:类是对某一类对象的抽象,类是概念层次的东西。但是我们也可以进一步的考虑:其实类也是一种对象。就想我们所说的概念主要用于定义,描述其他事物的,但概念本身也是一种食物,那么概念本身也需要被描述,而系统中所有的类,他们实际上也是对象,它们都是java.lang.Class的实例。
提问:Class和class的区别
举例回答:假设Person类代表人,张三,李四代表实例对象,也就是一个一个具体的人,Class类代表Java类,那么它的实例对象又代表什么呢
什么是字节码?
回答:字节码就是一堆二进制代码,当我们在开发过程中需要一个类时,需要先将该类的二进制代码加载到内存中来,然后在创建类的对象。
<1>对应各个类在内存中的字节码
<2>一个类被加载到内存空间时,占用一片存储空间,这个空间里的内容就是字节码,不同类的字节码是不同的,说以他们在内存中的类型是不同的
三种得到各个字节码对应类对象的方法
<1>类名.class
<2>对象.getClass()
<3>Class.forName(类名)
面试题:Class.forName(完整类名)的作用?回答:作用就是返回字节码,返回的方式有两种,如果JVM缓存里已经存在,那么将直接返回字节码,如果没有,那么类加载器 会将字节码加载进JVM,并且一同缓存!
2. 必须要理解反射的概念
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。通俗点来讲Java反射就是将Java类中的各个成分映射成各个Java类(什么叫类的各个成分,比如说一个类它属于哪个包,它有哪些属性,它有哪些方法,等等)。就想一辆汽车一样汽车有发动机,轮胎等等部件,实际上发动机,轮胎也是一个个类啊。我们把一个Java类中每一个成分都解析成相关类。这是我听过的最形象的讲反射概念的话。
注意:使用Java反射的后果是会让系统性能下降很多。
新概念:暴力反射
Java类中由于某些字段是私有的,所欲必须将这些字段用setAccessible()方法设置成可处理成状态,强行拿到这些字段,所以被称为暴力反射。
(1) 构造方法的反射,关键字:Constructor
四个方法用于访问Class对应的类所包含的的构造器
<1> Constructor<T> getConstructor(Class<?>....parameterTypes):返回此Class对象所表示的类的指定的public构造器
<2> Constructor<T>[] getConstructor:返回此Class对象所表示的类的所有的public构造器
<3> Constructor<T> getDeclaredConstructor(Class<?>....parameterTypes):返回此Class对象所表示的类的指定的构造器,与访问级别无关
<4>Constructor<T>[]getDeclaredConstructor:返回此Class对象所表示的类的所有构造器,与访问级别无关
(2) 成员变量的反射,关键字Field
<1>Field getField(String name):返回Class对象所表示的类的指定public属性
<2>Field[ ] getFields():返回Class对象所表示的类的所有public属性
<3>Field getDeclaredField(String name):返回Class对象所表示的类的指定属性,与访问级别无关。
<4>Field[ ] getDeclaredField():返回Class对象所表示的类的所有public属性,与访问级别无关。
新知识:暴利反射:setAccessoble()方法。采用该方法可以拿到某个对象的私有属性的具体值。
作业:将任意一个对象中所有的String类型变量所对应的字符串内容中的"b"变成"a"
package com.lee.homework;import java.lang.reflect.Field;public class StringRegulate {/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubDog dog = new Dog("ouby","blue",4);Field[] fields = dog.getClass().getDeclaredFields();for(Field field:fields){if(field.getType()==String.class){try {String value = (String) field.get(dog);String newValue=value.replace('b', 'a');field.set(dog, newValue);} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}System.out.println(dog.dogName);System.out.println(dog.color);}}
(3) 获取类的方法的原理与构造方法和成员变量原理基本相同,关键字Method
得到方法:Method method = 类名.getMethod("方法名",参数列表);
调用方法:Object invoke(object obj,Object args);该方法中的obj是执行该方法的主调,后面args的执行方法是传入该方法的参数
注意JDK1.4 JDK1.5的invoke方法区别
<1> 调用某个程序中的main方法
思考题:main方法的参数是一系列字符串数组,如何为invoke方法传递字符串数组呢?
按照jdk1.5的语法,整个数组是一个参数,当吧一个字符串数组作为参数。按照1.4的语法,整个数组中的每个元素分别对应一个参数,javac到底按那种语法进行处理 呢。所以在调用main方法时不能使用代码。解决的办法:mainMethod.invoke(nulll,(object)new String[]{...}),否则会出现 wrong number of argument错误
练习:编写一个程序调用另外一个类中的main方法
import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class MainTest {/** * 调用另外一个类中的main方法 */public static void main(String[] args) {// TODO Auto-generated method stubMainReflect mr = new MainReflect();try {Method method = mr.getClass().getMethod("main", String[].class);try {method.invoke(null, (Object)new String[]{"a","bc"});} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InvocationTargetException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (NoSuchMethodException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
<2> 注意的地方:通过反射调用累的静态方法时,不需要给invoke传入对象,传入null就可以
3.数组的反射
数组同样可以当做基本类型来看待,可以通过反射来操作数组。相对于其他类型数组的反射简单了很多,因为Java已经给我们提供了一个Array类,这个类位于reflect包下。通过这个类我们可以非常方便的对数组进行一些列反射操作。
Array提供了几个主要的类方法:
<1> static Object newInstance(Class<?> componentType,int ...length):创建一个指定元素类型和维度的数组,注意第二个参数,我们可以创建多维数组此外这个方法还要注意返回值是Object。注意:基本类型不是Object,例如int[ ]数组不是Object数组。基本类型不是Object。不过数组类型是Object的。
根据Java api的解释:具有相同类型以及相同维数的数组反射的类型才相同
<2> static XXX getXxx(Object array,int index):返回数组中第index个元素
实例代码如下:
package com.lee.reflect;import java.lang.reflect.Array;/* * 数组的反射应用举例 */public class ArrayReflectDemo {/** * @param args */public static void main(String[] args) {//创建一个长度为10的char型数组Object array = Array.newInstance(Character.class, 10);//分别为数组的前三个元素赋值Array.set(array, 0, 'a');Array.set(array, 1, 'b');Array.set(array, 2, 'c');//取出数组首元素,注意返回值Object ch = Array.get(array, 0);//如果是这样,编译器就会报错,因为定义数组时是Character类型,并不是char类型char ch1 =Array.getChar(array, 0);System.out.println(ch1);}}
4.深入理解hashcode
equals()相等的两个对象,hashcode()一定相等;
equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。换句话说,equals()方法不相等的两个对象,hashcode()有可能相等。(我的理解是由于哈希码在生成的时候产生冲突造成的)。
反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。解释下第3点的使用范围,我的理解是在object、String等类中都能使用。在object类中,hashcode()方法是本地方法,返回的是对象的地址值,而object类中的equals()方法比较的也是两个对象的地址值,如果equals()相等,说明两个对象地址值也相等,当然hashcode()也就相等了;在String类中,equals()返回的是两个对象内容的比较,当两个对象内容相等时,
Hashcode()方法根据String类的重写(第2点里面已经分析了)代码的分析,也可知道hashcode()返回结果也会相等。以此类推,可以知道Integer、Double等封装类中经过重写的equals()和hashcode()方法也同样适合于这个原则。当然没有经过重写的类,在继承了object类的equals()和hashcode()方法后,也会遵守这个原则。
一道反复被面的面试题:
说说hashcode方法的作用?
回答:hashcode用来提高集合元素中的查找效率,只有类的实例对象被要求采用哈希算法进行存储时,这个类才被要求覆盖hashcode方法。即使程序可能暂时不会用到当前类的hashcode方法,他是它提供了一个hashcode方法也没什么不好,没准以后什么时候又用到这个方法了,所以通常要求hashcode和equals方法一同被覆盖。
要点:实际上hashcode主要对hashset,hashtable,hashmap这几个集合类有意义。
5.反射的作用--框架
框架的要解决的问题到底是什么?
一个很形象的回答:假设我要做房子卖给用户,但是有用户自己安装门窗,那么我做的房子就是框架,用户需要使用我的框架将他们的门窗插入房子。框架与工具类的区别, 工具类是被用户类调用,而框架则是调用用户类。因为在写程序是才知道要调用的类名,所以在程序中无法直接new出实例对象,所以要采用反射的方式。
学习总结:对反射原理有了初步的认识,可以熟练的采用反射方式获得类的各个成员,还可以用反射方式写一个迷你型框架。
- 黑马程序员之基础加强之反射
- 黑马程序员_Java基础加强之反射
- 黑马程序员_java基础加强之反射
- 黑马程序员-JAVA基础加强之反射
- 黑马程序员_基础加强之反射
- 黑马程序员-Java基础加强之反射
- 黑马程序员_基础加强之反射
- 黑马程序员-----程序员之路_____基础加强之反射
- 黑马程序员_java基础加强之(反射)
- 黑马程序员:基础加强之反射机制和内省
- 黑马程序员--JAVA基础加强之反射技术
- 黑马程序员——java基础加强之反射
- 15--黑马程序员--基础加强之反射机制
- 黑马程序员_技术加强之反射
- 黑马程序员基础加强---反射
- 《黑马程序员》基础加强---反射
- 黑马程序员--基础加强反射
- 黑马程序员-----基础加强-反射
- ansible
- 单例模式
- Android--下拉列表框(Spinner)
- 编译报错 “dereferencing pointer to imcomplete type”原因
- FZU - 2138 久违的月赛之一 (二分)
- 黑马程序员之基础加强之反射
- win32和android 的cocos2dx环境搭建详细教程
- 电脑键盘键值码
- kafka在zookeeper中对应目录
- 执行能力--监控项目
- 声音采集
- eclipse下的weblogic插件改名了
- Hadoop编程、分布式文件系统结构与设计
- 回忆在iOS开发中常常使用的工具