# Java模块封装

#

面向对象的核心组成是类和接口,在项目中会利用包进行类的分组管理,包的概念有点像文件系统中的文件夹概念,这样会比较适合代码的更新与组织:

JavaFolder

blog目录中的Tools.java内容为:

package cn.tools.blog;

public class Tools{
    public void GetUI(){
        System.out.println("get user ui!");
    }
    public static void main(String args[]){
       System.out.println("this is class Tools in cn.tools.blog!"); 
    }
}
1
2
3
4
5
6
7
8
9
10

business目录中的Tools.java内容为:

package cn.tools.business;
public class Tools{
    public void GetBusiness(){
        System.out.println("get business logic!");
    }
}
1
2
3
4
5
6

测试主程序test.java为:

//import cn.tools.blog.Tools;
import cn.tools.blog.*;
import cn.tools.business.*;
public class test{
    public static void main(String[] args){
        cn.tools.business.Tools t1 = new cn.tools.business.Tools();
        t1.GetBusiness();
    }
}
1
2
3
4
5
6
7
8
9

注意几个地方:

  1. 如果现有的目录结构是按着包的结构排列的,可以使用javac *.java 来进行按需,且按照依赖顺序编译。
  2. 在编译有包定义的java文件时,像Tools.java这样的文件,如果要按包的定义生成目录,可使用javac -d . *.java。
  3. 在对包名称进行命名时要求所有的字母都得是小写。在包中定义的类要想被其他包中的类使用,需要声明为public类。
  4. 在导入时,使用import packageName.*并不影响性能,这样也只是导入所需的类,不需要的并不导入。
  5. 同时使用import导入不包中的相同类名时,需要使用时加上全类名。

# 静态导入

当一个类中的所有方法都是static时,可以利用JDK1.5提供的静态导入操作。

CommonFunc.java文件:

package cn.tools.math;

public class CommonFunc {
    public static void Add(int a,int b) {
        System.out.println(a+"+"+b+"="+(a+b));
    }
    public static void Sub(int a,int b) {
        System.out.println(a+"-"+b+"="+(a-b));
    }

    public static void Div(int a,int b) {
        System.out.println(a+"/"+b+"="+(a/b));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

测试主类:

import static cn.tools.math.CommonFunc.*;

public class Main {
    public static void main(String[] args) {
        Add(1, 2);
        Sub(6, 5);
        Div(6,3);
    }
}
1
2
3
4
5
6
7
8
9

# jar文件

jar(Java Archive)是Java给出的一种压缩格式文件,可以将很多*.class文件以jar包方式给用户,更方便维护。

有几个参数需要了解:

参数 说明
-c 创建一个jar包
-t 显示jar中内容列表
-x 解压jar包
-u 添加文件到jar包
-f 指定jar包的文件名
-v 输出详细报告
-m 指定MANIFEST.MF文件
-0 生成jar包时不压缩内容
-M 不生成清单文件MANIFEST.MF
-i 为指定jar文件创建索引
-C 在相应的目录下执行命令

它的命令格式为:

jar {c t x u f }[ v m e 0 M i ][-C 目录]文件名...

其中ctxu是必选其一,vme0Mi是可选可不选。来看几个常用命令:

打jar包:

jar -cvf target.jar folder

打jar包,但不生成清单,不压缩:

jar -cvfM0 target.jar cn

解压jar包:

jar -xvf target.jar

往jar包添加文件:

jar -uf target.jar addedFileName

打出jar包后需要在classpath中明确包含该jar包才能使用。

# 常用系统包

包名称 作用
java.lang 基本包,包含像String这样的基础常用类,JDK1.0的时候需要手动导入,后面是自动导入。
java.lang.reflect 反射机制相关,是java.lang的子包。
java.util 工具包,常用的类库和日期操作都在该包。
java.text 文本处理类库。
java.sql 数据库操作包。
java.net 网络编程。
java.io 输入,输出处理。
java.awt 构成抽象窗口工具集(abstract window toolkits),用来构建和管理应用程序的GUI。
javax.swing 用于建立GUI,相对java.awt来说相对轻量。
java.applet 在浏览器端运行java。

在JDK1.9之前,JDK提供包含所有的*.jar文件,比如rt.jar和tools.jar,只要启动了Java虚拟机就需要加载这些类文件。在JDK1.9之后,提供了一个模块化的设计,将原本加载jar文件变成了若干个模块文件,这样根据程序中指定的模块加载相应的类,提高加载速度。

# 访问控制权限

Java中共有四种访问权限:

范围 private default protected public
同一包的同一类 可访问 可访问 可访问 可访问
同一包的不同类 不可访问 可访问 可访问 可访问
不同包的子类 不可访问 不可访问 可访问 可访问
不同包的非子类 不可访问 不可访问 不可访问 可访问

一般属性是以private为主,方法以public为主。

# 构造方法私有化

在类结构中,每次使用new 对象名,就会调用构造方法并实例化新的对象,可利用这点来实现实例化对象的控制。

# 单例设计模式

该模式指的是整个系统中一个类只允许提供一个实例化对象,通过将构造方法私有化来实现,这样可以在系统中提供一个全局实例化对象供用户利用。

# 饿汉单例

public class Singleton {
    private static final Singleton Instance = new Singleton();

    private Singleton() {
    }
    public static Singleton getInstance() {
        return Instance;
    }
    public void printInfo() {
        System.out.println("this is singleton class!");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 懒汉单例


public class Singleton {
    private static Singleton instance;

    private Singleton() {
    }

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

    public void printInfo() {
        System.out.println("this is singleton class!");
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 加锁懒汉

public class Singleton {
    private static Singleton instance;

    private Singleton() {

    }

    public static Singleton getInstance() {
        synchronized (Singleton.class) {
            if (instance == null) {
                instance = new Singleton();
            }
        }
        return instance;
    }

    public void printInfo() {
        System.out.println("this is singleton class!");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 双重加锁懒汉

public class Singleton {
    private static Singleton instance;

    private Singleton() {

    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

    public void printInfo() {
        System.out.println("this is singleton class!");
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 内部静态类


public class Singleton {
    private static Singleton instance;

    private Singleton() {

    }

    private static class InnerClass{
        static final Singleton instance = new Singleton();
    }
    public static Singleton getInstance() {
        return InnerClass.instance;
    }

    public void printInfo() {
        System.out.println("this is singleton class!");
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 模式对比

模式 优点 缺点 适用场景
饿汉 简单方便,不管是否使用了单例对象都会生成单例对象 由于该静态对象是在类加载时生成,会降低应用的启动速度 类对象比较简单,占内存小
懒汉 在需要单例对象时才去构造单例对象,可以提高应用启动速度 线程不安全,多个线程同时获取单例对象时可能会生成多个单例对象 类对象比较复杂,占内存多

加锁懒汉是为了解决懒汉的线程安全问题,双重加锁懒汉是为了在内部已经单例实例化了之后直接获取即可,不用再判断线程安全。

内部静态类则是使用单例对象时才去加载,并且是线程安全的,这样实现简单还能懒加载,线程安全。

# 多例设计模式

多例跟单例的原理基本一致,但是是根据传入参数来返回不同的对象:

public class Multiton {
    private static final Multiton class1 = new Multiton("计算机");
    private static final Multiton class2 = new Multiton("英语");
    private static final Multiton class3 = new Multiton("数学");
    private String infoStore;
    private Multiton(String info) {
        this.infoStore = info;
    }

    public static Multiton getInstance(String info) {
        switch (info) {
        case "english":
            return class2;
        case "math":
            return class3;
        case "cs":
            return class1;
        default:
            return null;
        }
    }

    public String toString() {
        return this.infoStore;
    }

}

public class Main {
    public static void main(String[] args) {
        Multiton m1 = Multiton.getInstance("cs");
        Multiton m2 = Multiton.getInstance("english");
        Multiton m3 = Multiton.getInstance("math");
        System.out.println(m1);
        System.out.println(m2);
        System.out.println(m3);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 枚举

Java从最开始并没有提供枚举,当时很多使用多例来代替枚举,从JDK1.5开始,Java支持了枚举定义:

enum MyColor{
    RED,GREEN,BLUE
}
public class Main {
    public static void main(String[] args) {
        MyColor c1 = MyColor.RED;
        System.out.println(c1);
        for (MyColor color:MyColor.values()) {
            System.out.println(color);
            System.out.println(color.ordinal()+"-"+color.name());
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

枚举本身并不是一种新类型,跟String类一样,枚举对应的类是java.lang.Enum,每一个使用enum定义的类都继承了Enum类。

# 定义枚举结构

枚举也可以定义成员属性,构造方法,普通方法,但是本质上它属于多例,不允许使用public定义构造方法。如果没有无参构造方法,那么定义每个枚举时必须明确传入参数。

enum MyColor{
    RED("red"),BLUE("blue"),GREEN("green");
    private String colorString;
    private MyColor(String color) {
        this.colorString = color;
    }
    @Override
    public String toString() {
        return this.colorString;
    }
}
public class Main {
    public static void main(String[] args) {
        System.out.println(MyColor.RED);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 枚举类实现接口

interface IGetColorInfo{
    public String getColor();
}
enum MyColor implements IGetColorInfo{
    RED("red"),BLUE("blue"),GREEN("green");
    private String colorString;
    private MyColor(String color) {
        this.colorString = color;
    }
    @Override
    public String getColor() {
        return colorString;
    }
}
public class Main {
    public static void main(String[] args) {
        System.out.println(MyColor.RED.getColor());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 枚举定义抽象方法

枚举可直接进行抽象方法的定义,在每一个枚举对象中分别实现抽象方法。

enum MyColor {
    RED("red"){
        @Override
        public String getColor() {
            return "颜色信息:";
        }
    },BLUE("blue"){
        @Override
        public String getColor() {
            return "蓝色";
        }
    },GREEN("green"){
        @Override
        public String getColor() {
            return "绿色";
        }
    };
    private String colorString;
    @Override
    public String toString() {
        return colorString;
    }
    private MyColor(String color) {
        this.colorString = color;
    }
    public abstract String getColor() ;
}
public class Main {
    public static void main(String[] args) {
        System.out.println(MyColor.RED.getColor());
        System.out.println(MyColor.BLUE.getColor());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33