反射机制的理解:
1.反射机制允许程序在执行期借助于RefelectionAPI取得任何类的内部信息(比如成员变量,构造器,成员方法)并能操作对象的属性,方法,反射在设计模式和框架底层中都会用到
2.加载玩类之后,在堆中会产生一个class类型的对象(一个类只有一个class对象,这个对象包含了类的完整的结构信息,通过这个对象得到类的结构,这个对象就像一面镜子,透过这个镜子看到类的结构,所以形象的称之为反射。
反射的优点:
可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就是去底层支撑。
java的反射机制的应用
1.在运行时判断任何一个对象所属的类
2.在运行时构造任意一个类的 对象
3.在运行时得到任意一个类的所具有的成员变量和方法
4.在运行时调用任意一个对象的成员变量和方法
5.生成动态代理
反射相关的主要类
1.java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
2.java.lang.reflect.Method:代表类的方法,Method表示某个类的方法
3.java.lang.reflect.Filed:代表类的成员变量,Field对象表示某些类的长远变量
4.java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器
通过反射获取类的结构信息
java.lang.Class类
1.getName:获取全类名
2.getSimpleName:获取简单类名
3.getFields:获取所有public修饰的属性,包含本类以及父类的
4.getDeclaredFields:获取本类中的中的全部属性
5.getMethods:获取所有public修饰的方法,包含本类以及父类的
6.getDeclaredMethods:获取本类中的所有方法
7.getConstructors:获取本类中public修饰的的所有构造器
8.getDeclaredConstructors:获取本类中的全部构造器
9.getPackage:以package的形式返回包信息
10.getSuperClass:以class形式返回父类的信息
11.getInterfaces:以class【】形式返回接口信息
12.getAnnotations:以Annotation[]形式返回注解信息
Java.reflect.Field --- 类都是成员变量的一些方法
1.getModifiers:以int 形式返回修饰符
默认修饰符是0,public 是1,private是2,protected是4,static是8,final是16
2.getType:以Class类型返回
3.getName:返回属性名
Java.lang.reflect.Method类
1.getModifiers:以int形式返回修饰符
默认修饰符是0,public 是1,private是2,protected 是 4,static是8,fina是16
2.getReturnType :是以Class形式获取返回值
3.getName:返回方法名
4.getParameterTypes:是以Class【】返回参数类型数组
java.lang.reflect.Constructor类
1.getModifiers:以int 形式返回修饰符
2.getName:返回构造器名(全类名)
3.getParameterTypes:以Class[]返回参数类型数组
.
类加载
反射机制是Java实现动态语言的关键,也就是通过反射是先类的动态加载
静态加载:编译时加载相关的类,如果没有该类则报错,依赖性太强了
动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,也不报错了。降低了依赖性。
加载阶段: JVM在该阶段的主要目的是将字节码从不同的数据源(可能是class文件,也可能是jar包,身子网络)转为为二进制字节流加载到内存中的方法区中,并生成一个代表该类的Java.lang.Class对象
连接阶段--验证:1.目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并不会为好虚拟机自身的安全。
2.包括:文件格式验证(是否以魔数开头oxcafebabe开头),元数据验证,字节码验证和符号引用验证
3.可以考虑使用Xverify:none参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间。
连接阶段--准备
JVM会在该阶段对静态变量分配内存并默认初始化(对应数据类型的默认值如0,0L,null,false等)。这些变量所使用的内存都将在方法区中进行分配,例如static int a=100;
即使是静态变量在这个阶段还是初始化为0,finial static int a=100;这里的初始化为100;
连接阶段--解析
虚拟机将常量池内的符号引用替换为直接引用的过程
初始化阶段
1.到初始化阶段,才真正开始执行类中定义的java程序代码,此阶段是执行<clint>()方法的过程
2.<clint>()方法是有编译器按语句在源文件中出现的顺序依次自动收集类中的所有的静态变量的赋值动作和静态代码块中的语句,并进行合作
3虚拟机会保证一个类的<clint>()方法在多线程环境中被正确的加锁,同步,如果多个线程同时去初始化一个类,那么只有一个线程回去执行这个类<clint>()方法,其他现在需要阻塞等待,知道活到线程执行<clint>()方法完毕。
测试样例:(进一步理解反射机制)
在同一包下建立一个名为re.properties的文件夹,里面写入
classfullpath=com.student2.cat
method=eat
package com.student2;
import java.io.*;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DateFormat.Field;
import java.util.Properties;
public class test2 {
//在反射中,万物皆对象
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
//通过外部文件配置在不修改源码的情况下来控制程序,也符合设计模式的opc原则(开闭原则:在不修改源码的情况下扩容功能)
// cat c=new cat();
// c.cry();
Properties pro=new Properties ();
FileReader fr=new FileReader("src\\re.properties");
pro.load(fr);
//get方法返回的是object类型的 所以要转化为string
String classfullpath= pro.getProperty("classfullpath").toString();
String method= pro.getProperty("method").toString();
// fr.close();
// System.out.print(pro);
//cat c= new com.student2.cat();
// c.cry();
//找到classfullpath路径下的所对应的类
Class cls=Class.forName(classfullpath);
@SuppressWarnings("deprecation")
//并将获得的类实例化一个对象
Object ob= cls.newInstance();
System.out.println("o运行的类型为:"+ob.getClass());
//反射如何输出成员变量:成员变量.get(实例化对象);且只能反射公有的成员变量
java.lang.reflect.Field fil=cls.getField("name");
System.out.println(fil.get(ob));
Method me= cls.getMethod(method,null);
System.out.println("........................");
me.invoke(ob);
fr.close();
}
}
package com.student2;
public class cat {
public String name="旺财";
public void cry() {
System.out.print(name+"哭了");
}
public void eat() {
System.out.print(name+"需要吃饭了");
}
}
1.前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法 forName()获取
多用于配置文件,读取类全路径,加载类
String classfullpath="com.student2.cat";
Class cls=Class.forName(classfullpath);
2.前提:若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能最高实例:Class cls=Cat.class
多适用于参数传递,比如通过反射得到对应的构造器对象
3.前提:已有实例化对象 对象。getclass();
cat c=new cat();
Class cls=c.getclass();