模块化概述
模块化概述:随着Java越来越'庞大'的发展,无论是运行大型软件系统,还是只运行一个小程序,即使程序只需要使用Java的部分核心功能,JVA也要加载整个JRE环境。为了让Java实现轻量化,Java9正式的推出了模块化系统。Java被拆分为N多个模块,并允许Java程序可以根据需要选择加载程序必须的Java模块,这样就可以让Java以轻量化的方式来运行
模块的基本使用
模块语法只在Java8以上的版本才能使用
模块的基本使用步骤 1、创建模块(按照以前的讲解方式创建模块,创建包、类、定义方法) 2、为了体现模块的使用,我们创建两个模块。一个是myOne,一个是myTwo 3、分别在myOne模块和myTwo模块的src目录下新建一个名为module-info.java的描述性文件,该文件专门定义模块名、访问权限、模块依赖等信息。 描述性文件中使用模块导出和模块依赖来进行配置并使用 4、模块中所有为导出的包都是模块私有的,它们是不能再模块之外被访问的,解决:在module-info.java的描述性文件中配置模块导出 模块导出格式:exports 包名; 5、一个模块要访问其他的模块,必须明确指定依赖哪些模块,为明确的模块不能访问。如何指定:例如myTwo模块想访问myOne模块下的包,就在myTwo模块下新建的module-info.java文件里面配置模块依赖。模块依赖的格式:require 模块名; 注意:在require后面写模块名如果报错,就需要按下Alt+Enter提示,然后选择模块依赖
如何新建模块,如下
点击左上角的File -> Project structure -> 弹出的Project structure选项卡中选择左边的Modules -> 点击+ -> 点击New Module -> 点击Next -> 设置模块的路径名称 -> 回车
为了不让笔记做的混乱,我就在我们目前的java模块下的src下的ch27下新建myOne和myTwo类中做代码演示,然后我们把这两个类看做是不同的模块下就行了
a_15_1myOne_Student就看做是myOne模块的Student类 a_15_3myTwo_test01就看做是myTwo模块下的test01类
注意要把我们已有的myOne和myTwo类看做是myOne和myTwo两个不同的模块 假设我们要在myTwo模块下访问myOne模块下的学生类的study方法,即就是a_15_3myTwo_test类中做的代码演示,那里有相应笔记
再强调一遍,模块1指的是myOne,模块2指的是myTwo;myOne指的是a_15_1myOne_Student,即myOne下有一个类是学生类;myTwo指的是a_15_3myTwo_test01,用于作为测试类,探究能否在myTwo模块下访问myOne模块下的类的方法
注意:由于我们的模块1和模块2是在同一模块且同一包下的所以不会出现我们所述的报错错误。但是我们要理解为我们的就是发生了那样的错误详细的不同模块下使用彼此的内容会发生什么报错错误就快去a_15_3myTwo_test查看吧,以及如何解决
模块基本使用的练习
xxxxxxxxxx
package ch27;
public class a_15_1myOne_Student {
public void study(){
System.out.println("我是模块1的学生类的study方法");
}
}
x
package ch27;
import ch27.a_15_1myOne_Student;//导包的学生类也会报红
//如何在模块2访问模块1的学生类的study方法呢
public class a_15_2myTwo_test01 {
public static void main(String[] args) {
//创建模块1的学生类的对象
a_15_1myOne_Student s = new a_15_1myOne_Student();
//使用学生类的对象s调用学生类里面的study方法
s.study();
//则上面的学生类和study就会报红,即使在最上面导包了还是报红。原因:模块2无法访问模块1的内容
//--------------------------------------------------------------------------------------------------------
//通过上面的那些代码,我们可以知道myTwo模块下的test01类无法访问myOne模块下的学生类里面的study方法,如何解决呢,如下
//解决:
//1、分别在myOne模块和myTwo模块的src目录下新建一个名为module-info.java的描述性文件
//2、在myOne模块进行配置模块导出,格式:exports 包名
//3、在myTwo模块进行配置模块依赖。格式:require 模块名
//做了上面3步之后,就可以在这个模块访问其他模块了,即模块2访问模块1的学生类的study方法
//注意由于我们实际上并没有myOne模块和myTwo模块,就直接在我们的java模块下的src下新建名为module-info.java的描述性文件
}
}
//下一节的a_16的看看注释就好了。原因:那节课是必须要使用不同模块才能进行代码演示,不像我们这里a_15可以简单模拟一下假如有两个不同模块的情况。
//简单来说就是要想完成下面的代码演示必须要有两个不同模块,而我并不想建立这么多模块,一个java模块以后复习起来不会乱,再增加其他模块的话,不利于
//后续的复习。但是,虽然我们看不了代码运行,但是我已经在下节a_16的写了足够详细的笔记,完全可以看注释的笔记学
//有必要强调一下,并不是说下面的代码出现错误才不学,下面的所有代码和代码注释我都写了,其实代码是没问题,我只是注释掉了,解开注释后是可以
//正常编译不会出现任何红字报错,只不过在右键运行的时候在控制台会报错,原因是我只是模拟了有两个模块的情况下,并不是真正有两个模块,模块服务就不
//能正常在控制台运行。注意:如果你想要检验是否真的代码可以正常编译,那你就需要把下面的代码解开注释,我用的是大注释,很好解开注释,具体做法如下:
//解开下面的a_16_1、1_16_3的大注释。还要解开ch27包下的a_16_2Impl包下的Czxyhuaf类、Itheimehuanf类的大注释。还要解开src下
//的module-info类里面的注释
模块服务的使用
服务:从Java6开始,Java提供了一种服务机制,允许服务提供者和服务使用者之间完成解耦。简单的说,就是服务使用者只面向接口编程,但不清楚服务提供者发实现类
Java9的模块化系统则进一步的简化了Java的服务机制。Java9允许将服务接口定义在一个模块中,并使用uses语句来声明该服务接口,然后针对该服务接口提供不同的服务实现类,这些服务实现类可以分布在不同的模块中,服务实现模块则使用provides语句为服务接口指定实现类,服务使用者只需要面向接口编程即可
模块服务的使用步骤如下
第一步: 在myOne模块下创建一个包bag,在该包下提供一个接口,接口中定义一个抽象方法,如下
public interface MyService{
void service();
}
为了不让笔记做的混乱,我就在我们目前的java模块下新建一个接口a_16_1myOne_ch27_MyService且在里面定义一个抽象方法。我们就把上面那行创建的接口理解为是在myOne模块下的ch27包下,创建的MyService接口
第二步: 在ch27包下创建一个包a_16_2Impl,在该包下提供接口的两个实现类Itheimahuanf和Czxyhuanf
第三步: 在myOne这个模块下的描述性文件(即上节课建的myOne模块下的src目录下的名为module-info.java的描述性文件)中添加如下配置
x模块导出:exports ch27;
服务提供:provides a_16_1myOne_ch27_MyService with Itheimahuanf; //指定MyService的实现类是Itheimahuanf
第四步: myTwo这个模块下的描述性文件中添加如下配置
xxxxxxxxxx
说明服务接口:uses a_16_1myOne_ch27_MyService;
第五步: 在myTwo模块下新建一个类,看是否能使用myOne这个模块下的接口的方法。对于我们来说就是新建一个a_16_2myTwo_test01类就好
怎么使用myOne这个模块下的接口呢,如下
ServiceLoader类:一种加载服务实现的工具。该类在java.util包下,该类有一个泛型。该类是最终类,继承自Object类,该类实现了Iterable接口
该类怎么加载服务:通过调用ServiceLoader的静态load方法
模块服务使用的练习
x
package ch27;
public interface a_16_1myOne_ch27_MyService {
void service();
}
xxxxxxxxxx
package ch27;
import java.util.ServiceLoader;
import ch27.a_16_1myOne_ch27_MyService;
public class a_16_2myTwo_test01 {
public static void main(String[] args) {
//加载服务
ServiceLoader<a_16_1myOne_ch27_MyService> myServices = ServiceLoader.load(a_16_1myOne_ch27_MyService.class);
//遍历上面那个加载好的服务。由于ServiceLoader类实现了Iterable接口,所以ServiceLoader类是可以被遍历的
//注意要把a_16_1myOne_ch27_MyService当做是myOne模块下的,把这里的a_16_2myTwo_test01类当作myTwo模块下的
for(a_16_1myOne_ch27_MyService my : myServices){
my.service(); //即实现了在myTwo模块下调用myOne模块下的a_16_1myOne_ch27_MyService接口的service方法
}
}
}