- 反射
- 模块化
- 类加载的描述
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过 “类的加载”,“类的连接”,
如果不出现意外情况,JVM将会连续完成这三个步骤,
以有时也把这三个步骤统称为类加载或者类初始化.
一个类的生命周期包括了 “加载”、“验证”、“准备”、“解析”、“初始化”、“使用”、“卸载” 这七个阶段,
一般我们只研究前五个阶段,这五个阶段又可以分为 “加载”、“连接(准备,验证,解析)” 、 “初始化”
- 类的加载: 加载二进制数据
- 类的连接
验证阶段:用于检验被加载的类是否有正确的内部结构,并和其他类协调一致
准备阶段:将为静态变量和静态常量分配内存,并赋值
静态变量只会给默认值。
静态常量(static final修饰的)则会直接赋值。
解析阶段:将类的二进制数据中的符号引用替换为直接引用
- 类的初始化
类的初始化的主要工作是为静态变量赋程序设定的初值。
类的初始化步骤
- 类的初始化时机
全盘负责:就是当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
父类委托:就是当一个类加载器负责加载某个Class时,先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类
缓存机制:保证所有加载过的Class都会被缓存,当程序需要使用某个Class对象时,类加载器先从缓存区中搜索该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存储到缓存区
什么是双亲委派机制:
当前ClassLoader首先从自己已经加载的类中查询是否此类已经加载,
如果已经加载则直接返回原来已经加载的类。每个类加载器都有自己的加载缓存,
当一个类被加载了以后就会放入缓存,等下次加载的时候就可以直接返回了。
当前classLoader的缓存中没有找到被加载的类的时候,委托父类加载器去加载,
父类加载器采用同样的策略,首先查看自己的缓存,然后委托父类的父类去加载,
一直到bootstrp ClassLoader.
当所有的父类加载器都没有加载的时候,再由当前的类加载器加载,
并将其放入它自己的缓存中,以便下次有加载请求的时候直接返回。
当JVM启动的时候,Java缺省开始使用如下三种类加载器:
BootstrapClassLoader:它是虚拟机的内置类加载器,通常表示为null ,并且没有父null
PlatformClassLoader:平台类加载器可以看到所有平台类 ,平台类包括由平台类加载器或其祖先定义的Java SE平台API,其实现类和JDK特定的运行时类
SystemClassLoader:它也被称为应用程序类加载器(ApplicationClassLoader) ,与平台类加载器不同。 系统类加载器通常用于定义应用程序类路径,模块路径和JDK特定工具上的类
UserClassLoader:自定义类加载器
类加载器的继承关系:System的父加载器为Platform,而Platform的父加载器为Bootstrap
方法分类
示例代码
public class ClassLoaderDemo {
public static void main(String[] args) {
//static ClassLoader getSystemClassLoader():返回用于委派的系统类加载器
ClassLoader c = ClassLoader.getSystemClassLoader();
System.out.println(c); //AppClassLoader
//ClassLoader getParent():返回父类加载器进行委派
ClassLoader c2 = c.getParent();
System.out.println(c2); //PlatformClassLoader
ClassLoader c3 = c2.getParent();
System.out.println(c3); //null
}
}
反射: 在程序运行时期获取各个类(Class),将类的信息封装成相应的(Field,Constructor,Method)对象
类的信息:
类的对象 : Class
总结:
示例代码
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException {
// 获取字节码对象
// 第一种方式 对象名.getClass
// 方法的参数是一个类名的时候,获取到这个类的字节码文件
Student stu = new Student();
Class clazz1 = stu.getClass();
// 第二种方式 类名.class
// 方法的参数是一个Class字节码对象
Class clazz2 = Student.class;
method2(Student.class);
// 第三种方式 Class.forName(String className)
// 把类的路径存储到配置文件 中
Class clazz3 = Class.forName("com.itheima.m_code.demo01.Student");
System.out.println(clazz1 == clazz2);
System.out.println(clazz1 == clazz3);
}
// 第一种方式 对象名.getClass 应用场景
public static void method1(Student student) {
Class<? extends Student> aClass = student.getClass();
}
// 第二种方式 类名.class应用场景
public static void method2(Class clazz){
}
}
方法分类
T newInstance(Object…initargs) 根据指定的构造方法创建对象
/*
反射获取构造方法并使用
*/
public class ReflectDemo01 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class<?> c = Class.forName("com.itheima_02.Student");
//Constructor>[] getConstructors() 返回一个包含 Constructor对象的数组, Constructor对象反映了由该 Class对象表示的类的所有公共构造函数
// Constructor>[] cons = c.getConstructors();
//Constructor>[] getDeclaredConstructors() 返回反映由该 Class对象表示的类声明的所有构造函数的 Constructor对象的数组
Constructor<?>[] cons = c.getDeclaredConstructors();
for(Constructor con : cons) {
System.out.println(con);
}
System.out.println("--------");
//Constructor getConstructor(Class>... parameterTypes) 返回一个 Constructor对象,该对象反映由该 Class对象表示的类的指定公共构造函数
//Constructor getDeclaredConstructor(Class>... parameterTypes) 返回一个 Constructor对象,该对象反映由此 Class对象表示的类或接口的指定构造函数
//参数:你要获取的构造方法的参数的个数和数据类型对应的字节码文件对象
// 使用的是无参构造创建对象,选择构造的阶段
Constructor<?> con = c.getConstructor();
//Constructor提供了一个类的单个构造函数的信息和访问权限
//T newInstance(Object... initargs) 使用由此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例
Object obj = con.newInstance();
System.out.println(obj);
// Student s = new Student();
// System.out.println(s);
}
}
案例需求
代码实现
/*
通过反射实现如下的操作:
Student s = new Student("林青霞",30,"西安");
System.out.println(s);
*/
public class ReflectDemo02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class<?> c = Class.forName("com.itheima.t_code.reflect.itheima_02.Student");
//public Student(String name, int age, String address)
//Constructor getConstructor(Class>... parameterTypes)
Constructor<?> con = c.getConstructor(String.class, int.class, String.class);
//基本数据类型也可以通过.class得到对应的Class类型
//T newInstance(Object... initargs)
// Object obj = con.newInstance("林青霞", 30, "西安");
Student obj = (Student) con.newInstance("林青霞", 30, "西安");
// 如何获取姓名 年龄 地址
System.out.println(obj.getName());
System.out.println(obj.getAge());
System.out.println(obj.getAddress());
System.out.println(obj);
}
}
案例需求
代码实现
学生类:参见上方学生类
测试类
/*
* Constructor >[] getConstructors()
* 返回所有public修饰的公共构造方法对象的数组
* Constructor>[] getDeclaredConstructors()
* 返回所有构造方法对象的数组
* Constructor getConstructor(Class>... parameterTypes)
* 返回单个公共构造方法对象
* Constructor getDeclaredConstructor(Class>... parameterTypes)
* 返回单个构造方法对象
*/
public class ConstructorDemo {
public static void main(String[] args) throws Exception {
// 获取Student的Class对象
Class clazz = Class.forName("cn.itcast.domain.Student");
// 通过简便的方式,创建对象
// Object obj = clazz.newInstance();
// System.out.println(obj);
// 获取所有的public所修饰的构造方法
// Constructor >[] getConstructors()
// Constructor[] cons = clazz.getConstructors();
// for (Constructor c : cons) {
// System.out.println(c);
//
// }
// 获取所有的构造方法
/*Constructor[] cons = clazz.getDeclaredConstructors();
for (Constructor c : cons) {
System.out.println(c);
}*/
// 获取public修饰的指定的无参的构造
// Constructor con = clazz.getConstructor();
// System.out.println(con);
// 获取私有的指定的name的有参构造
// Constructor con = clazz.getDeclaredConstructor(String.class);
// System.out.println(con);
// 暴力反射
// con.setAccessible(true);
// 创建对象
// Object obj = con.newInstance("张三");
// System.out.println(obj);
// public Student(String name, int age, String address)
// Constructor con = clazz.getConstructor(String.class,int.class,String.class);
// Object obj = con.newInstance("张三",123,"北京");
// System.out.println(obj);
}
}
* Field[] getFields() 返回所有公共成员变量对象的数组
* Field[] getDeclaredFields() 返回所有成员变量对象的数组
* Field getField(String name) 返回单个公共成员变量对象
* Field getDeclaredField(String name) 返回单个成员变量对象
void set(Object obj,Object value) 给obj对象的成员变量赋值为value
/*
反射获取成员变量并使用
*/
public class ReflectDemo01 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class<?> c = Class.forName("com.itheima.t_code.reflect.itheima_02.Student");
Object obj = c.newInstance();
//Field[] getFields() 返回一个包含 Field对象的数组, Field对象反映由该 Class对象表示的类或接口的所有可访问的公共字段
//Field[] getDeclaredFields() 返回一个 Field对象的数组,反映了由该 Class对象表示的类或接口声明的所有字段
// Field[] fields = c.getFields();
Field[] fields = c.getDeclaredFields();
for(Field field : fields) {
System.out.println(field);
}
System.out.println("--------");
//Field getField(String name) 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定公共成员字段
//Field getDeclaredField(String name) 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定声明字段
Field addressField = c.getField("address");
//获取无参构造方法创建对象
// Constructor> con = c.getConstructor();
// Object obj = con.newInstance();
// obj.addressField = "西安";
//Field提供有关类或接口的单个字段的信息和动态访问
//void set(Object obj, Object value) 将指定的对象参数中由此 Field对象表示的字段设置为指定的新值
addressField.set(obj,"西安"); //给obj的成员变量addressField赋值为西安
System.out.println(obj);
// Student s = new Student();
// s.address = "西安";
// System.out.println(s);
}
}
案例需求
代码实现
学生类:参见上方学生类
案例代码:
/*
* Field[] getFields() 返回所有公共成员变量对象的数组
* Field[] getDeclaredFields() 返回所有成员变量对象的数组
* Field getField(String name) 返回单个公共成员变量对象
* Field getDeclaredField(String name) 返回单个成员变量对象
*/
public class FieldDemo {
public static void main(String[] args) throws Exception {
// 获取Student的Class对象
Class clazz = Class.forName("cn.itcast.domain.Student");
// 创建对象
Object obj = clazz.newInstance();
// Field[] getFields()
// Field[] fields = clazz.getFields();
// Field[] getDeclaredFields()
// Field[] fields = clazz.getDeclaredFields();
// for (Field field : fields) {
// System.out.println(field);
// }
Field address = clazz.getField("address");
// // 给这个变量 address 赋值
address.set(obj,"东京");
// // 获取值
// Object addressObj = address.get(obj);
// System.out.println(addressObj);
// System.out.println(obj);
// Field getDeclaredField(String name)
Field name = clazz.getDeclaredField("name");
// 取消访问检查
name.setAccessible(true);
name.set(obj,"小苍");
// 给年龄进行赋值
Field age = clazz.getDeclaredField("age");
// 取消访问检查
age.setAccessible(true);
age.set(obj,32);
System.out.println(obj);
}
}
* Method[] getMethods()
* 返回所有公共成员方法对象的数组,包括继承的
* Method[] getDeclaredMethods()
* 返回所有成员方法对象的数组,不包括继承的
* Method getMethod(String name, Class>... parameterTypes)
* 返回单个公共成员方法对象
* Method getDeclaredMethod(String name, Class>... parameterTypes)
* 返回单个成员方法对象
* Object invoke(Object obj,Object... args)
* 调用obj对象的成员方法,参数是args,返回值是Object类型
/*
反射获取成员方法并使用
*/
public class ReflectDemo01 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class<?> c = Class.forName("com.itheima.t_code.reflect.itheima_02.Student");
//Method[] getMethods() 返回一个包含 方法对象的数组, 方法对象反映由该 Class对象表示的类或接口的所有公共方法,包括由类或接口声明的对象以及从超类和超级接口继承的类
//Method[] getDeclaredMethods() 返回一个包含 方法对象的数组, 方法对象反映由 Class对象表示的类或接口的所有声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承方法
// Method[] methods = c.getMethods();
Method[] methods = c.getDeclaredMethods();
for(Method method : methods) {
System.out.println(method);
}
System.out.println("--------");
//Method getMethod(String name, Class>... parameterTypes) 返回一个 方法对象,该对象反映由该 Class对象表示的类或接口的指定公共成员方法
//Method getDeclaredMethod(String name, Class>... parameterTypes) 返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 Class对象
//public void method1()
Method m = c.getMethod("method1");
//获取无参构造方法创建对象
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
// obj.m();
//在类或接口上提供有关单一方法的信息和访问权限
//Object invoke(Object obj, Object... args) 在具有指定参数的指定对象上调用此 方法对象表示的基础方法
//Object:返回值类型
//obj:调用方法的对象
//args:方法需要的参数
m.invoke(obj);
// Student s = new Student();
// s.method1();
}
}
案例需求
代码实现
public class MethodTest {
public static void main(String[] args) throws Exception {
// 获取Student的Class对象
Class clazz = Class.forName("cn.itcast.domain.Student");
// 创建对象
Object obj = clazz.newInstance();
// public String method3(String s, int i)
Method method = clazz.getMethod("method3", String.class, int.class);
// 执行方法
Object str = method.invoke(obj, "麻生希", 30);
System.out.println(str);
System.out.println("~~~~~~~~~~~~~~~~~~~");
Method method1 = clazz.getDeclaredMethod("method4", String.class, int.class);
// 暴力反射
method1.setAccessible(true);
// 执行方法
Object o = method.invoke(obj, "波姐", 28);
System.out.println(o);
}
}
案例需求
代码实现
public class Test1 {
public static void main(String[] args) throws Exception {
// 泛型在编译时期是有这个泛型的,在运行时期是没有泛型的 --> 泛型擦除
ArrayList<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
// list.add(123);
// 获取list的Class对象
Class clazz = list.getClass();
// 获取对象中的方法 add
Method methodAdd = clazz.getMethod("add", Object.class);
// 运行,添加数据
methodAdd.invoke(list, 100);
methodAdd.invoke(list, 200);
methodAdd.invoke(list, true);
System.out.println(list);
}
}
案例需求
代码实现
配置文件:class.txt
className=com.itheima_06.Teacher
methodName=teach
/*
练习2:通过配置文件运行类中的方法
*/
public class ReflectTest02 {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//加载数据
Properties prop = new Properties();
FileReader fr = new FileReader("myReflect\\class.txt");
prop.load(fr);
fr.close();
/*
className=com.itheima_06.Student
methodName=study
*/
String className = prop.getProperty("className"); // com.itheima_06.Student
String methodName = prop.getProperty("methodName"); // study
// System.out.println(className);
// System.out.println(methodName);
//通过反射来使用
Class<?> c = Class.forName(className);//com.itheima_06.Student
Object obj = c.newInstance();
/* Constructor> con = c.getConstructor();
Object obj = con.newInstance();*/
Method m = c.getDeclaredMethod(methodName);//study
// 取消访问检查
m.setAccessible(true);
// 执行方法
m.invoke(obj);
}
}
Java语言随着这些年的发展已经成为了一门影响深远的编程语言,无数平台,
系统都采用Java语言编写。
但是,伴随着发展,Java也越来越庞大,逐渐发展成为一门“臃肿” 的语言。
而且,无论是运行一个大型的软件系统,还是运行一个小的程序,即使程序只需要使用Java的部分核心功能, JVM也要加载整个JRE环境。
为了给Java“瘦身”,让Java实现轻量化,Java 9正式的推出了模块化系统。
Java被拆分为N多个模块,并允许Java程序可以根据需要选择加载程序必须的Java模块,这样就可以让Java以轻量化的方式来运行
其实,Java 7的时候已经提出了模块化的概念,但由于其过于复杂,Java 7,Java 8都一直未能真正推出,直到Java 9才真正成熟起来。
对于Java语言来说,模块化系统是一次真正的自我革新,这种革新使得“古老而庞大”的Java语言重新焕发年轻的活力
在myOne模块中新建一个包,提供一个接口和两个实现类
在myOne模块中修改 module-info.java文件,添加以下内容
在myTwo模块中新建一个测试类
//加载服务
ServiceLoader myServices = ServiceLoader.load(MyService.class);
//遍历服务
for(MyService my : myServices) {
my.service();
}
在myTwo模块中修改 module-info.java文件,添加以下内容
public class Student {
//成员变量:一个私有,一个默认,一个公共
private String name;
int age;
public String address;
//构造方法:一个私有,一个默认,两个公共
public Student() {
}
private Student(String name) {
this.name = name;
}
Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
//成员方法:一个私有,四个公共
private void function() {
System.out.println("function");
}
public void method1() {
System.out.println("method");
}
public void method2(String s) {
System.out.println("method:" + s);
}
public String method3(String s, int i) {
return s + "," + i;
}
// 方法是私有的而且参数String s, int i 带返回值的
private String method4(String s, int i){
return s + ":" + i;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
this.name = name;
this.age = age;
this.address = address;
}
//成员方法:一个私有,四个公共
private void function() {
System.out.println("function");
}
public void method1() {
System.out.println("method");
}
public void method2(String s) {
System.out.println("method:" + s);
}
public String method3(String s, int i) {
return s + "," + i;
}
// 方法是私有的而且参数String s, int i 带返回值的
private String method4(String s, int i){
return s + ":" + i;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}