获取对象的方法
只要元素类型和维度一样返回的就是同一个class对象
类加载的内存分析
类加载主要经历三个阶段
- 加载:把.class文件加载到内存中,生成一个Class对象。
- 链接:先检查代码是否符合规范确保没有安全方面的问题,然后开始为静态变量开辟内存空间,这些空间都在方法区中进行分配,把常量池中的符号指向引用地址。
- 初始化:clinit方法把所有静态变量的赋值操作和静态代码合在一起执行一遍完成初始化。
什么时候会发生类的初始化
主动引用:会发生类的初始化
虚拟机启动时会先加载main方法所在的类
new一个类对象会发生类的初始化
调用类的静态成员和静态方法(final不算在内)
反射
当初始化一个类时,会先初始化他的父类。
被动引用:不会发生类的初始化
通过子类引用父类的静态变量不会导致子类初始化
定义这个类的数组不会触发该类的初始化
引用常量不会触发该类的初始化(常量在链接阶段就存入常量池了)
类加载器
类缓存:一个类一旦被加载,会缓存一段时间。垃圾回收机制可以回收这些Class对象
引导类加载器:用C++编写的,是JVM自带的加载器。负责Java平台核心库(rt.jar),该加载器无法直接获取。
扩展类加载器:负责加载扩展库jre/lib/ext目录或指定目录下的jar包。
系统类加载器:最常用的加载器,我们自己写的类就是通过这个加载器加载的。
动态创建对象执行方法
import pojo.User;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test02 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
// 获取Class对象
Class c1 = Class.forName("pojo.User");
// 通过Class对象的newInstance()方法构造一个对象
// 其实质是调用了这个对象的无参构造
// 如果这个对象没有无参构造那么这个方法会报错
User user1 = (User)c1.newInstance();
System.out.println(user1);
// 如果这个对象没有无参构造
// 可以使用反射获取他的有参构造器
Constructor constructor = c1.getDeclaredConstructor(String.class, String.class);
User zjq = (User)constructor.newInstance( "zjq", "123");
System.out.println(zjq);
// 也可以通过Class对象获得他的方法 如果该方法是私有的,我们可以通过.setAccessible() 方法把他设置为true
Method setName = c1.getDeclaredMethod("setName", String.class);
setName.setAccessible(true);
// 原本私有的方法下载可以使用了
setName.invoke(zjq, "梁朝伟");
System.out.println(zjq);
// 成功获得一张改名卡
// 小张已经不是小张了
}
}
性能分析对比
import pojo.User;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//测试三种方式执行代码的效率
public class Test03 {
//普通方法
public static void test1(){
User user = new User();
long start = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
user.getName();
}
long end = System.currentTimeMillis();
System.out.println(end-start);
}
// 调用反射执行方法
public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c = user.getClass();
Method getName = c.getDeclaredMethod("getName", null);
long start = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
getName.invoke(user,null);
}
long end = System.currentTimeMillis();
System.out.println(end-start);
}
// 关闭检测权限执行方法
public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c = user.getClass();
Method getName = c.getDeclaredMethod("getName", null);
getName.setAccessible(true);
long start = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
getName.invoke(user,null);
}
long end = System.currentTimeMillis();
System.out.println(end-start);
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
test1();
test2();
test3();
}
}
测试结果:
结论:关闭了权限检测之后执行方法会比不关更快,普通方式调用是最快的。