类加载-反射(JAVA灵魂)

一、清楚反射是什么?
1、类加载机制:
加载(class在加载期就被执行,之后再执行main方法)--连接(验证-准备-解析)--初始化

类加载含义:class文件读入内存后,创建一个java.lang.Class对象(专门用来装载类的信息!);一旦某个类被载入JVM中,同一个类就不会再次被载入;该类加载后主要是虚拟机用于用户调用的时候了解构建类的信息;
【细节】:1、我们书写的一个类产生一个class类对象,这个class类对象的实例化对象可以有无数个; 2、String str = new String("hello"); 产生了3个对象(class对象),2个字符串对象;

类加载虽然是JVM使用,但是JAVA是开源的,对其class类名,方法都了解;就可以通过反射;
反射是 通过类(Class 对象),可以得出当前类的 fields、method、construtor、interface、superClass、modified 等,同是可以通过类实例化一个实例、设置、唤醒方法。Spring 中一切都是返射、struts、hibernate 都是通过类的反射进行开发的。反射就是让你可以通过名称来得到对象(类、属性、方法)的技术;【总结:运行时探究和使用编译时未知的类-在类加载的时候通过class对象探究其身上的所有信息(除了注释),在编译时调用和使用对该类未知内部过程!】


二、反射做什么? reflect;
反射使用步骤:
--获得(三种方法Class.forName("全限定类名")、Class c = 类名.class、 Class c = 对象名.getClass();)
--探究(4个单词:Constructor(构造方法)、Fields(属性)、Methods(方法) Declared(所有的,包括非公共的) 所有公共的、所有申明的、指定公共的、指定申明的)
--操作(1、产生对象:Class.forName()/类名.class//对象名.getClass()获得对象
2、通过对象.newInstance()方法调用构造方法//Class的getConstructor
3、调用方法:通过对象的getMethods()方法,返回一个方法对象或方法对象数组;通过invoke()方法调用对应的方法;
4、调用属性:使用get/set方法;)
1、第一步:获得你想操作的类:java.lang.class对象;
1.1 利用语法类型名.class的方式获取到Class对象;(基本数据类型也有Class对象)
Class dogClass1 = DogBean.class;
Class strClass1 = String.class;
Class dateClass1 = Date.class;
Class intArrayClass1 = int[].class;
Class allDogClass1 = DogBean[].class;
Class voidClass = void.class;
【细节】:1、该方法(.class)只能在JDK1.5以后才能被使用;1.5之前要使用包装类的class对象 2、数据类型包装类用type:Integer.TYPE;
3、void也有class对象,也能通过.class来进行访问;
特点:1、不管是基本数据类型还是引用数据类型,甚至返回类型void都可以得到相应的Class对象; 2、没有编译时未知,运行时探究的动态效果;

1.2 调用实例对象继承于Object的getClass(get,set方法)方法
DogBean snoopy = new DogBean();
Class dogClass = snoopy.getClass();//得到DogBean的Class对象
Class strClass = "hello".getClass();
Class dateClass = new Date().getClass();
int[] arrayInt = new int[5];
Class intArrayClass = arrayInt.getClass();
DogBean[] allDogs = new DogBean[5];
Class allDogsClass = allDogs.getClass();
特点:1、可以得到所有类和数组的Class对象;
2、没有编译时未知,运行时探究的动态效果;

1.3 Class.forName("字符串形式的类型名");加载类。获取Class对象。
实现动态效果:把forName后面的引号内的内容改为想要调用的类的类名 用String进行代替
Class dogClass2 = Class.forName("com.lovo.bean.DogBean");//try-catch
特点:1、不支持类型:数组,基本数据类型、返回类型获取相应的Class对象;
2、唯一具有编译时未知,运行时探究的动态效果;动态加载;

2、第二步:调用(研究类的信息),getDeclaredMethods方法;
2.1类的基本申明部分:(包名、修饰符、接口、父类)
String packageName = dogClass.getPackage() .getName(); 探究包名;
String className = dogClass.getName(); 探究类全名和类的限定名;
String classSimpleName = dogClass .getSimpleName(); 探究简单名;
intMod = dogClass.getModifiers(); 得到修饰符,访问修饰符和可选修饰符的组合;
String classModStr = Modifier.toString(intMod) 使用工具类( Modifier)把整型的修饰符表示转换为字符串的修饰符表示;
dogClass. getSuperclass().getName(); 得到父类的名字; 从修饰符到
得到接口:Class[] allInterClasses =dogClass. getInterfaces(); 获得继承接口的class数组; 获得接口的代码
打印方法:(打印所有申明构造中的内容)
String interStr = "";
if(allInterClasses != null && allInterClasses.length != 0){
interStr = "implements ";
for(int i = 0; i < allInterClasses.length; i++){
interStr += allInterClasses[i].getSimpleName();
if(i != allInterClasses.length - 1){
interStr += ",";
}else{
interStr += " ";
}
}
}
System.out.println(classModStr + " class " + classSimpleName +
" extends "+superClassName + " " + interStr +
"}");
获得接口小细节】:获得实现接口的字符串; 可能有,可能没有实现接口 多实现接口后有逗号;

2.2探究属性(制定属性和所有属性)(Field):
2.2.1探究所有属性:
方法一:Field[] allfid = dogClass.getFields();
得到所有的公共属性public、包括父类继承而来的公共属性
方法二:Field[] allfid = dogClass.getDeclaredFields(); 得到所有的申明的属性(不包括来自父类的);
2.2.2 探究指定属性:(属性名,属性类型,属性修饰符)
Field thePublicField = dogClass.getField("name");//得到指定的公共属性(包括父类继承而来的);
Field theField = dogClass.get DeclaredField("age");//得到指定的申明(形参)属性(不包括来自父类的)


2.3探究所有构造(constructor)(公共构造方法:、所申明的构造、带参构造:、异常:exceptionTypes)
Constructor[] allPublicCons = dogClass.getConstructors();//得到所有公共的构造方法
Constructor[] allDeclaredCons = dogClass. getDeclaredConstructors();//得到所有申明的构造
Constructor thePublicCon = dogClass.getConstructor();//得到指定公共构造
Constructor theCon = dogClass.getDeclaredConstructor(String.class,int.class,boolean.class);//得到指定申明构造

得到形参列表: Class[] paramsClass = c on.getParameterTypes();//得到形参列表
if(paramsClass != null && paramsClass.length != 0 ){
for(int i = 0; i < paramsClass.length; i++){
paramStr += paramsClass[i] .getSimpleName();
if(i != paramsClass.length - 1){
paramStr += ",";
}
}
}
得到异常列表 Class[] exeTypes = con.getExceptionTypes();
if(exeTypes != null && exeTypes.length != 0){
exceptionStr = "throws ";
for(int i = 0; i < exeTypes.length; i++){
exceptionStr += exeTypes[i].getSimpleName();
if(i != exeTypes.length - 1){
exceptionStr += ",";
}
}
}
【细节】:1、 形参表示:使用 数据类型.class来表示! 2、构造器中能访问到构造方法修饰符、构造方法名、参数列表、抛出的异常; 3,真正的构造方法名就是类全名com.lovo.bean.userbean;

2.4探究所有方法(method)
第一步得到所有方法//得到所有的申明方法// 得到所有的指定方法;

3、第三步:使用reflectionAPI操作这些信息;
3.1 使用反射创建对象-- 在java中第三种创建对象的方法--newInstance()
3.1.1根据探究到的Constructor对象,产生类的实例对象;
好处:可以调用类中的任意构造方法; 坏处:实现过于麻烦!
DogBean dog = null ;
Constructor theCon =dogClass. getDeclaredConstructor(String.class,int.class,boolean.class);
dog = (DogBean) theCon.newInstance("",5,true); 通过这个方法在反射中用来产生实例对象
【细节】:1、对象的产生访问会受到访问修饰符的限制的!
2、 突破访问权限【构造、方法、属性都可以使用】:theCon.setAccessible(true);设置访问权限为可访--不到万不得已不能用;

3.1.2直接利用 Class对象产生实例化对象:
好处:代码简洁; 坏处:只能调用公共无参构造;
DogBean dog = null ;
dog = (DogBean) dogClass.newInstance();

3.2操作属性:探究到一个Name属性,给Field对象赋值--- 用get/set方法;受制于访问修饰符;
Field thePublicField = dogClass. getField(“name”);
thePublicField.set( dog1 , "小白" );给Field对象赋值,第一个参是代表给那个狗对象的name属性赋值;

3.3操作方法:上图
Method thePublicMethod = dogClass.getDeclaredMethod( "bark", int.class);
thePublicMethod.setAccessible(true);//不准用 方法名 + 形参对象
thePublicMethod. invoke(snoopy,10); / / 实例化对象标识符 + 实参;

【解决方案-语法糖数组做形参】: 传参,(Class...array)数据类型后加三个点:将数组作为参数传入,这个调用者就可以通过将数字加点的形式传入;但是这里不能传入数组; 好处:调用者自己将其封装来交给实参; 使用场景:不知道后面形参有多少个的时候使用;

三、反射与动态多态的关系?
properties的工作原理,反映了Xml的原理规范;将键名和调用系统规范全部书写好,程序员将要调用的方法继承一个统一的父类系统,要调用那个系统就直接输入调用方法的类名;
案例】:
Xml做了(网络编程处理,服务器URL处理,端口处理,多线程处理、反射处理)



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值