文章目录
I know, i know
地球另一端有你陪我
一、类加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化
加载
就是指将class文件读入内存,并为之创建一个Class对象
任何类被使用时系统都会建立一个Class对象
连接
验证 是否有正确的内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值
解析
将类的二进制数据中的符号引用替换为直接引用
初始化
静态初始化 — 父类初始化 — 子类初始化
静态代码块 — 构造代码块 — 构造函数
父类 — 子类
二、反射
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
1、获取 class对象
/*
反射:就是通过class文件对象去使用该文件中的成员变量,
构造方法,成员方法
我们之前写过很多的类java文件,再去实例化的时候,直接new就可以了
Person person = new Person();
person.eat();
但是,现在并没有现成的java文件,只拿到一个class文件怎么办呢?
换句话说,就算你是用java文件去创建对象,底层依旧是需要一个class文件
也就是说想要创建对象,就必须要得到一个class文件,
也就是获取该class的文件对象
class类:
成员变量: Fields
构造方法: Constructor
成员方法: Method
1、怎么获取到class文件对象呢?
1)通过Object中的getClass()方法获取,返回该Object的运行时类
2)通过类名获取静态属性class
3)Class类中的静态方法
public static 类<?> forName(String className)
返回与给定字符串名称的类或接口相关联的类对象。
*/
public class Reflect1 {
public static void main(String[] args) throws Exception{
Pokemon p1 = new Pokemon("piplup");
Pokemon p2 = new Pokemon("ralts");
Class<? extends Pokemon> c1 = p1.getClass();
Class<? extends Pokemon> c2 = p2.getClass();
// 方式1:
// 通过Object中的getClass()方法获取
System.out.println(c1==c2);
System.out.println("-----------------------");
// 方式2:
// 通过类名获取静态属性class
Class<Pokemon> c3 = Pokemon.class;
System.out.println(c3==c1);
System.out.println("-----------------------");
// 方式3:
// Class类中的静态方法(开发中最常用的方式)
// public static 类<?> forName(String className)
// 返回与给定字符串名称的类或接口相关联的类对象。
// 注意:这里需要写该类再本项目中完整路径,不加 src
Class<?> c4 = Class.forName(
"javase.day25.Reflect.Pokemon");
System.out.println(c4==c3);
}
}
2、获取构造方法 & 对象
public class Reflect2 {
public static void main(String[] args) throws Exception{
// 获取class文件对象
Class<?> c = Class.forName("javase.day25.Reflect.Pokemon");
// public Constructor<?>[] getConstructors()
// 获取该类中所有 public 的构造方法
Constructor<?>[] sc = c.getConstructors();
for (Constructor<?> constructor : sc) {
System.out.println(constructor);
}
System.out.println("-----------------------------");
// public Constructor<?>[] getDeclaredConstructors()
// 获取所有的构造方法
// 包括public,protect,默认(包)访问和 private 字段
Constructor<?>[] dcs = c.getDeclaredConstructors();
for (Constructor<?> constructor : dcs) {
System.out.println(constructor);
}
System.out.println("----------------------------");
// public Constructor<T> getConstructor(
// Class<?>... parameterTypes)
// 获取单个 public 构造方法
Constructor<?> con = c.getConstructor(String.class, int.class);
System.out.println(con);
System.out.println("---------------------------");
// public Constructor<T> getDeclaredConstructor(
// 类<?>...parameterTypes)
// 获取任意构造方法
// 包括 public,protect,默认(包)访问和 private 字段
Constructor<?> dc = c.getDeclaredConstructor();
System.out.println(dc);
System.out.println("--------------------------");
// 创建对象
// public T newInstance(Object... initargs)
// 使用指定参数和构造方法创建对象
Object o1 = con.newInstance("piplup",5);
System.out.println(o1);
System.out.println("--------------------------");
// 在通过使用获取到私有的构造方法创建对象的时候,报错非法访问异常
// java.lang.IllegalAccessException
// public T setAccessible(true)
// 暴力访问
dc.setAccessible(true);
Object o2 = dc.newInstance();
System.out.println(o2);
}
}
3、获取成员变量 & 对象赋值
public class Reflect3 {
public static void main(String[] args) throws Exception{
Class<?> c = Class.forName("javase.day25.Reflect.Pokemon");
// public Field[] getFields()
// 获取该类中所有 public 的成员变量
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("-------------------------");
// public Field[] getDeclaredFields()
// 获取所有的成员变量
// 包括public,protect,默认(包)访问和 private 字段
Field[] declaredFields = c.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("-------------------------");
// public Field getField(String name)
// 获取单个 public 的成员变量
// name - 字段名称
Field gender = c.getField("gender");
System.out.println(gender);
System.out.println("-------------------------");
// public Field getDeclaredField(String name)
// 获取任意成员变量
// 包括public,protect,默认(包)访问和 private 字段
Field name = c.getDeclaredField("name");
Field level = c.getDeclaredField("level");
System.out.println(name);
System.out.println("-------------------------");
// 通过反射获取无参构造方法
// 然后再通过反射一个一个成员变量进行赋值
Constructor<?> dc = c.getDeclaredConstructor();
dc.setAccessible(true);
Object o = dc.newInstance();
// Field类中有一个方法可以给成员变量进行赋值
// void set(Object obj, Object value)
// 暴力访问
name.setAccessible(true);
level.setAccessible(true);
name.set(o,"ralts");
level.set(o,5);
gender.set(o,1);
System.out.println(o);
}
}
4、获取成员变量 & 对象赋值
public class Reflect4 {
public static void main(String[] args) throws Exception{
Class<?> c = Class.forName("javase.day25.Reflect.Pokemon");
// public 方法[] getMethods()
// 获取所有的成员 public 的方法,还包括父类的
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("---------------------------");
// public 方法[] getDeclaredMethods()
// 获取所有的成员的方法,仅自身
Method[] declaredMethods = c.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
System.out.println("---------------------------");
// public 方法 getMethod(String name,类<?>... parameterTypes)
// 获取一个指名的 public 方法
// 注意:只写方法名,不写小括号
Method funlevel = c.getMethod("funlevel", int.class);
System.out.println(funlevel);
System.out.println("---------------------------");
// public 方法 getDeclaredMethod(String name,类<?>... parameterTypes)
// 获取任意一个指名方法
Method funname = c.getDeclaredMethod("funname", String.class);
System.out.println(funname);
System.out.println("---------------------------");
// 获取show方法并调用
// 创建对象
Constructor<?> con = c.getConstructor(String.class, int.class);
Object o = con.newInstance("piplup",5);
// Object invoke(Object obj, Object... args)
// 在具有指定参数的 方法对象上调用此 方法对象表示的底层方法
funlevel.invoke(o,5);
// private 方法,暴力访问
funname.setAccessible(true);
funname.invoke(o,"piplup");
}
}
5、通过配置文件运行类中的方法
配置
里面的内容基本上都是 键–值 成对成对存在的
例:
className=javase.day27.Pokemon
methodName=study
// 测试类
public class Pokemon {
public void study(){
System.out.println("学会了撞击");
}
}
public class Reflect1 {
public static void main(String[] args) throws Exception{
//在此之前是通过创建对象,调用方法
//学习反射之后,ava里面提供了一个配置文件类
//Properties
//获得、读取配置文件
Properties properties = new Properties();
FileReader fr = new FileReader("configure.txt");
properties.load(fr);
fr.close();
String className = properties.getProperty("className");
// System.out.println(className);
String methodName = properties.getProperty("methodName");
// System.out.println(methodName);
//获取构造方法,获取对象
Class<?> c = Class.forName(className);
Constructor<?> dc = c.getDeclaredConstructor();
dc.setAccessible(true);
Object o = dc.newInstance();
Pokemon p = (Pokemon) o;
//获取方法,并调用
Method dm = c.getDeclaredMethod(methodName);
dm.setAccessible(true);
dm.invoke(p);
}
}
运行结果:学会了撞击
6、修改成员变量方法
写一个方法
public void setProperty(Object obj, String propertyName
, Object value){},
此方法可将obj对象中名为propertyName的属性的值设置为value
可以修改 private 成员
public class Reflect2 {
public static void main(String[] args) {
Pokemon p = new Pokemon();
Reflect2.setProterty(p,"name","piplup");
Reflect2.setProterty(p,"level",5);
System.out.println(p);
}
public static void setProterty(Object obj, String propertyName
, Object value) {
// 获取 class 对象
Class<?> c = obj.getClass();
Field df = null;
try {
// 获取成员变量并修改
df = c.getDeclaredField(propertyName);
df.setAccessible(true);
df.set(obj,value);
} catch (IllegalAccessException | NoSuchFieldException e) {
e.printStackTrace();
}
}
}
总结
反射
获取 class 对象
Class<?> c4 = Class.forName("javase.day25.Reflect.Pokemon");
获取所有构造方法
public Constructor<?>[] getDeclaredConstructors()
利用指定构造方法创建对象
public T newInstance(Object... initargs)
暴力访问
注:访问非公共时使用,用到谁就暴力访问谁
public T setAccessible(true)
获取所有成员变量
public Field[] getDeclaredFields()
对指定对象的成员变量赋值
void set(Object obj, Object value)
获取所有成员方法
public 方法[] getDeclaredMethods()
在指定对象上调用指定方法
Object invoke(Object obj, Object... args)