黑马程序员_反射

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


一.类加载器




1.类的加载




当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化




 加载 
就是指将class文件读入内存,并为之创建一个Class对象.任何类被使用时系统都会建立一个Class对象




连接:接阶段又可以分为三个子步骤:验证,准备和解析




验证:是否有正确的内部结构,确保java类型数据格式的正确性,并适于JVM使用




准备:负责为类的静态成员分配内存,并设置默认初始化值




解析:解析过程就是在类型的常量池中寻找类,接口,字段和方法的符号引用,把这些符号引用替换成直接引
用.这个阶段可以被推迟到初始化之后,当程序运行的过程中真正使用某个符号引用的时候再去解析它




类初始化时机


1)创建类的实例
2)访问类的静态变量,或者为静态变量赋值
3)调用类的静态方法
4)使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
5)初始化某个类的子类
6)直接使用java.exe命令来运行某个主类




2.类加载器




含义:负责将.class文件加载到内在中,并为之生成对应的Class对象
类加载器的组成及作用


Bootstrap ClassLoader 根类加载器:也被称为引导类加载器,负责Java核心类的加载.比如System,String等.在JDK中JRE的lib目录下rt.jar文件中


Extension ClassLoader 扩展类加载器:负责JRE的扩展目录中jar包的加载.在JDK中JRE的lib目录下ext目录


Sysetm ClassLoader 系统类加载器:负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径






二.反射




1.概述


反射机制:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法.对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制


反射技术:其实就是动态加载一个指定的类,并获取该类中的所有的内容,而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员.简单说:反射技术可以对一个类进行解剖


反射的好处:大大的增强了程序的扩展性


2.反射的基本步骤:




获得Class对象,就是获取到指定的名称的字节码文件对象.




实例化对象,获得类的属性.方法或构造函数




访问属性,调用方法,调用构造函数创建对象




3.获取Class对象的三种方式:




每一个类对象都有一个静态的属性class,弊端:必须要先明确该类.如果是明确地获得某个类的Class对象可以用此方式,主要用于传参 
Class clazz = Person.class; 


通过每个对象都具备的方法getClass来获取.弊端:必须要创建该类对象,才可以调用getClass方法.如果拿到了对象,不知道是什么类型可以用此方式,用于获得对象的类型 
Object obj = new Person(); 
Class clazz1 = obj.getClass(); 


使用的Class类中的方法,静态的forName方法.指定什么类名(完整的类名),就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可,用于类加载 
String classname = “cn.itcast.reflect.Person”; 
Class clazz = Class.forName(classname);//当类的字节码已经加载进了内存,就将该字节码返回;如果jvm还没有该字节码,就用类加载器加载,再返回加载的字节码
前两种方式不利于程序的扩展,因为都需要在程序使用具体的类来完成 
三种方式得到的字节码都是同一个字节码:


代码演示: 


<strong><span style="font-family:SimHei;font-size:14px;">[java] view plaincopy
String str1 = “abc”; 
Class cls1 = str1.getClass(); 
Class cls2 = String.class; 
Class cls3 = Class.forName(“java.lang.String”); 
System.out.println(cls1 == cls2);//true 
System.out.println(cls1 == cls3);//true </span></strong>




4.九个预定义的Class:




1)包括八种基本类型(byte;short;int;long;float;double;char;boolean)的字节码对象和一种返回值为void类型的void.class


2)Integer.TYPE是Integer类的一个常量,它代表此包装类型包装的基本类型的字节码,所以和int.class是相等的.基本数据类型的字节码都可以用与之对应的包装类中的TYPE常量表示


3)只要是在源程序中出现的类型都有各自的Class实例对象,如int[].class.数组类型的Class实例对象,可以用Class.isArray()方法判断是否为数组类型的


5.反射的使用:


Class类


1)类中的方法,不包括获取成员属性及方法对象


static Class forName(String className):返回与给定字符串名的类或接口的相关联的Class对象


Class getClass():返回的是Object运行时的类;即返回Class对象即字节码对象 


String getName():以String形式返回此Class对象所表示的实体名称


String getSuperclass():返回此 Class 所表示的实体(类;接口;基本类型或 void)的超类的 Class 


boolean isArray():判定此Class对象是否表示一个数组 


boolean isPrimitive():判断指定的Class对象是否是一个基本类型 


2)通过Class对象获取类实例


如:


String className="包名.Person";


Class clazz=Class.forName(className);


Object obj=clazz.newInstance();


反射获取成员方法并使用:


获取所有方法:


Method[] getMehtods():返回一个包含某些Method对象的数组.是所代表的的类中的公共成员方法


Method[] getDeclareMethods():返回Method 对象的一个数组,这些对象反映此Class 对象表示的类或接口声明的所有方法,包括公共;保护;默认(包)访问和私有方法,但不包括继承的方法


获取单个方法:
Method getMethod(String name,Class<?>… parameterTypes):返回一个Method对象,它表示的是此Class对象所代表的类的指定公共成员方法


Method getDeclaredMethod(String name,Class<?>… parameterTypes):返回一个Method 对象,该对象反映此Class 对象所表示的类或接口的指定已声明方法.name 参数是一个String,它指定所需方法的简称,parameterTypes 参数是Class 对象的一个数组,它按声明顺序标识该方法的形参类型


使用方法:Method类方法


void setAccessible(boolean)方法:值为true时取消 Java 语言访问检查


Object invoke(Object obj ,参数);//调用对象的method方法


代码演示:




[java] view plaincopy
[java] view plaincopy 
package itcast; 


import java.lang.reflect.Constructor; 
import java.lang.reflect.Method; 


/** 
* @author oyfc 
*/ 
public class MethodDemo { 


/** 
* 通过反射获取成员方法并使用。 
* @param args 
* @throws ClassNotFoundException 
*/ 
<span style="white-space:pre"> </span>public static void main(String[] args) throws Exception { 


<span style="white-space:pre"> </span>//获取字节码文件对象 
<span style="white-space:pre"> </span>String className = "itcast.Person"; 
<span style="white-space:pre"> </span>Class class1 = Class.forName(className); 


<span style="white-space:pre"> </span>//创建对象 
<span style="white-space:pre"> </span>Constructor constructor = class1.getConstructor(String.class,int.class); 
<span style="white-space:pre"> </span>Object object = constructor.newInstance("zhangfei",21); 


<span style="white-space:pre"> </span>//获取所有成员方法 
<span style="white-space:pre"> </span>Method[] methods = class1.getDeclaredMethods(); 
<span style="white-space:pre"> </span>for(Method meth: methods){ 
<span style="white-space:pre"> </span>sop(meth); 
<span style="white-space:pre"> </span>} 
<span style="white-space:pre"> </span>//获取成员方法 
<span style="white-space:pre"> </span>Method method = class1.getDeclaredMethod("show"); 
<span style="white-space:pre"> </span>//暴力访问 
<span style="white-space:pre"> </span>method.setAccessible(true); 
<span style="white-space:pre"> </span>//调用方法 
<span style="white-space:pre"> </span>method.invoke(object, null); 




<span style="white-space:pre"> </span>} 


/** 
* @param method 
*/ 
<span style="white-space:pre"> </span>private static void sop(Object object) { 
<span style="white-space:pre"> </span>System.out.println(object); 
<span style="white-space:pre"> </span>} 







反射类的构造函数并使用:


获取所有构造方法:


Constructor<?>[] getConstructors()返回一个包含某些Constructor 对象的数组,这些对象反映此Class 对象所表示的类的所有公共构造方法.


Constructor<?>[] getDeclaredConstructors()返回Constructor 对象的一个数组,这些对象反映此Class 对象表示的类声明的所有构造方法.它们是公共、保护、默认(包)访问和私有构造方法


获取单个构造方法:


Constructor<T> getConstructor(Class<?>...parameterTypes):返回一个Constructor 对象,它反映此Class 对象所表示的类的指定公共构造方法


Constructor<T> gettDeclaredConstructor():


使用方法:Constructor类的方法


T newInstance(Object ... initargs)):创建此Class对象所表示的类的一个新实例


代码演示:




[java] view plaincopy
</pre>程序示例:</p><p><span style="font-size:18px;"></span><pre name="code" class="java">[java] view plaincopy 
package itcast; 


import java.lang.reflect.Constructor; 


/** 
* 通过反射获取构造方法并使用。 

* @author oyfc 
*/ 
<span style="white-space:pre"> </span>public class ConstructorDemo { 


/** 
* @param args 
* @throws Exception 
*/ 
<span style="white-space:pre"> </span>public static void main(String[] args) throws Exception { 
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>// 获取字节码文件对象 
<span style="white-space:pre"> </span>String className = "itcast.Person"; 
<span style="white-space:pre"> </span>Class class1 = Class.forName(className); 


<span style="white-space:pre"> </span>// 获取所有所有公共构造方法 
<span style="white-space:pre"> </span>// Constructor[] constructors = class1.getConstructors(); 
<span style="white-space:pre"> </span>// 获取所有所有构造方法 
<span style="white-space:pre"> </span>Constructor[] constructors = class1.getDeclaredConstructors(); 
<span style="white-space:pre"> </span>for (Constructor con : constructors) { 
<span style="white-space:pre"> </span>sop(con); 
<span style="white-space:pre"> </span>} 


<span style="white-space:pre"> </span>//获取无参构造方法 
<span style="white-space:pre"> </span>Constructor constructor = class1.getDeclaredConstructor(); 
<span style="white-space:pre"> </span>//取消访问检查,暴力访问 
<span style="white-space:pre"> </span>constructor.setAccessible(true); 
<span style="white-space:pre"> </span>//创建对象 
<span style="white-space:pre"> </span>Object object = constructor.newInstance(); 
<span style="white-space:pre"> </span>sop(object);//null::0 


<span style="white-space:pre"> </span>//获取有参构造方法 
<span style="white-space:pre"> </span>Constructor constructor2 = class1.getDeclaredConstructor(String.class); 
<span style="white-space:pre"> </span>//创建对象 
<span style="white-space:pre"> </span>Object object2 = constructor2.newInstance("张飞"); 
<span style="white-space:pre"> </span>sop(object2);//张飞::0 


<span style="white-space:pre"> </span>} 


/** 
* @param con 
*/ 
<span style="white-space:pre"> </span>private static void sop(Object obj) { 
<span style="white-space:pre"> </span>System.out.println(obj); 
<span style="white-space:pre"> </span>} 



反射类的成员变量并使用:


获取所有成员:


Field[] getFields():返回包含某些Field对象的数组,表示所代表类中的成员字段


Field[] getDeclaredFields():


获取单个成员:


Field getField(String name):返回一个Field对象,它表示此Class对象所代表的类或接口的指定公共成员字段


Field getDeclaredField(String name)


修改成员的值:Field类的方法


set(Object obj,Object value):将指定对象变量上此 Field 对象表示的字段设置为指定的新值


代码演示:




<strong><span style="font-family:SimHei;font-size:14px;">[java] view plaincopy
[java] view plaincopy 
Field field = clazz.getField(fieldName);//获取指定的字段值 
field.setAccessible(true);//取消访问检查,也称暴力访问 
field.set(obj,value);//将指定对象变量上此 Field 对象表示的字段设置为指定的新值. 


//如:
[java] view plaincopy
[java] view plaincopy 
package itcast; 


import java.lang.reflect.Constructor; 
import java.lang.reflect.Field; 


/** 
* @author oyfc 
*/ 
public class FieldDemo { 


/** 
* @param args 
* @throws Exception 
*/ 
public static void main(String[] args) throws Exception { 
//获取字节码文件对象 
String className = "itcast.Person"; 
Class class1 = Class.forName(className); 


//创建实例对象 
Constructor constructor = class1.getConstructor(String.class,int.class); 
Object object = constructor.newInstance("张非",21); 


//获取所有成员变量 
// Field[] fields = class1.getDeclaredFields(); 
// for(Field field:fields) { 
// sop(field); 
// } 


//获取单个成员变量 
Field field = class1.getField("name"); 
//为指定变量赋值 
field.set(object, "xiaozhang"); 
sop(object);//xiaozhang::21 







/** 
* @param field 
*/ 
private static void sop(Object object) { 
System.out.println(object); 



} </span></strong>






6.数组的反射 


1)每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组属于同一个类型,即都共享该 Class 对象


2)代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class 


3)基本数据类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用;非基本数据类型的一维数组既可以当做Object类型使用,有可以当做object[]类型使用


代码演示:




<span style="font-family:SimHei;">[java] view plaincopy
public class ReflectTest { 
public static void main(String[] args) throws Exception { 
int [] a1 = new int[]{1,2,3}; 
int [] a2 = new int[4]; 
int[][] a3 = new int[2][3]; 
String [] a4 = new String[]{"a","b","c"}; 
System.out.println(a1.getClass() == a2.getClass());//true 
System.out.println(a1.getClass() == a4.getClass());//false 
System.out.println(a1.getClass() == a3.getClass());//false 
System.out.println(a1.getClass().getName());//[I 
System.out.println(a1.getClass().getSuperclass().getName());//java.lang.Object 
System.out.println(a4.getClass().getSuperclass().getName());//java.lang.Object 


Object aObj1 = a1; 
Object aObj2 = a4; 
//Object[] aObj3 = a1;//错误 
Object[] aObj4 = a3; 
Object[] aObj5 = a4; 
System.out.println(a1);//打印的是变量a1的值,不是数组的值[I@1cfb549 
System.out.println(a4); 
System.out.println(Arrays.asList(a1)); 
System.out.println(Arrays.asList(a4)); 


}</span> 
4)Arrays.asList()方法处理int[]和String[]时的差异 


static List asList(T… a)// 返回一个受指定数组支持的固定大小的列表.(对返回列表的更改会“直接写”到数组)


System.out.println(Arrays.asList(a1));//[[I@1cfb549] 


System.out.println(Arrays.asList(a4));//[a,b,c] 
5)Array工具类用于完成对数组的反射操作 


Array 类提供了动态创建和访问 Java 数组的方法 


static Object get(Object array,int index)//返回指定数组对象中索引组件的值,如果该值是一个基本类型值,则自动将其包装在一个对象中.array - 数组,index - 索引 


static int getLength(Object array) //以 int 形式返回指定数组对象的长度


代码演示:




<strong>[java] view plaincopy
<span style="white-space:pre"> </span>private static void printObject(Object obj) { 
<span style="white-space:pre"> </span>Class clazz = obj.getClass(); 
<span style="white-space:pre"> </span>if(clazz.isArray()){ 
<span style="white-space:pre"> </span>int len = Array.getLength(obj); 
<span style="white-space:pre"> </span>for(int i=0;i<len;i++){ 
<span style="white-space:pre"> </span>System.out.println(Array.get(obj, i)); 
<span style="white-space:pre"> </span>} 
<span style="white-space:pre"> </span>}else{ 
<span style="white-space:pre"> </span>System.out.println(obj); 
<span style="white-space:pre"> </span>} 
} </strong>




7.反射的作用:实现框架的功能 


框架与工具类有区别,工具类被用户的类调用,而框架式调用用户提供的类


在写框架时,用户可能还不存在,那么我写的框架程序怎么调用用户以后写的类.因为在写程序时无法知道要被调用的类名,所有在程序中无法直接new某个类的实例对象,要用到反射方式 


采用配置文件加反射的方式创建ArrayList和HashSet的实例对象


代码演示:


<strong><span style="font-family:SimHei;">[java] view plaincopy
<span style="white-space:pre"> </span>public class ReflectTest2 { 
<span style="white-space:pre"> </span>public static void main(String[] args) throws Exception{ 
<span style="white-space:pre"> </span>//InputStream ips = new FileInputStream("config.properties"); 


<span style="white-space:pre"> </span>//查找资源,类加载器,配置文件放在classpath的目录下 
<span style="white-space:pre"> </span>//InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties"); 


<span style="white-space:pre"> </span>//相对该类包的路径,写相对路径 
<span style="white-space:pre"> </span>//InputStream ips = ReflectTest2.class.getResourceAsStream("resources/config.properties"); 


<span style="white-space:pre"> </span>//在classpath的根目录下找,必须从根开始写绝对路径 
<span style="white-space:pre"> </span>InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties"); 


<span style="white-space:pre"> </span>Properties props = new Properties(); 
<span style="white-space:pre"> </span>props.load(ips); 
<span style="white-space:pre"> </span>ips.close(); 
<span style="white-space:pre"> </span>String className = props.getProperty("className"); 


<span style="white-space:pre"> </span>//Collection collections = new HashSet(); 
<span style="white-space:pre"> </span>Collection collections = (Collection)Class.forName(className).newInstance(); 
<span style="white-space:pre"> </span>} 


} </span></strong>




版权声明:本文为博主原创文章,未经博主允许不得转载。
springboot003基于Springboot+Vue的图书个性化推荐系统的设计与实现毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值