Java+7入门经典 - 5 类 Part 2/2

来源:互联网 发布:软件开发技术发展方向 编辑:程序博客网 时间:2024/06/07 09:25

5.9 包

包package是一个唯一命名的类的集合; 将类集合到包中, 是为了在应用程序中使用预先编写的类时, 避免与类自身引起命名冲突.

通过包名加以限定, 包中的类不会和程序中或者其他包中的类命名冲突;

String类的全名是java.lang.String, 可以使用非限定名称是因为java.lang包中的类在程序代码中已经隐式的import了(default package). 
如果自定义了String类, 需要使用java.lang.String来调用库的类.

5.9.1 对类打包

包语句package statement由关键字package加上包名组成. 

Note 必须是第一条语句, 包语句之前只允许空行或注释; public的类可以在包的外部被访问; 否则只能被包内部的类访问;

1
2
3
4
package Geometry;
public class Line {
    // Details of the class definition
}

>Geometry中的类必须在开头包括同样的包语句, 必须在同一个目录Geometry下.

1) 包与目录结构

名为ClassName的类定义必须存储在名为ClassName.java的文件中[可以在文件中再定义其他类, 但主类名必须与文件名统一];
所有在包PackageName中的类文件必须包含在名为PackageName的目录下. 
Note 可以将编译生成的ClassName.class文件存储在另一个目录下, 但目录名必须与包名一样;

包名可以由多个简单名字组合, 点号分隔.

1
2
package Geometry.Shapes3D;
package Geometry.Shapes2D;

目录结构是Geometry/Shapes3D和Geometry/Shapes2D;

2) 编译包

Note 指向包目录的路径必须显式地设置到CLASSPATH环境变量中, 让编译器知道. 设定CLASSPATH的方法可以是在调用编译器时使用-classpath选项;

Note 指向包目录的路径是包含包目录的路径; e.g. Geometry类存储在C:\Test\Geometry目录下的Geometry包中, 那Geomerty目录的路径是C:\Test而不是C:\Test\Geometry.

1
javac -classpath "C:\Test" Line.java

>编译会影响所有Line类引用的所有类;

>如果路径中包含空格, 必须使用双引号;

如果包内的类互相不相关, 可以使用通配符编译相应的文件;

1
javac -classpath "C:\Test 1" *.java

3) 访问包
编译使用的包的程序时, 1)可以将.class文件存放在包命名的同名目录;

2) 如果包目录包含.class文件, 包路径必须出现在CLASSPATH环境变量中, 或者使用编译器命令行参数 -classpath (会覆盖CLASSPATH).

Note 使用CLASSPATH, 只需要包含对应包的路径, 不必考虑Java的标准包, 编译器解释器能自动找到;

CLASSPATH, e.g. Windows: Control Panel->System->Advanced System Setting->Create the variable CLASSPATH; 可以添加任意路径, 分号隔开; Linux: CLASSPATH取决于所使用的shell程序;

使用JDK时, 使用-classpath的优点是只对当前的编译或执行起作用. 

1
javac –classpath "C:\MySource;C:\MyPackages" MyProgram.java

3)将编译的包变成标准包集合的扩展;

4) 使用扩展

扩展是存储在ext目录中的.jar文件, 默认目录结构 >

>创建归档文件: jar cvf Geometry.jar Geometry\*.class, 将Geometry.java放在ext目录下.

Note 当创建.jar文件时, 要确保在包名对应的目录结构中添加了.class文件.

[More] 工具和实用程序 Tools and Utilities;

5.9.2 将类从包添加到程序中

1
import Geometry.Shapes3D.*; // Include all classes from this package

>导入规范中可以使用通配符; e.g.导入包中所有的类, 而不是目录中所有的文件;

Note 这时程序中的类名称必须与包中的类名不同, 否则会冲突;

1
import Geometry.Shapes3D.Sphere; // Include the class Sphere

>只导入要使用的类, 避免冲突;

Note *只能用来选择包中所有类, 不能用来选择所有的包; e.g. Geometry.*;

5.9.3 程序中的包和名称

包名可以看作类名的前缀; 类的全名其实是Folder.SubFolder.ClassName;

使用全名可以不需要import, 也可以在特定情况下防止名字冲突;

1
Geometry.Shapes3D.Sphere ball = new Geometry.Shapes3D.Sphere(10.01.01.01.0);

5.9.4 导入静态成员

1
2
3
Math.PI //普通使用
import static java.lang.Math.PI;
//可以直接使用PI;

可以使用*号导入类的静态成员: 常量(变量)和方法;

1
import static java.lang.Math.*; // Import all static members of the Math class

5.9.5 标准包

标准类在标准包中:

java.lang 包含一些对于Java 基本的类(比如Math 类), 这些类都在程序中自动可用. 不需要使用import 语句来导入它们.

java.nio.file 包含的类与java.io 包中的类一起支持文件I/O, 是在JDK 7 中新加入的;

java.awt 包含的类支持Java 的图形用户界面(Graphical User Interface-GUI). 通常使用Swing 类, 更加容易而且效果更好.

javax.swing 提供的类支持“Swing”GUI 组件. 不仅仅比同类的java.awt 更灵活, 更容易使用, 也主要由Java 实现并且对本地代码依赖很少;

java.awt.event 包含支持事件处理的类;

java.awt.geom 包含绘制和操作平面几何实体的类;

javax.swing.border 其中的类支持生成围绕Swing 组件的边界;

javax.swing.event 其中的类支持Swing 组件的事件处理;

java.applet 包含的类允许编写Java applet-嵌套在网页中的程序;

java.util 包含的类支持对管理数据集合, 访问日期和时间信息以及分析字符串进行一部分标准操作;

封装了基本数据类型的标准类

Boolean, Character, Byte, Short, Integer, Long, Float, Double;

基本类型与字符串之间的转换

每个类的静态toString()方法; 非静态toString()方法返回类对象的字符串表示形式;

将String对象转换成基本类型: Integer-parseInt(), NumberFormatException异常; parseShort(), parseByte(), parseLong()...
parseFloat(), parseDouble(), parseBoolean()...

基本数据类型和Boolean类定义了静态方法valueOf(), 将字符串转换成类类型的对象; 对Boolean类型来说, 忽略大小写, 如果字符串不等于true则valueOf()返回false;

将对象转换成值

每个封装基本数据值的类定义了classValue()方法, class代表对应的基本类型名, 该方法将对象封装的值以对应的基本类型返回;

e.g. 一个Double类型对象, 封装了3.1415, number.doubleValue返回double类型的值3.1415;

基本常量

static final的MAX_VALUE和MIN_VALUE;

浮点型有POSITIVE_IFINITY, NEGATIVE_INFINITY和NaN(Not a Number, 非数字, 0/0), 可以用进行比较; 方法有isInfinte(), isNaN();

Note 及时不是被零除也可能出现无限值; 对于计算结果太大无法表示的情况会产生POS和NEGATIVE_INFINITY;

基本类型数值的自动装箱

装箱转换 boxing conversion, 自动装箱 autoboxing;

将基本类型的值传递给一个方法, 但是参数是一个指向对象的引用, 当情况允许时, 编译器会提供基本类型数值到对于类类型的自动转换; e.g. int -> Integer;

对于封装了基本类型的类的对象, 当需要将指向对象的引用转换成对象封装的值, 编译器会插入拆箱转换 unboxing conversion;

5.10 类成员的访问控制

静态类方法可以引用静态成员, 非静态方法可以指向类的成员; 可访问度还取决于类成员设定的访问属性, 包, 类是否public.

5.10.1 使用访问属性

同一个包中的类能直接访问其他的类名: 声明变量或设定参数类型; 成员变量和方法的可访问性由访问属性access attribute控制; 只有类为public时, 类名才可以被其他包的类访问;

类成员的访问属性: 

无访问属性: 允许同一个包中任意类的方法访问;

public: 只要类声明为public, 允许任意位置的类方法访问; 

private: 只允许类内部的方法访问, 完全不能在类的外部访问;

protected: 允许同一个包中任意类的方法访问并且允许任意位置的子类访问;

包内:

包外:

>Class1在另一个包中的子类无法访问没有访问属性的成员;

5.10.2 设定访问属性

public, protected, private, 按顺序排列有助于代码阅读;

当成员变量作为private时, 
获取成员的值: 可以使用取值accessor方法: public type getMember() { return member; }
修改成员的值: 可以使用赋值mutator方法: public oid setMember(type value) { member = value; }, 赋值方法可以进行新值有效性检测;

5.10.3 选择访问属性

对于面向对象来说, public类中的成员变量一般为private; 使用access方法获取成员变量;

特殊情况:

-对于包中非public的类, 无法从包外访问, 这时最好允许包中的其他类能直接访问其中的数据成员;
-对于final的数据成员, constant值可能在包外也有用, 可以设置成public;
-类中的方法可能只想被同一类的其他方法使用, 这种情况应该设为private;
-对于标准类比如Math, 作为数据值的容器, 应该将所有内容设置为pubic;

使用包和访问属性

Note 包中每个类的源文件和.class文件必须放在名称一样的包下[路径可以不一样].

在编译时要确保源文件和class文件的目录路径在CLASSPATH变量中, 或者-classpath设置目录;

源文件开头的包语句定义了类所属的包;

e.g. TryPackage目录下的TryPackage.java, 对于Windows系统如果路径是C:\Packages\Geometry; 引用和导入的类在Geometry下;
编译: TryPackage.java在当前目录下;

1
javac –classpath "C:\Packages" TryPackage.java

执行: .代表当前目录

1
java –classpath ".;C:\Packages" TryPackage

二维数组定义:

1
2
double[][] coords = { {1.0, 0.0}, {6.0, 0.0}, {6.0, 10.0},
        {10.0,10.0}, {10.0, -14.0}, {8.0, -14.0}};

数组长度coords.length为6;

Note 可以创建一个二维数组, 每行的元素数目不同. e.g. double[][] coords = { {1.0, 2, 0.0}, {6.0, 0.0}};

编译包下的类, 将.class生成在包下:

1
javac -classpath "C:\Packages" Geometry/*.java

5.11 嵌套类

将一个类的定义放到另一个类中, 这个内部类被称为嵌套类nested class; 嵌套类也可以在自身内部嵌套另一个类;

1
2
3
4
5
6
7
public class Outside {
// Nested class
    public class Inside {
    // Details of Inside class...
    }
// More members of Outside class...
}

>Inside被定义成public, 所以在Outside外部也能访问Inside类;

包围类也称为顶级类top level class. 顶级类自身不是嵌套类; 想要创建嵌套类的对象, 必须使用包围类的名称作为限定名来引用嵌套类;

1
Outside.Inside inner = outer.new Inside(); // Define a nested class object

在Outside的非静态成员方法中, 可以直接使用Inside类名, 编译器自动使用了this作为限定名.

在Outside内部: Inside inner = new Inside(); 等于this.Inside inner = this.new Inside();

Note 包围类的静态方法不可以创建非静态嵌套类对象, 直接创建的非静态嵌套类的对象, 会在包围类的有效范围之外创建出嵌套类对象, 这是非法的策略; [失去控制]

5.1.11.1 静态嵌套类

嵌套类对象独立于包围类对象;

1
2
3
4
5
6
7
8
9
10
public class Outside {
    public static class Skinside {
    // Details of Skinside
    }
    // Nested class
    public class Inside {
    // Details of Inside class...
    }
// More members of Outside class...
}

>Skinside类是静态的, 可以独立于任何Outside类对象声明嵌套类对象;

1
Outside.Skinside example = new Outside.Skinside();

>静态嵌套类的名称存在于外部类的上下文中, 嵌套类名由包围类类名限定;

Note 静态嵌套类能拥有静态成员, 非静态嵌套类不能拥有;

如果查看编译器产生的.class文件, 嵌套类有自己的名为Outside$Inside的class文件; 嵌套类的类名由包括它的外部类的类名限定;

5.11.2 使用非静态嵌套类

将原本静态嵌套类中的静态数据成员搬到包围类中处理; 

5.11.3 使用非顶级类的嵌套类

可以在包含内部类的顶级类的外部创建内部类的对象;

static的Rabbit

1
2
MagicHat oldHat = new MagicHat("Old hat"); // New hat object
MagicHat.Rabbit rabbit = new MagicHat.Rabbit(); // Create rabbit object

>使用顶级类的类名作为限定符;

非statici的Rabbit

1
2
MagicHat oldHat = new MagicHat("Old hat"); // New hat object
MagicHat.Rabbit rabbit = oldHat.new Rabbit(); // Create rabbit object

Note 构造函数调用时顶级类的使用: oldHat.new Rabbit(); 对象名限定符在new之前, 表示在对象oldHat的上下文中创建rabbit, 在rabbit中使用的顶级类成员和oldHat绑定;

5.11.4 本地嵌套

在方法中定义类: 本地嵌套类 local nested class, 或称为本地内部类 local inner class; 非静态嵌套类通常被称为内部类 inner class;

当方法内部的计算需要使用特殊的, 在其他地方不需要的类时, 使用本地内部类; e.g. 监听用户与应用程序之间交互事件的监听器;

本地内部类能引用在类定义出现的方法中声明的变量, 但是这些变量必须是final的;

5.12 小结

类定义: 类定义设定了作为类成员的变量和方法;

类文件: 每个类都必须存储到一个与类同名的文件中, 必须使用扩展名.java;

类变量: 使用关键字static 声明类变量, 每个类变量的实例都会被所有类对象共享;

实例变量: 类的每个对象都有自己的实例变量—它们在类中声明, 没有使用关键字static;

静态方法: 对于设定为static 的方法, 即使不存在类对象也可以调用, 但是static 方法不能引用实例变量;

非静态方法: 没有使用static 进行设定的方法可以直接访问类中的所有变量;

递归方法: 自己调用自己的方法;

类成员访问: 类成员的访问性取决于对它们各自设置的访问属性. 访问属性分为public private protected 或者无属性;

包: 类可以被聚集到一个包中; 如果要从包的外部访问包中的类, 那么这些类必须使用关键字public 进行声明;

包成员: 为了将类设计成包的成员, 需要在包含类定义的文件的开头使用一条包语句;

使用包成员: 为了将包中的类添加到文件中, 需要在文件中的任何包语句之后立即使用import语句;

嵌套类: 嵌套类是指在另一个类定义的内部定义的类. 嵌套类对象只有在外部类对象的上下文中才能存在;

创建静态嵌套类对象: 可以独立地创建静态嵌套类对象, 但是静态嵌套类的类名必须由外部类的类名进行限定;

---5 End---


原创粉丝点击