第5章、包及访问控制权限
5.1 包的定义
在Java程序中的包主要用于将不同功能的文件进行分割。在之前的代码开发中,所有编译后的*.class文件都保存在同一个目录中,这样一来就会带来一个问题:如果出现了同名文件,就会发生文件的覆盖问题,因为在同一个目录中不允许有重名文件。而要想解决同名文件冲突的问题,就必须设置不同的目录,因为在不同的目录下可以有重名文件。所谓的包实际上指的就是文件夹,即目录。在 Java中使用package关键字来定义包,此语句必须写在 *.java文件的首行。
-
定义包:
package com.yootk.demo ; // 定义程序所在包,此语句必须放在首行 public class Hello { public static void main(String args[]) { System.out.println("Hello World !") ; } }
表示把Hello程序定义在“com.yootk.demo”包中(在定义包时出现 “.” 表示子目录),在进行编译时,就会使生成的Hello.class保存在指定的包下,即目录下。此时Hello.class文件就保存在com/yootk/demo目录下。
-
打包编译:javac -d . Hello.java
- " -d ":生成目录,根据package的定义生成
- “ . ”:设置保存的路劲,如果为 “ . ” 则表示在当前所在路径下生成
-
解释程序:java com.yooth.Hello
- 在解释程序的时候不要进入到包里,应该在包外面输入类的完整名称(包.类)
-
开发中的程序都要有包
为了方便程序管理,所有的类都一定要放在包中,而完整的类名称永远都是 “ 包.类 ” ,同时没有包的类不应该在开发中出现。
5.2 包的导入
不同包之间的互相访问,需要先将包导入到该程序中,使用关键字“import”。
-
在当前目录下定义了个test1.Message的类:
package test1; // 定义程序所在包,此语句必须放在首行 public class Message { public static void main(String args[]) { System.out.println("Hello World !") ; } }
定义一个test2.TestMessag的类
package test2; import test1.Message; // 导入所需要的类 public class TestMessage { public static void main(String args[]) { Message msg = new Message(); // 实例化对象 msg.print(); // 调用方法 } }
本程序由于要使用到 Message类,所以首先使用了import语句根据类的名称(包.类) 进行导人,导入后直接实例化 Message类对象,然后调用print()方法。
-
public class 与 class 声明类的区别:使用 public class 声明的类可以在包外访问,例如上面代码,把Message类改为用class声明,则会在导入的时候报错,因为用class声明的类对包外是不可访问的。
- public class:类名必须与文件名称保持一致,在一个*.Java文件中只能有一个由 public class 声明的类。
- class:类名可以与文件名不一致,并且在一个*.Java文件中可以有多个由 class 声明的类。如果一个类由class声明,则它只能被本包所访问。
-
导入一个包中的多个类:import 包.*
-
在导入多个包之后,如果出现了导入了不同包但同名的类,在调用该类的时候要再前面加上包名:包名.类名。否则会报错
5.3 系统常用包
Java本身提供了大量的程序开发包,其中常见的有:
5.5访问权限控制
4种访问控制权限:
-
protected:
-
定义com.yootk.demoa.A类:
package com.yootk.demoa ; public class A { protected String info = "Hello" ; // 使用protected权限定义 }
-
定义com.yootk.demob.B类继承A类:
package com.yootk.demob; import com.yootk.demoa.A; public class B extends A { // 继承A类,是A不同包的子类 public void print() { System.out.println("A类的info = " + super.info); // 直接访问父类中的protected属性info } }
-
测试代码:
package com.yootk.test; import com.yootk.demob.B; public class Test { public static void main(String args[]) { new B().print(); } }
由于B类是A类的子类,所以不同包的B类可以访问A类中的protected属性
-
5.6 命名规范
- 类名:每个单词的首字母大写
- 变量名:第一个单词的首字母小写,之后每个单词的首字母大写
- 方法名:第一个单词的首字母小写,之后每个单词的首字母大写
- 常量名:每个字母大写
- 包名:每个字母小写
5.7 单例设计模式(Singleton)
设计永远只有一个实例化对象的类:
-
将构造方法进行private声明
class Singleton { // 定义一个类 private Singleton() { // ***构造方法私有化*** } public void print() { System.out.println("Hello World ."); } } public class TestDemo { public static void main(String args[]) { Singleton inst = null; // 声明对象 inst = new Singleton(); // 错误:The constructor Singleton() is not visible inst.print(); // 调用方法 } }
程序发生编译错误,因为构造方法被私有化了,无法在类的外部调用。
-
既然在类外无法调用构造,那么就在本类中调用构造方法实例化对象。
class Singleton { // 定义一个类 Singleton instance = new Singleton() ; // ***在内部实例化本类对象*** private Singleton() { // 构造方法私有化 } public void print() { System.out.println("Hello World ."); } }
-
由于类外没法实例化Singleton对象,也就没法调用其属性 instance ,所以使用static关键字声明属性 instance 使它能直接使用类名调用
class Singleton { // 定义一个类 static Singleton instance = new Singleton() ; // ***可以由类名称直接访问*** private Singleton() { // 构造方法私有化 } public void print() { System.out.println("Hello World ."); } } public class TestDemo { public static void main(String args[]) { Singleton inst = null; // 声明对象 inst = Singleton.instance; // 利用“类.static属性”方式取得实例化对象 inst.print(); // 调用方法 } }
-
类中的所有属性都应该被封装,说有 instance 属性也应该被封装,所以需要getter方法来获得 instance 属性。
class Singleton { // 定义一个类 private static Singleton instance = new Singleton() ; // ***封装属性*** private Singleton() { // 构造方法私有化 } public void print() { System.out.println("Hello World ."); } public static Singleton getInstance() { // ***取得本类对象*** return instance; } } public class TestDemo { public static void main(String args[]) { Singleton inst = null; // 声明对象 inst = Singleton.getInstance(); // 利用“类.static方法()”取得实例化对象 inst.print(); // 调用方法 } }
-
但这样的程序也有问题:
class Singleton { // 定义一个类 private static Singleton instance = new Singleton() ; private Singleton() { // 构造方法私有化 } public void print() { System.out.println("Hello World ."); } public static Singleton getInstance() { // 取得本类对象 instance = new Singleton(); // ***重新实例化对象*** return instance; } }
这样操作语法上没错,但这样做就可以创建多个对象了。
-
可以在定义 instance 时加上关键字 final
class Singleton { // 定义一个类 private final static Singleton instance = new Singleton() ; // ***final关键字*** private Singleton() { // 构造方法私有化 } public void print() { System.out.println("Hello World ."); } public static Singleton getInstance() { // 取得本类对象 return instance; } } public class TestDemo { public static void main(String args[]) { Singleton inst = null; // 声明对象 inst = Singleton.getInstance(); // 利用“类.static方法()”取得实例化对象 inst.print(); // 调用方法 } }
这样子,在使用Singleton类时,不管代码如何操作,也永远只会存在唯一的一个Singleton类的实例化对象,而这样的代码,在设计模式上就被称为单例设计模式。
-
总结:
-
首先私有化(private)构造方法
-
然后在本类中实例化一个对象:
private final static Singleton instance = new Singleton();
-
加上getter方法以获取 instance 属性
-
5.8 多例设计模式
单例设计模式设计的类只能拥有一个实例化对象。而多例设计模式是设计只能拥有指定个数对象的类。(比如星期1-7,男女,三原色红绿蓝等)
不管是单例设计模式还是多例设计模式,有一个核心不动摇:即私有化构造方法
package com.yootk.demo;
class Sex {
private String title;
private static final Sex MALE = new Sex("男");
private static final Sex FEMALE = new Sex("女");
private Sex(String title) { // 构造私有化了
this.title = title;
}
public String toString() {
return this.title;
}
public static Sex getInstance(String ch) { // 返回实例化对象
switch (ch) {
case "man":
return MALE;
case "woman":
return FEMALE;
default:
return null;
}
}
}
public class TestDemo {
public static void main(String args[]) {
Sex sex = Sex.getInstance(2);
System.out.println(sex);
}
}
本章小结
- Java中使用包可以实现多人协作的开发模式,避免类名称重复的麻烦。
- 在Java中使用 package关键字来将一个类放入一个包中。
- 在Java中使用 import语句,可以导入一个已有的包。
- 如果在一个程序中导入了不同包的同名类,在使用时一定要明确地写出“包.类名称”。
- Java中的访问控制权限分为4种: private、default 、protected、public;
- 单例设计模式的核心意义是整个类在运行过程中只能存在一个实例化对象,并且构造方法必须用private封装。