Java 类加载器
类加载器
方法区:类:Demo.class 静态区:静态方法/main方法
类加载器 (静态之前)自动在堆中创建 Demo字节码文件对象
类的初始化
加载 class文件读入内存,并为之创建一个Class对象
连接
验证 内部结构,与其他类的协调
准备 静态成员分配内存,设置初始值
解析 符号引用替换为直接引用
初始化 就是我们以前讲过的初始化步骤
类初始化时机
1. 创建类的实例 new cls()
2. 类的静态变量,或者为静态变量赋值 cls.a
3. 类的静态方法 cls.method()
4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
5. 初始化某个类的子类 new sun()
6. 直接使用java.exe命令来运行某个主类 运行 main
类加载器的组成
Bootstrap ClassLoader 根类加载器 Java核心类的加载
如System,String等。在JDK中JRE的lib目录下rt.jar文件中
Extension ClassLoader 扩展类加载器 负责JRE的扩展目录中jar包的加载。
在JDK中JRE的lib目录下ext目录
System ClassLoader 系统类加载器 加载包
负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径。
反射(通过字节码文件对象,获取其所有属性方法)
反射需要用到的成员及方法:
Class类
Constructor 构造
Method 方法
Filed 字段
instance 实例
invoke 执行
reflect:
//Class类:描述文件对象
//Constructor类:描述构造方法的类
//Method类:描述方法的类
//Field类:描述变量的类
public static void main(String[] args) throws Exception{
//获取文件字节码对象(只有一个) 类进入内存
//Person p=new Person(); Class c=p.getClass();//1.通过对象获取
//Class c1=Person.class;//通过类名获取
Class c2=Class.forName("com.shangwu.Person");//Class.静态(包名.类名)
System.out.println(c);//class com.shangwu.Person
//获取构造方法数组 Constructor<T>
//Constructor[] cons=c.getConstructors(); //所有公共构造方法数组
Constructor[] cons = c.getDeclaredConstructors();//所有构造方法数组
for(Constructor con:cons){ System.out.println(con); }//遍历
//获取构造方法 Constructor<T>
//Constructor con=c.getConstructor();//公共构造方法对象 空参
//Constructor con=c.getConstructor(String.class,int.class); // 有参
Constructor con=c.getDeclaredConstructor(String.class);//私有有参构造
con.setAccessible(true);//暴力反射时 取消java语言的访问检查
//通过获取的构造方法 创建对象
//Object obj=con.newInstance();//空参构造 Person对象 多态
//Object obj=con.newInstance("张三",18);//有参构造 Person对象
Object obj=con.newInstance("李四");//私有有参构造 Person对象
//Object obj2=c.newInstance();//类文件对象 调用公共空参构造 对象
Person p2=(Person)obj; //向下转型
p2.eat();
//获取成员变量数组
//Field[] fields = c.getFields(); //获取所有公共成员变量数组
Field[] fields=c.getDeclaredFields();//获取所有成员变量数组
for(Field f:fields){ System.out.println(f); }
//获取成员变量
Field nameField=c.getField("name");//获取类中的公共成员变量name
//Field ageField = c.getDeclaredField("age"); //私有/公共成员变量age
//ageField.setAccessible(true); //取消 Java 语言访问检查
//对象变量赋值 取值
nameField.set(obj,"张三"); //指定对象 对应变量 赋值
String name=(String) nameField.get(obj);//返回指定对象 对应变量的值
//获取成员方法数组
Method[] methods = c.getMethods();//获取所有公共成员方法
//Method[] methods=c.getDeclaredMethods();//获取所有成员方法
for(Method m:methods){ System.out.println(m); }
//获取的公共有参方法并调用
Method mSetAge=c.getDeclaredMethod("setAge",int.class);//方法名参数
//mSetAge.setAccessible(true); //取消 Java 语言访问检查
Method mGetAge=c.getMethod("getAge");//获取公共 方法名 无参数
Object result =mSetAge.invoke(obj, 18); //指定对象 调用对应方法
int age=(int)mGetAge.invoke(obj); //对象 调用方法 返回值 转型
Method mMain=c.getMethod("main", String[].class); //获取main函数
mMain.invoke(null,(Object)args); //调用main函数 传参 数组转对象
} //防止传参时 数组自动拆分
反射配置:
public class Student { public void study(){ System.out.println("学生学习"); } } config.properties文件(File)内容: #ClassName=com.xiawu.Worker #MethodName=work ClassName=com.xiawu.Student MethodName=study public class FanshePeizhi { //Person Student Worker public static void main(String[] args) throws Exception { //1.准备 配置文件 键值对 config.properties //2.读取键值对 FileReader fr=new FileReader("config.properties"); Properties pro=new Properties(); pro.load(fr); fr.close(); //从集合中获取类名 和 方法名 String className=pro.getProperty("ClassName"); String methodName=pro.getProperty("MethodName"); //System.out.println(methodName); //反射获取指定类的class文件对象 Class c=Class.forName(className); //类文件对象 Object obj=c.newInstance(); //创建对象 Method method=c.getMethod(methodName); //获取指定方法 method.invoke(obj); //运行制定方法 } }
泛型擦除:
//泛型擦除(通过反射向有泛型约束的集合中,添加任意类型的元素) public class FanxingCachu { public static void main(String[] args) throws Exception { ArrayList<Integer> arr=new ArrayList<Integer>(); arr.add(1); //arr.add("你好"); Class c=arr.getClass();//ArrayList类文件对象 Method method=c.getMethod("add", Object.class);//获得add方法 method.invoke(arr, "你好"); //调用方法(对象,方法参数) System.out.println(arr); } }