1、类的加载
加载 :
将class文件读入内存,并创建一个Class对象
任何类被使用时都会建立Class对象
连接 :
验证 是否有正确是内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值
解析 将类的二进制数据的符号引用替换为初识化值
初始化: 开启堆栈空间 , 默认初始化,显示初始化等。
2、类加载器
负责将 .class文件 加载到内存中,并生成对应的Class对象
组成:
Bootstrap ClassLoader 根类加载器(引导类加载器)
负责Java核心类的加载 eg:System,String等
在JDK中JRE的lib目录下rt.jar文件中
Extension ClassLoader 扩展类加载器
负责JRE的扩展目录中jar包的加载。
在JDK中JRE的lib目录下ext目录
Sysetm ClassLoader 系统类加载器
负责在JVM启动时加载来自java命令的class文件
classpath环境变量所指定的jar包和类路径
3、反射
反射理解:
通过Class文件对象,去使用该文件的 成员变量 构造方法 成员方法。
反射机制:
1)把java文件保存到本地硬盘 .java
2)编译.java 成 .class文件
3)使用jvm , 把class文件通过类加载 加载到到内存中
4)class文件在内存中用 class类 来表示
属性类 : Field
构造方法类 : Constructor
方法类 : Method
获取class字节码文件对象的方式
A: Object类的getClass()方法。
Person p = new Person();
Class c = p.getClass(); 对象名.getClass(); c拿到p的class文件
B:数据类型的静态属性class。
数据类型.class();
C:Class类中的静态方法
Class.forName(); 传参为类的全路径(带报名的路径)
使用哪个方式呢:
开发中: 第三种
原因:第三种得到的是一个字符串,而不是具体的类名。
可以把字符串配置到配置文件中。
自己用:第二种方便。
通过反射获取构造方法并使用。
方法:
获得所有公共(public)构造方法:
//Constructor[] getConstructors();
获得所有构造方法:
//Constructor[] getDeclaredCsonstructors();
获得单个构造方法:
Constructor<T> getConstructor(Class<?>... parameterType)
参数表示的是: 你要获得的构造方法的参数,
及数据类型的class字节码文件对象
Class c = Class.forName("person.Person");
Constructor con = c.getConstructor();
Object obj = con.newInstance();
注:上面三条语句相当于 Person p = new Person();
--public Person(String name, int age, String address)
// 获得该路径下的class字节码文件对象
Class c = Class.forName("person.Person");
Constructor con = c.getConstructor(String.class, int.class, String.class);
Object obj = con.newInstance("李",11,"陕西")
注:上面三条语句相当于 Person p = new Person("李",11,"陕西");
--private Person(String name)
// 获得该路径下的class字节码文件对象
Class c = Class.forName("person.Person");
Constructor con = c.getDeclaredConstructor(String.class);
con.setAccessible(true);
Object obj = con.newInstance("李");
注:上面三条语句相当于 Person p = new Person("李");
通过反射获取成员变量并使用
方法: set(Object obj, object value)
将指定对象(obj)上此 Field对象表示的字段设置为指定的新值
Class c = Class.forName("person.Person");
for (Field field : fields) {
System.out.println(field);
Class c = Class.forName("person.Person");
Constructor con = c.getConstructor();
Object obj = con.newInstance();
Field addressfields = c.getField("address");
addressfields.set(obj, "西安");
注:如果是私有对象,则使用 .getDeclaredField();
并 暴力访问 -- .setAccessible(true);
通过反射获取成员方法并使用
获取所有方法:
getMethods
getDeclaredMethods
获取单个方法:
getMethod
getDeclaredMethod
暴力访问:
method.setAccessible(true);
方法: invoke(Object obj, Object...args)
参数1,表示对象是谁
参数2,调用该方法的实际传参
返回值是object
Class c = Class.forName("person.Person");
Constructor con = c.getConstructor();
Object obj = con.newInstance();
Method m1 = c.getMethod("show");
m1.invoke(obj);
Class c = Class.forName("person.Person");
Constructor con = c.getConstructor();
Object obj = con.newInstance();
Method m1 = c.getMethod("show2", String.class);
m1.invoke(obj, "带参");
Class c = Class.forName("person.Person");
Constructor con = c.getConstructor();
Object obj = con.newInstance();
Method m1 = c.getMethod("getString", String.class,int.class);
Object objString = m1.invoke(obj, "hello",100);
System.out.println(objString);
4、反射案例
A:通过反射运行配置文件的内容
public class Case1 {
public static void main(String[] args) throws Exception {
Properties prop = new Properties();
FileReader fr = new FileReader("class.txt");
prop.load(fr);
fr.close();
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
Class c = Class.forName(className);
Constructor con = c.getConstructor();
Object obj = con.newInstance();
Method m = c.getMethod(methodName);
m.invoke(obj);
}
}
class.txt 文件内容
className=??? 填写文件带包名的路径
methodName=??? 方法名
B:通过反射越过泛型检查
//原理:用class字节码操作 利用泛型只在编译期出现的现象
//创建<Integer> 型集合
ArrayList<Integer> array = new ArrayList<Integer>();
//得到array的class文件对象
Class c = array.getClass();
Method m = c.getMethod("add", Object.class);
//调用array的add方法 传进字符串。
m.invoke(array, "hello");
System.out.println(array);
C:通过反射给任意的一个对象的任意的属性赋值为指定的值
public class Case3_Tool {
public void setProperty(Object obj, String propertyName, Object value) throws Exception {
Class c = obj.getClass();
Field field = c.getDeclaredField(propertyName);
field.setAccessible(true);
field.set(obj,value);
}
}
public class TestCase3 {
public static void main(String[] args) throws Exception {
Person p = new Person();
Case3_Tool t = new Case3_Tool();
t.setProperty(p, "name", "李");
t.setProperty(p, "age", 10);
System.out.println(p);
}
}
class Person{
private String name;
public int age;
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}