动态和静态加载
类加载:
反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。
1.静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
2.动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,则不报错,降低了依赖性
类加载时间:
1.当创建对象时(静态加载)
2.当子类被加载时,父类也加载(静态加载)
3.调用类中的静态成员时(静态加载)
4.通过反射(动态加载)
类加载流程图
1.加载Loading阶段:将类的class文件读入内存,并为之创建一个java.lang.Class对象,此过程由类加载器完成
2.在连接Linking阶段:将类的二进制数据合并到JRE中
3.初始化阶段:JVM负责对类进行初始化,该处主要是指静态成员
类加载五个阶段
加载阶段:
JVM在该阶段的主要目的是将字节码从不同的数据源转化成二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象
连接阶段-验证:
1.目的为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
2.包括:文件格式验证(是否是魔数oxcafebabe开头)、元数据验证、字节码验证和符号引用验证
3.可以考虑使用 -Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间
连接阶段-准备:
JVM会在该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始化值、如0,0L,null,false)
连接阶段-解析:
虚拟机将常量池内的符号引用替换为直接引用的过程
初始化阶段:
1.到初始化阶段,才真正开始执行类中定义的java程序代码,此阶段是执行<clinit>()方法的过程
2.<clinit>()方法是由编译器按语句在源文件中出现的顺序、依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并
3.虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类<clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕
4.正因为有这个机制, 才能保证某个类在内存中,只有一份Class对象
获取类结构信息
第一组:java.lang.Class类
第二组:java.lang.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,final:16)
2.getReturnType:以Class形式获取返回类型
3.getName:返回方法名
4.getParameterTypes:以Class[] 返回参数类型数组
第四组:java.lang.reflect.Constructor类
1.getModifiers:以int形式返回修饰符
2.getName:返回构造器名(全类名)
3.getParameterTypes:以Class[] 返回参数类型数组
package com.jh.class_;
//演示如何通过反射获取类的结构信息
import org.junit.jupiter.api.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectionUtils {
public static void main(String[] args) {
}
@Test
public void api01() throws ClassNotFoundException {
String path = "com.jh.class_.Mango";
//得到class对象
Class<?> class01 = Class.forName(path);
//1.getName:获取全类名
System.out.println(class01.getName());//com.jh.class_.Mango
//2.getSimpleName:获取简单类名
System.out.println(class01.getSimpleName());//Mango
//3.getFields:获取所有public修饰的属性,包含本来以及父类
Field[] fields = class01.getFields();
for (Field field : fields) {
System.out.println("本类及父类的public属性:" + field.getName());
}
/* 本类及父类的属性:name
本类及父类的属性:shuiguo*/
//4.getDeclaredFields:获取本类中所有属性
Field[] declaredFields = class01.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("本类中所有属性:" + declaredField.getName());
}
/* 本类中所有属性:name
本类中所有属性:age
本类中所有属性:address
本类中所有属性:peach*/
//5.getMethods:获取所有public修饰的方法,包括本类以及父类
Method[] methods = class01.getMethods();
for (Method method : methods) {
System.out.println("本类及父类的public修饰的方法:"+method.getName());
}
/*本类及父类的public修饰的方法:m1
本类及父类的public修饰的方法:hi
本类及父类的public修饰的方法:wait
本类及父类的public修饰的方法:wait
本类及父类的public修饰的方法:wait
本类及父类的public修饰的方法:equals
本类及父类的public修饰的方法:toString
本类及父类的public修饰的方法:hashCode
本类及父类的public修饰的方法:getClass
本类及父类的public修饰的方法:notify
本类及父类的public修饰的方法:notifyAll*/
//6.getDeclaredMethods:获取本类中所有方法
Method[] declaredMethods = class01.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("本类中所有的方法:" + declaredMethod.getName());
}
/*本类中所有的方法:m1
本类中所有的方法:m2
本类中所有的方法:m4
本类中所有的方法:m3
本类中所有的方法:hi*/
//7.getConstructors:获取所有public修饰的构造器,包含本类
Constructor<?>[] constructors = class01.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("本类中public修饰的构造器:" + constructor.getName());
}
/*本类及其父类中public修饰的构造器:com.jh.class_.Mango
本类及其父类中public修饰的构造器:com.jh.class_.Mango*/
//8.getDeclaredConstructors:获取本类中所有构造器
Constructor<?>[] declaredConstructors = class01.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("获取本类中所有构造器:" + declaredConstructor.getName());
}
/*获取本类中所有构造器:com.jh.class_.Mango
获取本类中所有构造器:com.jh.class_.Mango
获取本类中所有构造器:com.jh.class_.Mango*/
//9.getPackage:以包名形式返回,包信息
System.out.println("以包名形式返回包信息:" + class01.getPackage());
/*以包名形式返回包信息:package com.jh.class_*/
//10.getSuperclass:以Class形式返回父类信息
Class<?> superclass = class01.getSuperclass();
System.out.println(superclass);
/*class com.jh.class_.SuiGuo*/
//11.getInterfaces:以Class形式返回接口信息
Class<?>[] interfaces = class01.getInterfaces();
for (Class<?> anInterface : interfaces) {
System.out.println("以Class形式返回接口信息:" + anInterface.getName());
}
/*以Class形式返回接口信息:com.jh.class_.IA
以Class形式返回接口信息:com.jh.class_.IB*/
//12.getAnnotations:以Annotations形式返回注解信息
Annotation[] annotations = class01.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println("注解信息:" + annotation);
}
/*注解信息:@java.lang.Deprecated()*/
}
}
反射暴破创建实例
1.方式一:调用类中的public修饰的无参构造器
1.方式二:调用类中的指定构造器
3.Class类相关方法:
(1.newInstance:调用类中的无参构造器,获取对应类的对象
2.getConstructor(Class...):
3.getDecalaredConstructor(Class...):根据参数列表,获取对应的所有构造器对象)
4.Constructor:类相关方法
setAccessible:暴破
newInstance(Object...):调用构造器
package com.jh.class_;
//演示通过反射机制创建实例
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@SuppressWarnings("all")
public class ReflecCreateInstance {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//1.先获取User类的Class对象
String path = "com.jh.class_.User";
Class<?> userclass = Class.forName(path);
//2.通过public的无参构造器创建实例\
Object o = userclass.newInstance();
System.out.println(o);//User{age=23, name='tom'}
//3.通过public的有参构造器创建实例
//得到对应构造器
Constructor<?> constructor = userclass.getConstructor(String.class);
//创建实例,传入实参
Object jim = constructor.newInstance("jim");
System.out.println(jim);//User{age=23, name='tom'}
//4.通过非public的有参构造器创建实例
//得到对应的构造器
Constructor<?> declaredConstructor =
userclass.getDeclaredConstructor(int.class, String.class);
//暴破:使用反射可以访问private构造器
declaredConstructor.setAccessible(true);
//创建实例
Object jason = declaredConstructor.newInstance(24, "jason");
System.out.println(jason);//User{age=24, name='jason'}
}
}
class User{
private int age = 23;
private String name = "tom";
//无参构造器
public User(){
}
//public的公有有参构造器
public User(String name){
}
//有参构造器
private User(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
反射暴破操作属性
1.根据属性名获取Filed对象
Filed filed = class对象.getDeclaredFiled(属性名);
2.暴破:filed.setAccessible(true);
3.访问
filed.set(o,值);//o是对象
4.注意:如果是静态属性,则set和get中的参数o,可以写成null
package com.jh.class_;
//演示反射操作属性
import java.lang.reflect.Field;
@SuppressWarnings("all")
public class ReflecAccessProperty {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//1.得到Student类对应的Class对象
String path = "com.jh.class_.Student";
Class<?> class01 = Class.forName(path);
//2.创建对象
Object o = class01.newInstance();
//3.使用反射得到age属性对象
Field age = class01.getField("age");
age.set(o,24);
System.out.println(o);//Student{age=24 null}
//4.使用反射操作name
Field name = class01.getDeclaredField("name");
//对name进行暴破
name.setAccessible(true);
name.set(o,"tom");//因为name是static属性,因此o也可以写成null
System.out.println(o);//Student{age=24 tom}
}
}
class Student{
public int age;
private static String name;
public Student(){
}
@Override
public String toString() {
return "Student{" +
"age=" + age + "\t"+ name +
'}';
}
}
反射暴破操作方法
1.根据方法和参数列表获取Method方法对象,Method m = class01.getDeclaredMethod(方法名,xx.class);//得到本类的所有方法
2.获取对象:Object o = class01.newInstance();
3.暴破:m.setAccessible(true);
4.访问:Object returnValue = m.invoke(o,实参列表);//o是对象
5.注意:如果是静态方法,则invoke的参数o,可以写成null
package com.jh.class_;
//演示通过反射调用方法
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@SuppressWarnings("all")
public class ReflecAccessMethod {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//1.得到Boss类对应的Class对象
String path = "com.jh.class_.Boss";
Class<?> class01 = Class.forName(path);
//2.创建对象
Object o = class01.newInstance();
//3.调用public方法
//得到hi对象
Method hi = class01.getMethod("hi",String.class);
Object jason = hi.invoke(o, "jason");
//hi=jason
//4.调用private static方法
//得到方法对象
Method say =
class01.getDeclaredMethod("say", int.class, String.class, char.class);
//进行暴破
say.setAccessible(true);
//调用
Object message = say.invoke(o, 24, "tom", '男');
System.out.println(message);//24 tom 男
//5.在反射中,如果方法有返回值,统一返回Object ,但是运行类型和方法定义的返回类型一致
}
}
class Boss{
public int age;
private String name;
public Boss(){
}
public void hi(String s){
System.out.println("hi=" + s);
}
private static String say(int n,String s,char c){
return n + " " + s + " " + c;
}
}