1.Java类加载机制
1.1 概要
class文件有类加载器加载后,在JVM中形成一份描述Class结构的元信息对象,通过该元信息对象Class可以获知class文件的结构信息,如构造函数,属性和方法等。
虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的加载机制。
1.2工作机制
类加载器就是寻找类的字节码文件,并构造出类在JVM内部表示的对象组件,在JAVA中,类加载器把一个类装入JVM中,要经过以下几个步骤:
1.加载,查找和导入Class文件
2.连接,把类的二进制数据合并到JRE中。
a校验:检查载入Class文件数据的正确性。
b准备:给类的静态变量分配存储空间。
c解析:将符号引用转成直接引用。
3.初始化:对类的静态变量,静态代码块执行初始化操作。
1.3类初始化的时机
下列四种情况能够出发类的初始化
new出来的对象。
需要调用父类的方法
制定的主类,main()
java.lang.reflect反射的方法。
1.4反射概述
JAVA反射机制是对运行状态中,对指定的类,任意的方法或者字段进行操作,这种动态获取的信息以及动态调用对象方法的功能成为反射。
主要组成:
Class类
COnstructor类
Method方法
Field字段
instance实例
invoke执行
1.5创建数据,JavaBean
//用于数据的封装
/*
* JavaBean 规范:
* 1.必须提供私有字段。
* 2.必须提供getter和setter方法。
* 3.提供无参构造方法。
* 4.必须实现序列化接口
* java.io.Serializable
*
*
* */
public class JavaBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String className;
private String id;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public JavaBean(String className, String id) {
super();
this.className = className;
this.id = id;
}
public JavaBean() {
super();
// TODO Auto-generated constructor stub
}
}
1.6 获取Class的三种方法和应用场景
/*
* 三种方式获得Class对象
* 1.不同应用场景,需要不同的方式
* 方式:
* 1.通过字符串(全限定类名)获取。
* 2.通过JAVA类型获得。
* 3.通过实例对象(变量名)来获得。
*
* 应用:
* 方式一:从配置文件中来获得类的全限定类名,并通过反射进行所有操作。
* 方式二:确定构造方法、普通方法形参列表时,需要通过类型获得。
* public void init(String s,Integer i);
* 内存需要通过类型对应的Class进行标识。
* init(Stirng.class,Integer.class)
* 方式三:方法内部通过变量名获得
* */
@Test
public void demo01() throws ClassNotFoundException{
// 通过字符串获得
Class clazz = Class.forName("MyReflect.JavaBean");
System.out.println(clazz);
}
@Test
public void demo02() throws ClassNotFoundException{
// 通过JAVA类型获得
Class clazz = JavaBean.class;
System.out.println(clazz);
}
@Test
public void demo03() throws ClassNotFoundException{
// 通过实例对象获得
JavaBean javaBean = new JavaBean();
Class clazz = javaBean.getClass();
System.out.println(clazz);
}
}
1.7反射获取构造方法
1.7.1 反射获取无参构造。
public class Contructor {
@Test
public void demo01(){
// 1.触发无参构造方法。
JavaBean javaBean = new JavaBean();
}
@Test
public void demo02() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
// 1.通过反射获得无参构造方法,在获得实例对象。
/*
* 1.获得Class对象。
* 2.通过Class获得无参构造。
* 3.通过构造对象获得实例化对象。
* */
// 获得class
Class clazz = Class.forName("MyReflect.JavaBean");
// 获得构造对象,相当于JavaBean()
Constructor constructor = clazz.getConstructor();
// 获得实例,相当于:new JavaBean();
// newInstance() 创建制定实参的实例对象
Object object = constructor.newInstance();
}
@Test
public void demo03() throws Exception, SecurityException{
Class clazz = JavaBean.class;
Constructor constructor = clazz.getConstructor(String.class,String.class);
Object object = constructor.newInstance("0001","Tommy");
System.out.println(object);
}
@Test
// 无参构造快速获得实例对象
public void demo04() throws Exception, SecurityException{
// 1.获得Class
Class clazz = JavaBean.class;
// 2.通过CLazz直接获得对象
Object object = clazz.newInstance();
}
}
@Test
// 获取私有构造方法,创建实例对象
public void demo05() throws Exception, SecurityException{
// 1.获得Class对象
Class clazz = JavaBean.class;
// 2.获得制定形参的私有构造
/*
* clazz.getConstructor(parameterTypes); 获得指定对象的public构造方法。
*
* clazz.getDeclaredConstructor(parameterTypes);
* 获得指定对象的所有构造方法。
* */
Constructor constructor = clazz.getDeclaredConstructor(String.class,String.class);
// 3.通知JVM允许实例化私有构造
constructor.setAccessible(true);
// 4.创建实例,并设置实参
Object object = constructor.newInstance("kooo1","Tommy&hans");
System.out.println(object);
}
1.8反射私有方法
public class Method {
@Test
public void demo01(){
JavaBean javaBean = new JavaBean();
javaBean.setId("000001");
javaBean.setClassName("Tommys");
String idString = javaBean.getId();
System.out.println(idString);
}
@Test
public void demo02() throws Exception, Exception{
// 1.获得实例
Class clazz = JavaBean.class;
Object object = clazz.newInstance();
// 2.通过色图ID方法,设置参数
// 2.1获得方法,setID
java.lang.reflect.Method method = clazz.getMethod("setId", String.class);
// 2.2执行方法,javaBean.setID()
// 2.3确定实例对象,并执行确定方法,具体实际参数
method.invoke(object, "b00093");
System.out.println(object);
}
@Test
public void demo03() throws Exception, Exception{
// 1.获得实例
Class clazz = JavaBean.class;
Object object = clazz.newInstance();
// 2.通过色图ID方法,设置参数
// 2.1获得方法,setID
java.lang.reflect.Method method = clazz.getMethod("setId", String.class);
// 2.2执行方法,javaBean.setID()
// 2.3确定实例对象,并执行确定方法,具体实际参数
method.invoke(object, "b00093");
System.out.println(object);
// 3.通过getId方法,获得数据
java.lang.reflect.Method getMethod = clazz.getMethod("getId");
String idString = (String) getMethod.invoke(object);
System.out.println(idString);
}
}
1.9 反射main函数
@Test
public void testMian() throws Exception, Exception{
// 执行静态main方法
// 获得实例
// 执行方法,必须Class对象
// 1.获Class对象
Class clazz = JavaBean.class;
// 2.获得main方法
Method method = clazz.getMethod("main", String[].class);
System.out.println(method);
//3.执行main方法
// 3.1参数一:为实例对象,Static方法不需要
// 3.2参数二:main方法执行的实际参数。
// 可变参数在执行时,JVM内部将传递的实参数组打散,变成了多个参数。
// 可变参数这里,method.invoke(null, args);
// 等效method.invoke(null, "","","');
String[] args = {"abc","123","xxx"};
// method.invoke(null, args);错误的写法。
// 数组参数需要特殊处理
// 1.将String[] 转换成Object,可变参数将不处理数组。
method.invoke(null, (Object)args);
// 2.将提供二维数组,args将作为二维数组的第一个数。
method.invoke(null, new Object[] {args});
}
2.0反射字段
public class Reflect_field {
@Test
public void demo01() throws Exception, Exception{
// 1.获取实例对象
Class clazz = BeanDemo1.class;
Object object = clazz.newInstance();
// 2.给字段赋值
Field filed = clazz.getField("description");
filed.set(object, "descriptions");
// 3.获取字段值
String string = (String)filed.get(object);
System.out.println(string);
}
@Test
public void demo02() throws Exception, Exception{
// 私有字段
// 1.获得实例
Class clazz = BeanDemo1.class;
Object object = clazz.newInstance();
// 2.获得声明的字段
// ***clazz.getField(arg0) 公共字段
// ***clazz.getDeclaredField(arg0); 声明字段,私有
Field field = clazz.getDeclaredField("className");
// 3.设置运行访问的私有
field.setAccessible(true);
field.set(object, "i am className");
// 4.设置数据
String classname = (String)field.get(object);
// 5.获得数据
System.out.println(classname);
}
}