跳至主要內容

类结构扩展

wangdx大约 11 分钟

类结构扩展

包功能简介

  • 项目开发是一个不断递进的过程,一个完整的 Java 项目必然必然要包含有大量的“*.class”文件,但是如果将这些文件保存在同一个目录中则有可能会出现类名称冲突以及代码维护的困难,所以最佳的做法是将不同功能的类保存在同一个文件目录之中
  • 这样的目录在 Java 中称其为“包(Package)

包的定义

案例
package pkg.w01;

/**
 * @author wangdx
 */
public class Test {
    public static void main(String[] args) {
        System.out.println("hello");
    }
}

程序执行

  • 打包编译程序:javac -d . Hello.java
    • “-d”:生成一个目录,根据程序源代码中的 package 定义来生成目录
    • "." :在当前所在的目录下生成相应的包.类;
  • 执行打包程序类:java com.yootk.main.Hello

包的导入

利用包结构对代码拆分之后,如果需要引入项目中其它包的程序类,则可以使用 import 语句完成

案例
package pkg.w02.entity;

/**
 * @author wangdx
 */
public class Message {
    @Override
    public String toString() {
        return "这是图书信息";
    }
}

----------------------

/**
 * 指定导入类
 */
package pkg.w02;

import pkg.w02.entity.Message;

/**
 * @author wangdx
 */
public class Test {
    public static void main(String[] args) {
        Message message = new Message();
        System.out.println(message);
    }
}

/**
 * 自动匹配导入类
 */
package pkg.w02;

import pkg.w02.entity.*;

/**
 * @author wangdx
 */
public class Test {
    public static void main(String[] args) {
        Message message = new Message();
        System.out.println(message);
    }
}


/**
 * 避免重复导入类
 */
package pkg.w02;

/**
 * @author wangdx
 */
public class Test {
    public static void main(String[] args) {
        pkg.w02.entity.Message message = new pkg.w02.entity.Message();
        System.out.println(message);
    }
}

静态导入

案例

package pkg.w02.entity;

/**
 * @author wangdx
 */
public class Message {
    public static String getInfo() {
        return "一祥集团:www.yix.com";
    }

    @Override
    public String toString() {
        return "这是图书信息";
    }
}




package pkg.w02;

import static pkg.w02.entity.Message.*;

/**
 * @author wangdx
 */
public class Test2 {
    public static void main(String[] args) {
        System.out.println(getInfo());
    }
}

jar 文件

jar(Java Archive,Java 归档文件)是一种 Java 给出的压缩格式文件,即:可以将*.class 文件以*.jar 压缩包的方式给用户,这样方便程序的维护。如果要使用 jar 的话,可以直接利用 JDK 给出的 jar 命令完成,如果要确定使用参数则可以输入“jar --help”查看,在实际开发过程之中往往只使用三个参数:

  • -c:创建一个新的文件;
  • -v:生成标准的压缩信息;
  • -f:由用户自己指定一个*.jar 的文件名称。
案例

CLASSPATH

每一个*.jar 文件都是一个独立的程序路径,如果要想在 Java 程序之中使用此路径,则必须通过 CLASSPATH 属性进行程序路径的配置。

  • 设置 CLASSPATH 属性:SET CLASSPATH=.;H:\muyan\yootk.jar
  • 设置系统 CLASSPATH

系统常见包

访问控制权限

单例设计模式

单例设计模式(Singleton)的核心意义在于将类中的构造方法私有化(主要使用 private 或 protected)这样在类的外部就无法直接使用关键字 new 进行对象实例化,从而实现对象实例化的控制,但是如果一个类不存在实例化对象将无法进行方法的调用,那么就可以在内部定义一个本类的公共对象,这样无论在任何时候类中都只会存在有一个实例化对象。

案例
/**
 * 单例设计模式
 * @author wangdx
 */
public class Singleton {
    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {

    }

    public static Singleton getInstance() {
        return INSTANCE;
    }

    @Override
    public String toString() {
        return super.toString() + "医学科技:www.yixue.com";
    }
}

class Test {
    public static void main(String[] args) {
        Singleton singleton = Singleton.getInstance();
        System.out.println(singleton);
    }
}
/*
 * 懒汉式单例模式
 * */
class Singleton1 {
    private static Singleton1 instance;

    private Singleton1() {
    }

    public static Singleton1 getInstance() {
        if (instance == null) {
            instance = new Singleton1();
        }
        return instance;
    }

    @Override
    public String toString() {
        return super.toString() + "医学科技:www.yixue.com";
    }
}
class Test1{
    public static void main(String[] args) {
        Singleton1 singleton1 = Singleton1.getInstance();
        System.out.println(singleton1);
    }
}

多例设计模式

多例设计模式和单例设计模式的本质上都是相同的,都需要将构造方法进行私有化定义.单例设计模式只能够有一个实例化对象,而多例设计模式中可以提供有若干个实例化对象。例如:如果要定义一个表示颜色基色的 Color 类,那么一般来讲就需要提供有三个实例化对象:蓝色、绿色、红色,如果要定义描述一周时间的类,那么这个对象也仅仅只能够有七个,如果要定义描述性别的类,那么一般只有两种:男、女。

案例
/**
 * 多例设计模式
 *
 * @author wangdx
 */
public class Sex {
    private String value;
    public static final int MALE = 0;
    public static final int FEMALE = 1;
    private static final Sex MALE_INSTANCE = new Sex("男");
    private static final Sex FEMALE_INSTANCE = new Sex("女");

    private Sex(String value) {
        this.value = value;
    }

    public static Sex getInstance(int choose) {
        switch (choose) {
            case MALE: {
                return MALE_INSTANCE;
            }
            case FEMALE: {
                return FEMALE_INSTANCE;
            }
            default: {
                return null;
            }
        }
    }

    @Override
    public String toString() {
        return this.value;
    }
}
class Test{
    public static void main(String[] args) {
        Sex sex = Sex.getInstance(Sex.MALE);
        System.out.println(sex);
    }
}

枚举类

定义枚举类

枚举是一种可以明确列出一个类中所有有序对象的程序结构,可以实现多例设计模式的简化定义,是在 JDK 1.5 之后推出的功能,同时为了便于开发者定义枚举,也提供了一个 enum 的关键字。

案例
/**
 * 定义枚举类
 *
 * @author wangdx
 */
public enum Color {
    RED, BLUE, GREEN;
}

class Test {
    public static void main(String[] args) {
        Color c = Color.BLUE;
        System.out.println(c);
    }
}

BLUE
/*
 * 获取枚举全部对象
 * */
class Test1 {
    public static void main(String[] args) {
        for (Color c : Color.values()) {
            System.out.print(c + "、");
        }
    }
}
REDBLUEGREEN
/*
 * 结合switch
 * */
class Test2 {
    public static void main(String[] args) {
        Color c = Color.RED;
        switch (c) {
            case BLUE: {
                System.out.println("蓝灯亮");
                break;
            }
            case RED: {
                System.out.println("红灯亮");
                break;
            }
            case GREEN: {
                System.out.println("绿灯亮");
                break;
            }
        }
    }
}
红灯亮

Enum 类

在 Java 里面需要通过 enum 关键字来实现枚举类的定义,但是严格意义上来讲,使用 enum 关键字所定义的类本质上相当于一个类继承了 Enum 父类结构,即:如果要想研究枚举,那么首先就需要来观察一下 Enum 类的定义

public abstract class Enum<E extends Enum<E>>  // 泛型上限 extends Object implements Constable, Comparable<E>, Serializable {}
案例
/*
 * 观察Enum使用
 * */
class Test3 {
    public static void main(String[] args) {
        for (Color c : Color.values()) {
            System.out.println("【" + c + "】name=" + c.name() + "、ordinal=" + c.ordinal());
        }
    }
}RED】name=RED、ordinal=0BLUE】name=BLUE、ordinal=1GREEN】name=GREEN、ordinal=2

扩展枚举结构

案例
/**
 * 枚举中定义属性
 *
 * @author wangdx
 */
public enum Color {
    //此时类中不提供有无参构造,所以每一个枚举项(实例化对象)都必须明确的调用构造方法并传递参数
    //枚举项必须写在首航
    RED("红色"), GREEN("绿色"), BLUE("蓝色");
    private String content;

    private Color(String content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return this.content;
    }
}
/*
 * 观察Enum使用
 * */
class Test3 {
    public static void main(String[] args) {
        for (Color c : Color.values()) {
            System.out.println("【" + c + "】name=" + c.name() + "、ordinal=" + c.ordinal());
        }
    }
}

【红色】name=RED、ordinal=0
【绿色】name=GREEN、ordinal=1
【蓝色】name=BLUE、ordinal=2
/*
* 枚举实现接口
* */
interface IMessage {
    public String getColor();
}

enum Color1 implements IMessage {
    RED("红色"), GREEN("绿色"), BLUE("蓝色");
    private String content;

    private Color1(String content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return this.content;
    }

    @Override
    public String getColor() {
        return this.content;
    }
}

class Test1 {
    public static void main(String[] args) {
        IMessage msg = Color1.BLUE;
        System.out.println(msg.getColor());
    }
}
蓝色

枚举应用案例

案例
/**
 * 通过枚举定义图书分类
 *
 * @author wangdx
 */
public enum BookType {
    MATH("数学"), PROGRAM("软件编程"), NETWORK("网络工程");
    private String content;

    private BookType(String content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return this.content;
    }
}

class Book {
    private String title;
    private String author;
    private double price;
    private BookType type;

    public Book(String title, String author, double price, BookType type) {
        this.title = title;
        this.author = author;
        this.price = price;
        this.type = type;
    }

    @Override
    public String toString() {
        return "【图书】名称:" + this.title + "、作者:" + this.author + "、价格:" + this.price + "、类型:" + this.type;
    }
}
class Test{
    public static void main(String[] args) {
        System.out.println(new Book("Java就业编程实战","李兴华",89.6,BookType.NETWORK));
    }
}

【图书】名称:Java就业编程实战、作者:李兴华、价格:89.6、类型:网络工程

Jigsaw 设计简介

传统 JDK 的编译和运行

  • JDK1.9(Java9)最大的变化之一是引入了模块系统(Jiqsaw 项目),jiasaw 是 OpenJDK 项目下的一个子项日,旨在为 Java SE 平台设计、实现一个标准的模块系统,并应用到该平台和 JDK 中。
  • 在 JDK 1.8 及以前的版本中,每当程序编译或执行的时候都需要加载大量的系统类库,而这些系统类库会被统一保存在两个重要的 jar 文件之中,这两个 jar 文件的名称为:
- tools.iar(${JAVA HOME}\lib\tools.jar、17M):相关工具支持类配置;
- rt.jar(${RE HOME}\lib\rt.jar、52M):Java 中核心类库。

JDK 的模块加载

由于这两个开发包的体积较大,这样一来在每次程序编译或解释执行时就会带来执行性能问题,所以在 JDK 1.9 之后引入了模块化系统,最主要的目的是将“rt.jar”与“tools.jar”中的代码根据功能模块进行拆分,这样就可以根据需要进行模块加载,减少不必要的模块加载,从而提升程序的执行性能

javaDoc 的模块定义

在 JDK 1.9 之后 JavaDoc 文档结构发生了改变,所有的程序包都保存在相应的模块之中如图所示,同时在 JDK 的安装目录中提供了“jmods”目录用于模块保存。

模块

模块基本定义和使用

模块目录结构

模块的本质和包是非常类似的,都属于一个文件目录,而在 Java 模块中定义要求中,明确的提出该模块目录必须存在有一个“module-info.java”模块描述文件,该文件定义了模块的名称以及与其相关的其他模块的信息。如果要想充分的理解这种模块的定义,那么首先就必须对当前程序的开发做出一个目录结构上的限定

模块创建

  • 创建一个“com.yix”模块目录,此时的路径为:“D:\develop\project\wyix\gitee\study_service\com.yix”
  • 创建“module-info.java”模块描述文件,该文件的路径为:“D:\develop\project\wyix\gitee\study_service\com.yix\module-info.java",内容为:module com.yix {}
  • 创建程序类“com.yix.main.Hello”,程序类的路径为"D:\develop\project\wyix\gitee\study_service\com.yix\main\Hello.java",代码如下:
案例
package main;

/**
 * @author wangdx
 */
public class Hello {
    public static void main(String[] args) {
        System.out.println("一祥集团:www.yix.com");
    }
}

javac -encoding UTF-8 -d mods/com.yix com.yix/module-info.java com.yix/main/Hello.java

-d: 生成一个模块保存目录 目录名称为com.yix
com.yix/module-info.java 使用特定的module配置文件打包
com.yix/main/Hello.java 打包的程序类

java --module-path mods -m com.yix/main.Hello

模块引用

案例
  • 创建 D:\develop\study\pkg\com.yix
  • 创建 com.yix.info.Message
package com.yix.info;

/**
 * @author wangdx
 */
public class Message {
    @Override
    public String toString() {
        return "大国精神:www.tt.com";
    }
}
javac -encoding UTF-8 -d mods/com.yix com.yix/module-info.java com.yix/info/Message.java

  • 创建 D:\develop\study\pkg\com.yix\module-info.java
/**
 * @author wangdx
 */
module com.yix {
    exports com.yix.info;
}
  • 进入 D:\develop\study\pkg cmd 运行下面指令
javac -encoding UTF-8 -d mods/com.yix com.yix/module-info.java com.yix/com/yix/info/Message.java
  • 创建 D:\develop\study\pkg\test
  • 创建 com.yix.test.TestMessage
package com.yix.test;

import com.yix.info.Message;

/**
 * @author wangdx
 */
public class TestMessage {
    public static void main(String[] args) {
        System.out.println(new Message());
    }
}

  • 创建 D:\develop\study\pkg\test\module-info.java
/**
 * @author wangdx
 */
module test {
    requires com.yix;
}
  • 进入 D:\develop\study\pkg cmd 运行下面指令
javac -encoding UTF-8 --module-path mods -d mods/test test/module-info.java test/com/yix/test/TestMessage.java
  • 运行下面指令测试
java --module-path mods -m test/com.yix.test.TestMessage

模块打包

  • 当前的程序已经实现了模块的定义与导入处理,但是如果细心的读者观察${JAVA HOME}/jmods”目录下保存的模块名称会发现所有的模块都是以 .jmod 文件形式命名的,这些被统一称为模块文件,而如果要想将自己的模块也打包为模块文件,则就需要通过如下的几步操作完成:
    • 第一步:在 Java 程序里面最为基本的核心结构就是*.jar 文件,每一个*.jar 文件里面都可能存在有若干个程序包,而模块实际上也是对于相关程序包的管理,所以模块也需要jar 文件的环境支持,所以要首先进行.jar 文件创建;
    • 第二步:根据jar 文件创建相关的“.jmod”文件,每一个“*.jmod”就属于一个模块的名称(目录)
    • 第三步:根据*.jmod 创建一个新的 JRE 环境(因为这个 JRE 环境里面只包含有所需要的模块)。
  • 本程序中“com.yootk.info.Message”类为外部模块引用的程序类,如果要想打包为模块文件,那么就需要将“mods/com.yootk”目录下所保存的程序打包为"message.jar”文件:
jar --create --file message.jar -C mods/com.yix .
  • 得到了“message.jar”文件之后就可以根据此文件创建“com.yootk.jmod”模块文件
jmod create --class-path message.jar com.yix.jmod
  • 本程序中“com.yootk.test.TestMessage”为测试的主程序,可以将“mods/test”模块打包为“test.jar”,但是需要注意的是,在打包时可以直接设置程序启动的主类,将“test.jar”变为一个可执行 jar 文件```
jar --create --file test.jar --main-class com.yix.test.TestMessage -C mods/test .
  • 根据“test.jar”文件创建“test.jmod”模块文件:
jmod create --class-path test.jar test.jmod
  • 此时所有生成的“*.jmod”文件都保存在了“h:\yootk”根目录之中,为了便于模块的配置,可以在此目录下创建一个“parts”目录(路径 h:\yootk\parts),保存所有的“*.jmod”文件内容;
  • 如果要想让当前的 jmod 可以正常使用,则必须创建有一个新的 JRE 环境,而这个 JRE 环境就属于几个特定模块的支持使用(不像外部提供的 JDK 里面的 JRE 需要有很多的模块,这里面只包含有自己所需要的部分模块即可)
jlink --module-path parts --add-modules java.base,com.yix,test --output muyan
  • 使用新的 JRE 环境(muyan)运行 test 模块
D:\develop\study\pkg\muyan\bin\java --module test

上次编辑于: