类的初始化时机:
当Java程序首次通过下面6种方式来使用某个类或接口时,系统就会初始化该类或者接口。
1. 创建类的实例(对象)
2. 调用类的类方法
3. 访问类或者接口的类变量,或者为该类变量赋值
4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
5. 初始化某个类的子类
6. 直接使用java.exe命令来运行某个主类
类加载器使用ClassLoader表示。Java运行时具有以下内置类加载器:
1. Bootstrap class loader:它是虚拟机的内置类加载器,通常表示为null ,并且没有父加载器; 引导类加载器负责加载java的核心类;
2. Platform class loader: 它是平台类加载器; 负责加载JDK中一些特殊的模块;
3. System class loader: 它也被称为应用程序类加载器 ; 它的加载路径是程序运行的当前路径;
这3个类加载器实例之间存在继承关系;
系统类加载器 --extends--> 平台类加载器 -extends--> 引导类加载器
ClassLoader 中的两个方法
1. static ClassLoader getSystemClassLoader():返回用于委派的系统类加载器
2. ClassLoader getParent():返回父类加载器进行委派
反射的定义
JAVA反射机制是在运行状态中,对于任意一个实体类,都能够获取到该类的所有的属性和方法,并且
对其进行使用;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
由于这种动态性,可以极大的增强程序的灵活性,在运行时期可以动态对我们的程序进行扩展;
获取Class对象:
我们要想通过反射去使用一个类,首先我们要获取到该类的字节码文件对象,也就是类型为Class类型
的对象。一个类只能存在一个Class对象。
这里我们提供三种方式获取Class类型的对象:
1. 使用类的静态class属性来获取该类对应的Class对象。举例:Student.class将会返回
Student类对应的Class对象
Class<Student> studentClazz1 = Student.class;
2. 调用对象的getClass()方法,返回该对象所属类对应的Class对象,该方法是Object类中的
方法,所有的Java对象都可以调用该方法
Student s = new Student();
Class studentClazz2 = s.getClass();
3. 使用Class类中的静态方法forName(String className),该方法需要传入字符串参数,该
字符串参数的值是某个类的全路径,也就是完整包名的路径 (常用)
Class studentClazz3 = Class.forName("com.itheima.advance.reflect.demo01.Student");
三个Class的对象完全相同,也就是说 一个类只能存在一个Class对象。
反射获取构造方法并创建对象:
Class类中用于获取构造方法的方法:
1、Constructor<?>[] getConstructors():
返回所有公共构造方法对象的数组
2、Constructor<?>[] getDeclaredConstructors():
返回所有构造方法对象的数组
3、Constructor<T> getConstructor(Class<?>... parameterTypes):
返回单个公共构造方法对象
4、Constructor<T> getDeclaredConstructor(Class<?>...parameterTypes):
返回单个构造方法对象
Class studentClazz = Class.forName("com.itheima.advance.reflect.demo02.Student");
Constructor clazzConstructor = studentClazz.getConstructor(String.class , int.class);
括号内为该构造器参数类型的类 int的类是int.class String的类是String.class 该方法不带declare所以只能获取公共构造器;
使用该构造器创建对象:
Student s2 = (Student)clazzConstructor.newInstance("张三", 23);
Constructor declaredConstructor = studentClazz.getDeclaredConstructor(String.class)
因为有declare 可以获取私有构造器,私有构造器创建对象时需要设置为强制访问:
declaredConstructor.setAccessible(true);
Student s3 = (Student) declaredConstructor.newInstance("李四");
反射获取成员变量(属性):
1、Field[] getFields(): 返回所有公共成员变量对象的数组
2、Field[] getDeclaredFields(): 返回所有成员变量对象的数组
3、Field getField(String name): 返回单个公共成员变量对象
4、Field getDeclaredField(String name):返回单个成员变量对象
获取Student的字节码文件对象
Class studentClazz = Class.forName("com.itheima.advance.reflect.demo03.Student");
获取name共有属性对象:
Field name = studentClazz.getField("name");
获取age私有属性对象:
Field age = studentClazz.getDeclaredField("age");
调用成员变量对象的方法来给成员变量赋值
void set(Object obj, Object value):给obj对象的该成员变量赋值为value
反射中创建对象的三种方式:
1. 直接new出来
Student s1 = new Student();
2. 获取无参构造方法对象,然后通过调用无参构造方法对象去创建一个对象
Constructor con1 = studentClazz.getDeclaredConstructor();
Student s1 = (Student) con1.newInstance() ;
3. 可以使用Class对象中的newInstance方法去创建对象,必须要有公共无参构造器
Student s1 = (Student)studentClazz.newInstance();
给name公共属性设置值:
name.set(s1 , "张三");
给age私有属性设置值:
age.setAccessible(true);
age.set(s1 , 23);
反射获取成员方法:
1、Method[] getMethods():
返回所有公共成员方法对象的数组,包括继承的
2、Method[] getDeclaredMethods():
返回所有成员方法对象的数组,不包括继承的
3、Method getMethod(String name, Class<?>... parameterTypes) :
返回单个公共成员方法对象
4、Method getDeclaredMethod(String name, Class<?>...parameterTypes):
返回单个成员方法对象 (常用)
Method info = clazz.getMethod("info", String.class)
第一个参数 方法名
第二个参数为可变长参数,该方法中所有的参数类型的类对象
返回Method对象
Method中的方法:
public Object invoke(Object obj, Object... args)
第一个参数: 调用该方法的对象
第二个参数: 该方法的所需要的实际参数
返回 执行该方法的返回值
Method info = studentClazz.getDeclaredMethod("info", String.class);
String invoke = (String)info.invoke(changhao, "hello");
如果该方法是静态方法,那么invoke方法中的第一个参数可以使null
String invoke = (String)info.invoke(null, "hello");
如果是私有方法,调用invoke之前需要先调用setAccessble(true);
反射中方法:
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
对象是否有某个反射对象
例如:
boolean flag = IntegerClass.isAnnotationPresent(Override.class)
public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
获取某个注解对象
例如:
Retention annotation = IntegerClass.getAnnotation(Retention.class);
RetentionPolicy value = annotation.value(); //获取注解对象属性的值,返回值为RetentionPolicy枚举对象。