三.类加载
1.动态加载和静态加载
- 基本说明
- 反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载1.静态加载:编译时加载相关的类,如果没有则报错,依赖性太强2.动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,则不报错,降低了依赖性3.举例说明
- 类加载时机
- 1.当创建对象时(new))2.当子类被加载时3.调用类中的静态成员时4.通过反射Class.forName("com.test.Cat");
2.类加载流程图
3.类加载的五个阶段
3.1加载阶段
- JVM在该阶段的主要目的是将字节码从不同的数据源(可能是class文件、也可能是jar包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象
3.2连接阶段
3.2.1验证
1.目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。2.包括:文件格式验证(是否以魔数oxcafebabe开头)、元数据验证、字节码验证和符号引用验证3.可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间。
3.2.2准备
JVM会在该阶段对静态变量,分配内存并初始化(对应数据类型的默认初始值如0、0L、null、false等)。这些变量所使用的内存都将在方法区中进行分配
/**
* @author LeeZhi
* @version 1.0
* 我们说明一个类加载的连接阶段-准备
*/
public class ClassLoad02 {
public static void main(String[] args) {
}
}
class A{
//属性-成员变量-字段
//分析类加载的连接阶段-准备 属性是如何处理
//1. n1 是实例属性,不是静态变量,因此在准备阶段,是不会分配内存
//2. n2 是静态变量,分配内存n2是默认初始化0,而不是20
//3. n3 是static final是常量,他和静态变量不一样,因为一旦赋值就不变 n3 = 30
public int n1 =10;
public static int n2 = 20;
public static final int n3 = 30;
}
3.2.3解析
虚拟机将常量池内的符号引用替换为直接引用的过程。
3.3初始化
- Initialization(初始化)
- 1.到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行<clinit>()方法的过程。2.<clinit>()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并。3.虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,直到活动饯程执行<clinit>()方法完毕[debug源码]
/**
* @author LeeZhi
* @version 1.0
* 演示类加载-初始化阶段
*/
public class ClassLoad03 {
public static void main(String[] args) {
//1 加载B类,并生成B的class对象
//2. 链接num=0
//3. 初始化阶段
//依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句
/*
clinit(){
System.out.println("B静态代码块被执行");
//num=300:
num=100;
}
合并:num = 100
*/
//4. "B () 构造器被执行"
//new B();//类加载
System.out.println(B.num);//100 如果直接使用类的静态属性,也会导致类的加载
}
}
class B{
static {
System.out.println("B 静态代码块被执行");
num=300;
}
static int num = 100;
public B(){
System.out.println("B () 构造器被执行");
}
}
四.反射获取类的结构信息
1.第一组:java.lang.Class类
1.getName:获取全类名2.getSimpleName:获取简单类名3.getFields:获取所有publicf修饰的属性,包含本类以及父类的4.getDeclaredFields:获取本类中所有属性5.getMethods:获取所有public修饰的方法,包含本类以及父类的6.getDeclaredMethods:获取本类中所有方法7.getConstructors:获取所有public修饰的构造器,包含本类8.getDeclaredConstructors:获取本类中所有构造器9.getPackage:以Package]形式返回包信息10.getSuperClass:以Class形式返回父类信息11.getInterfaces:以Class[]形式返回接口信息12.getAnnotations:以Annotation[]形式返回注解信息
/**
* @author LeeZhi
* @version 1.0
* 演示如何通过反射获取类的结构信息
*/
public class ReflectionUtils {
public static void main(String[] args) {
}
//第一组方法API
@Test
public void api_01() throws ClassNotFoundException {
/**
* 1.getName:获取全类名
* 2.getSimpleName:获取简单类名
* 3.getFields:获取所有publicf修饰的属性,包含本类以及父类的
* 4.getDeclaredFields:获取本类中所有属性
* 5.getMethods:获取所有public修饰的方法,包含本类以及父类的
* 6.getDeclaredMethods:获取本类中所有方法
* 7.getConstructors:获取本类所有public修饰的构造器
* 8.getDeclaredConstructors:获取本类中所有构造器
* 9.getPackage:以Package]形式返回包信息
* 10.getSuperClass:以Class形式返回父类信息
* 11.getInterfaces:以Class[]形式返回接口信息
* 12.getAnnotations:以Annotation[]形式返回注解信息
*/
//1.得到Class对象
Class<?> personCls = Class.forName("com.gbx.reflection.Person");
System.out.println(personCls.getName());
System.out.println(personCls.getSimpleName());
Field[] fields = personCls.getFields();
for (Field field : fields) {
System.out.println("本类以及父类的属性:" + field.getName());
}
Field[] declaredFields = personCls.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("本类所有属性:"+declaredField.getName());
}
Method[] methods = personCls.getMethods();
for (Method method : methods) {
System.out.println("本类及父类的方法:" + method.getName());
}
Method[] declaredMethods = personCls.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("本类所有方法:" + declaredMethod.getName());
}
Constructor<?>[] constructors = personCls.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("本类的构造器:" + constructor.getName());
}
Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("本类中所有构造器:" + declaredConstructor.getName());
}
System.out.println(personCls.getPackage());
Class<?> superclass = personCls.getSuperclass();
System.out.println("父类的class对象"+superclass);
Class<?>[] interfaces = personCls.getInterfaces();
for (Class<?> anInterface : interfaces) {
System.out.println("接口信息:" + anInterface);
}
Annotation[] annotations = personCls.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println("注解信息:" + annotation);
}
}
}
class A{
public String hobby;
public void hi(){
}
public A() {
}
}
interface IA{
}
interface IB{
}
class Person extends A implements IA,IB{
//属性
public String name;
protected int age;
String job;
private double sal;
public Person() {
}
public Person(String name) {
this.name = name;
}
private Person(String name,int age){
}
//方法
public void m1(){
}
protected void m2(){
}
void m3(){
}
private void m4(){
}
}
2.第二组:java.lang.reflect.Field类
1.getModifiers:以int形式返回修饰符[说明:默认修饰符是0,public是1,private是2,protected是4,static是8,final是16] public(1)+static (8)=92.getType:以Class形式返回类型3.getName:返回属性名
@Test
public void api_02() throws ClassNotFoundException {
//1.得到Class对象
Class<?> personCls = Class.forName("com.gbx.reflection.Person");
Field[] declaredFields = personCls.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("本类所有属性:"+declaredField.getName()
+"该属性的修饰值:"+declaredField.getModifiers()
+"该属性的类型"+declaredField.getType());
}
}
3.第三组:java.lang.reflect.Method类
1.getModifiers:以int形式返回修饰符[说明:默认修饰符是0,public是1,private是2,protected是4,static是8,final是16]2.getReturnType:以Classj形式获取返回类型3.getName:返回方法名4.getParameterTypes:以Class[]返回参数类型数组
Method[] declaredMethods = personCls.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("本类所有方法:" + declaredMethod.getName()
+"该方法的访问修饰符"+declaredMethod.getModifiers()
+"该方法返回类型"+declaredMethod.getReturnType());
//输出当前这个方法的形参数组情况
Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println("该方法形参类型:" + parameterType);
}
}
4.第四组:java.lang.reflect.Constructor类
1.getModifiers:以int形式返回修饰符2.getName:返回构造器名(全类名)3.getParameterTypes:以Class[]返回参数类型数组
Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("本类中所有构造器:" + declaredConstructor.getName());
Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println("该构造器的形参类型:" + parameterType);
}
}
五.通过反射创建对象
1.方式一:调用类中的oublic修饰的无参构造器2.方式二:调用类中的指定构造器
3.Class类相关方法
- newInstance:调用类中的无参构造器,获取对应类的对象
- getConstructor(Class...clazz):根据参数列表,获取对应的public构造器对象
- getDecalaredConstructor((Class...clazz):根据参数列表,获取对应的所有构造器对象
4.Constructor类相关方法
- setAccessible:暴破
- newlnstance(Object...obj):调用构造器
5.1通过反射访问类中的成员
1.根据属性名获取Field对象
Field f=clazz对象.getDeclaredField(属性名):
2.暴破:f.setAccessible(true);//f是Field
3.访问
f.set(o,值);syso(f.get(o));
4.如果是静态属性,则set和get中的参数o,可以写成null
/**
* @author LeeZhi
* @version 1.0
*/
public class ReflectAccessProperty {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//1.得到Student类对应的Class对象
Class<?> stuClass = Class.forName("com.gbx.reflection.Student");
//2.创建对象
Object o = stuClass.newInstance();//o 得运行类型就是Student
//3.使用反射得到 age属性对象
Field age = stuClass.getField("age");
age.set(o,18);//通过反射设置属性
System.out.println(o);
//4.使用反射操作name属性
Field name = stuClass.getDeclaredField("name");
//对name进行暴破
name.setAccessible(true);
name.set(o,"小黄");//
name.set(null,"子");//因为name是static属性,因此o也可以写出nulL
System.out.println(o);
}
}
class Student{
public int age;
private static String name;
public Student() {
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
'}';
}
1.根据方法名和参数列表获取Method方法对象:Method m=clazz.getMethod(方法名,XX.class);
2.获取对象:Object o=clazz.newInstance();
3.暴破:m.setAccessible(true):
4.访问:Object returnValue=m.invoke(o,实参列表)://o就是对象
5.注意:如果是静态方法,则invoke的参数o,可以写成null!
public class ReflectAccessMethod {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//1.得到Boss类对应的Class对象
Class<?> bossCls = Class.forName("com.gbx.reflection.Boss");
//2.创建对象
Object o = bossCls.newInstance();
//3.调用public的hi方法
//Method hi = bossCls.getMethod("hi");
//3.1得到hi方法对象
Method hi1 = bossCls.getDeclaredMethod("hi",String.class);
//3.2调用
hi1.invoke(o,"Lee");
//4.调用 private static 方法
//4.1得到 say 方法对象
Method say = bossCls.getDeclaredMethod("say", int.class, String.class, char.class);
say.setAccessible(true);
System.out.println(say.invoke(100, "小黄", "女"));
//4.3因为say方法是static的,还可以这样调用,可以传入null
System.out.println(say.invoke(null,200,"李四",'女'));
//5.在反射中,如果方法有返回值,统一返回0bjct,但是他运行类型和方法定义的返回类型一致
Object reVal=say.invoke(null,300,"王五",'男');
System.out.println("reVal的运行类型="+reVal.getClass());//String
}
}
class Boss{
public int age;
private static String name;
private static String say(int n,String s,char c){
return n +" "+s +" "+c;
}
public void hi(String s){
System.out.println("hi" + s);
}
}