6.3 封装扩展之包
6.3.1 包的概念
在面向对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组,称为软件包。有点类似于目录。比如:为了更好的管理电脑中的歌曲,一种好的方式就是将相同属性的歌曲放在相同文件
下,也可以对某个文件夹下的音乐进行更详细的分类。
在Java中也引入了包,包是对类、接口等的封装机制的体现,是一种对类或者接口等的很好的组织方式,比如:一个包中的类不想被其他包中的类使用。包还有一个重要的作用:在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。
6.3.2 导入包中的类
Java 中已经提供了很多现成的类供我们使用. 例如Date类:可以使用 java.util.Date 导入 java.util 这个包中的 Date类.
public class Test { public static void main(String[] args) { java.util.Date date = new java.util.Date(); //这样写比较冗余,不建议 // 得到一个毫秒级别的时间戳 System.out.println(date.getTime()); } }
使用 import语句导入包.
import java.util.Date; public class Test { public static void main(String[] args) { Date date = new Date(); //简洁,建议这样写 // 得到一个毫秒级别的时间戳 System.out.println(date.getTime()); } }
如果需要使用 java.util 中的其他类, 可以使用 import java.util.*
import java.util.*; //不是把util包中所有的类都导进来,而是随用随取,用到哪个类就导哪个类进来 public class Test { public static void main(String[] args) { Date date = new Date(); // 得到一个毫秒级别的时间戳 System.out.println(date.getTime()); } }
但是我们更建议显式的指定要导入的类名. 否则还是容易出现冲突的情况.
比如:
import java.util.*; import java.sql.*; public class Test { public static void main(String[] args) { // util 和 sql 中都存在一个 Date 这样的类, 此时就会出现歧义, 编译出错 Date date = new Date(); System.out.println(date.getTime()); } } // 编译出错
在这种情况下需要使用完整的类名
import java.util.*; import java.sql.*; public class Test { public static void main(String[] args) { java.util.Date date = new java.util.Date(); //具体说明 System.out.println(date.getTime()); } }
可以使用import static导入包中静态的方法和字段。(不建议这样写,旁门左道)
import static java.lang.Math.*; //导入Math 类的所有静态方法,用的时候取用 public class Test { public static void main(String[] args) { double x = 30; double y = 40; // 静态导入的方式写起来更方便一些,也就方便一点点 // double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); 不导入时的写法 double result = sqrt(pow(x, 2) + pow(y, 2)); System.out.println(result); } }
注意事项: import 和 C++ 的 #include 差别很大. C++ 必须 #include 来引入其他文件内容, 但是 Java 不需要.
import 只是为了写代码的时候更方便. import 更类似于 C++ 的 namespace 和 using
6.3.3 自定义包
基本规则
- 在文件的最上方加上一个 package 语句指定该代码在哪个包中.
- 包名需要尽量指定成唯一的名字, 通常会用公司的域名的颠倒形式(例如 com.baidu.demo1 ).
- 包名要和代码路径相匹配. 例如创建 com.baidu.demo1 的包, 那么会存在一个对应的路径 com/baidu/demo1 来存储代码.
- 如果一个类没有 package 语句, 则该类被放到一个默认包中.
操作步骤
- 在 IDEA 中先新建一个包: 右键 src -> 新建 -> 包
- 在弹出的对话框中输入包名, 例如 com.baidu.demo1
- 在包中创建类, 右键包名 -> 新建 -> 类, 然后输入类名即可.
- 此时可以看到我们的磁盘上的目录结构已经被 IDEA 自动创建出来了
- 同时我们也看到了, 在新创建的 Test.java 文件的最上方, 就出现了一个 package 语句。
6.3.4 包的访问权限控制举例
如下两段代码分别在两个包中:Computer类位于com.baidu.demo1包中,TestComputer位置com.baidu.demo2包中:
package com.baidu.demo1; class Computer { private String cpu; // cpu private String memory; // 内存 public String screen; // 屏幕 String brand; // 品牌 public Computer(String brand, String cpu, String memory, String screen) { this.brand = brand; this.cpu = cpu; this.memory = memory; this.screen = screen; } public void Boot() { System.out.println("开机~~~"); } public void PowerOff() { System.out.println("关机~~~"); } public void SurfInternet() { System.out.println("上网~~~"); } }
package com.baidu.demo2; import com.baidu.demo1.Computer; public class TestComputer { public static void main(String[] args) { Computer p = new Computer("HW", "i7", "8G", "13*14"); System.out.println(p.screen); // System.out.println(p.cpu); // 报错:cpu是私有的,不允许被其他类访问 // System.out.println(p.brand); // 报错:brand是default,不允许被其他包中的类访问 } }
6.3.5 常见的包
- java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入。
- java.lang.reflect:java 反射编程包;
- java.net:进行网络编程开发包。
- java.sql:进行数据库开发的支持包。
- java.util:是java提供的工具程序包。(集合类等) 非常重要
- java.io:I/O编程开发包。
7. static成员
7.1 再谈学生类
使用前文中介绍的学生类实例化三个对象s1、s2、s3,每个对象都有自己特有的名字、性别,年龄,学分绩点等成员信息,这些信息就是对不同学生来进行描述的,如下所示:
public class Student{ public String name; public String gender; public int age; public double score; public Student(String name,String gender,int age,double score) { this.name = name; this.gender = gender; this.age = age; this.score = score; } public static void main(String[] args) { Student s1 = new Student("Li leilei", "男", 18, 3.8); Student s2 = new Student("Han MeiMei", "女", 19, 4.0); Student s3 = new Student("Jim", "男", 18, 2.6); } }
假设三个同学是同一个班的,那么他们上课肯定是在同一个教室,那既然在同一个教室,那能否给类中再加一个成员变量,来保存同学上课时的教室呢?答案是不行的。
之前在Student类中定义的成员变量,每个对象中都会包含一份(称之为实例变量),因为需要使用这些信息来描述具体的学生。而现在要表示学生上课的教室,这个教室的属性并不需要每个学生对象中都存储一份,而是需要让所
有的学生来共享。此时我们可以定义一个静态成员。
在Java中,被static修饰的成员,称之为静态成员,也可以称为类成员,其不属于某个具体的对象,是所有对象所共享的。
7.2 static修饰成员变量
static修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。
【静态成员变量特性】
- 不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中
- 既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问
- 类变量存储在方法区当中
- 生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁)
public class Student { public String name; public String gender; public int age; public double score; public static String classRoom = "Bit306"; public Student(String name,String gender,int age,double score) { this.name = name; this.gender = gender; this.age = age; this.score = score; } public static void main(String[] args) { // 静态成员变量可以直接通过类名访问 System.out.println(Student.classRoom); //通过类名直接访问 Student s1 = new Student("Li leilei", "男", 18, 3.8); Student s2 = new Student("Han MeiMei", "女", 19, 4.0); Student s3 = new Student("Jim", "男", 18, 2.6); // 也可以通过对象访问:但是classRoom是三个对象共享的 System.out.println(s1.classRoom); System.out.println(s2.classRoom); System.out.println(s3.classRoom); } }