第五讲 类的封装和类的继承
主要内容 软件包的创建和使用 Java访问权限修饰词 类的访问权限修饰词 Java中类的层次结构和类的继承 对象的初始化再讨论 |
软件包的创建和使用
什么是软件包(package)
包的组成:由一组类(class)和接口(interface)组成。
Java允许把多个类收集在一起成为一组,称作包(package)。
包的作用:包是Java提供的一种类库的封装机制。专有的名字空间,解决了不同包中的类同名的问题。使自己的任务和其他人提供的代码库相分离。
软件包的建立
从示例程序理解
编译如下程序,查看所编译文件的位置。
package mylib.simple;
public class List{
public List(){
System.out.println("mylib.simple.List");
}
}
结论:
1、包对应着文件系统的目录层次结构。
2、编译生成的字节码文件将置放到包中,即包名所指定的目录中。
软件包的创建
package packagename;
几个要点:
l package语句必须是文件中的第一条语句。
l 用“.”作为分隔符来指明包(目录)的层次。
l 包名由小写字母组成。
l 没有注明放入到某个包中去的类,自动地归在一个无名包中
软件包的使用
l 设置环境变量classpath
l 在Jcreator中添加classpath
l 使用如下两种方法之一:
² 用import加载包中的类:import 包名; 或import 包名.类名;
² 直接用包名.类名去访问类
说明:
² import语句必须放在package语句和类的定义之间。
² 某个类若用到其他类,会优先在所在软件包中查找,继而在classpath指定的路径下查找。
例:创建一个newjw目录,在此新目录下创建如下java文件。
import mylib.simple.List;
class TestList{
public static void main(String[] aa){
new List();
}
}
试用方法二改写并编译执行之。
思考 1. 一个程序的首语句是package a.b.c.d;其意是? 2. 一个程序中可含多个类,它们可分放到不同的软件包吗? 3. 若要使用d:\java07下的软件包,classpath如何设置? 4. 如何用到不同目录下的软件包myclass.lib1中的类? 5. 同一个软件包中的类可否直接使用? 6. 一个类设计成可被到处使用,应声明为public类吗? 7. 一个类用到其他类时,编译时的类查找路径是? |
软件包的操作练习
练习:建立工具包,并使用之。
1. 设计一个P类置入mylib.tools包中,该P类含rint和rintln方法,可实现字符串的输出。
2. 用mylib.tools中的类P,分别输出字符串和数字。
import ;
class TestP{
public static void main(String[] aa){
}
}
3. 创建一个Input类,含有来输入整数或字符串的方法,以使下面的程序能正确编译和执行。
import mylib.tools.Input;
import mylib.tools.P;
class TestInput{
public static void main(String[] aa){
int y=Input.aInt();
P.rintln(y+"");
String s=Input.aString();
P.rintln(s);
}
}
练习 1. 分别构造一个Circle类和Square类,可接受半径(边长),包含求面积的方法。将它们放在myclass.simple包中。 2. 利用上述类,求半径为4.5的圆面积,边长为4.5和6.5的矩形面积。 |
Java访问权限修饰符
决定类成员的访问权限的修饰符有:public 、protected 、private。
权限的设定对于类的封装有着重要的意义。公开需要公开的,隐藏必须隐藏的。这样就让类的继承变得简单。
无权限修饰符的成员
允许本类、同一软件包中的类访问。即享受“包访问权限”。
public成员
public描述的是一个类中可向外公开的信息(属性和方法)。
允许本类、继承类、同一软件包中的类、不同软件包中的类访问。
示例:不同软件包之间一个类访问另一个类的public成员。
package mylib.lib1; //Base.java
public class Base{
public int x=5;
public void print(){
System.out.println("base"+x);//本类访问
}
}
package mylib.lib2; //Derive.java
class Derive {
public static void main(String args[]){
mylib.lib1.Base b = new mylib.lib1.Base();
b.x=5; //不同软件包的类访问
b.print();
}
}
思考 1. 程序编译后,磁盘上新增的目录结构? 2. 在Base类中,可以公开的信息是? 3. public的公开范围? 4. 如果Base类中的成员变量x前无public,会在何环节产生问题? |
private成员
private修饰的成员变量和成员方法都只能在本类中访问。
修饰不希望被其它类访问的变量和方法。有两种限制:
² 其它类中的该类对象不能访问private成员。
² 派生子类时,子类不能继承父类的private成员
class Base1{
private int x=1;
private void print(){
System.out.println("base"+x);
}
void doprint(){
print();
}
}
class Derive1{
public static void main(String args[]){
Base1 b = new Base1();
b.doprint(); //直接调用b.print();试试!
}
}
观察JCreator中的数据视图(ctrl+alt+c),加深对private成员的认识。
假如构造方法是private的,类就不可直接实例化成对象:
class Sundae{
private Sundae(){
System.out.println("Here is a sundae");
}
static Sundae getASundae(){
return new Sundae();
}
}
class TestSundae{
public static void main(String[] aa){
Sundae s=Sundae.getASundae();
}
}
protected成员
这是受保护成员。其修饰的数据和方法对继承它的子类公开。
protected成员允许本类、继承类和同一软件包中的类访问。
包权限访问
class Base1{
protected int x=1;
protected void print(){
System.out.println("base"+x);
}
}
class Derive1{
public static void main(String args[]){
Base1 b = new Base1();
b.print();
}
}
继承类对protected成员的访问
package mylib.simple;//Cookie.java
public class Cookie{
public Cookie(){
System.out.println("Cookie constructor");
}
protected void bite(){System.out.println("bite");}
}
import mylib.simple.Cookie; //Chocolatechip.java
class Chocolatechip extends Cookie{
Chocolatechip(){
System.out.println("Chocolatechip");
}
public static void main(String[] aa){
Chocolatechip c=new Chocolatechip();
c.bite();
}
}
思考 1. 何谓类的封装? 2. 从封装角度比较以上不同的权限修饰? 3. 一个public成员向谁公开信息? 4. 一个protected成员向谁公开信息? 5. 一个private成员向其它类公开信息吗? 6. private有何意义? |
练习:试填表说明不同访问修饰符的访问权限
访问修饰符 |
本类 |
同软件包 |
不同包中子类 |
不同包且无继承 |
public |
|
|
|
|
protected |
|
|
|
|
无修饰词 |
|
|
|
|
private |
|
|
|
|
类的访问权限
无访问修饰符
即为缺省类。可以被同一个软件包中的类访问。
public类
通过import导入(配合classpath的设置),可以被任何其它的类访问。
public class 类名
思考 假如某一程序中定义了一个public类,框架如下: package mylib.abc; public class Abc{…}
1. 该程序应命名为? 2. 在另一个程序中如何能访问到Abc类? 3. 如果该类有显式的构造方法,并允许在其它类中创建该类的对象,构造方法的权限设置应是? |
private类
专用于修饰内部类,内部类常用于处理本类中的事件。
类的继承
类的层次结构
指的是继承关系可以层次地递延下去。
在Java程序中创建的所有类都是类层次结构的部件
每个类都有父类
如果没有使用extends关键字,则Object类就是缺省的父类。
Object类包含在java.lang包中。所有的类都是从这个类继承而来的。
Object类定义和执行了在Java系统需要的所有类的行为。
类的层次结构图
思考
1. 根据层次结构图,每个类都有父类吗? 2. 如果类定义时无extends部分,该类的父类是? 3. 多个子类可以继承自一个父类吗? 4. 一个类可以同时继承多个父类吗? 5. Object类在哪个软件包中? |
类的继承(inheritance)
使用extends关键字实现继承
class SubClass extends SuperClass { ClassBody } |
父类和子类
继承另一个类的类称为子类,被继承的类称为父类。
在Java中一个类只能直接继承一个父类。
继承的意义
一个类能从其它类继承行为与属性。
例:通过对Person类的继承,定义Children类
class Person{
int salary;
void employed(){
System.out.print("Work state:");
if (salary==0) System.out.println("no job");
else System.out.println("job");
}
}
class Children extends Person{
int age;
void printAge(){
System.out.println("Age:"+age);
}
}
class Test{
public static void main(String[] aa){
Children c=new Children();
c.salary=560;
c.age=12;
c.printAge();
c.employed();
}
}
思考 1. 一个类如何去继承另一个类? 2. 示例中Children继承了Persons类的什么? 3. Children的实例化对象与Persons的实例化对象区别在哪里? 4. 若希望父类中的某成员不被子类所继承,如何实现? |
练习:阅读和分析程序,理解继承。
import javax.swing.*;
class Test extends JFrame{
public static void main(String[] aa){
Test t=new Test();
t.setVisible(true);
t.setSize(300,200);
}
}
对象的初始化再讨论
基本的初始化过程
² 初始化时涉及到成员变量和构造方法;
² 实例变量的初始化在构造方法之前。
class Tag{
Tag(int m){
System.out.println("Tag("+m+")");
}
}
class Card{
Tag t1=new Tag(1);
Card(){
System.out.println("Card()");
t3=new Tag(33);
}
Tag t2=new Tag(2);
void f(){
System.out.println("f()");
}
Tag t3=new Tag(3);
}
class TestInit2{
public static void main(String[] aa){
Card t=new Card();
t.f();
}
}
静态变量的初始化
类中的静态成员变量的初始化在编译时进行
静态变量只初始化一次
class Bow{
Bow(int m){
System.out.println("Bow("+m+")");
}
void f(int m){
System.out.println("f("+m+")");
}
}
class Table{
Bow b1=new Bow(1);
Table(){
System.out.println("Table()");
b2.f(1);
}
static Bow b2,b3;
static{
b2=new Bow(2);
b3=new Bow(3);
}
}
class TestInit{
public static void main(String[] aa){
System.out.println("Creating new Table()");
new Table();
System.out.println("Creating new Table()");
new Table();
}
}
思考 1. 对象的初始化在什么时候进行? 2. 静态变量和实例变量的初始化时机? 3. 实例变量和构造方法哪个先初始化? 4. 除了构造方法外,通常的成员方法会自动初始化吗? 5. 类有多个成员变量,这些变量的初始化顺序? |
带有继承时的初始化过程
² 静态变量初始化
² 运行父类的无参数构造方法(按级别高到低)
² 本类实例变量初始化
² 运行本类的构造方法
class GrandParent{
GrandParent(){
System.out.println("GrandParent");
}
}
class Parent extends GrandParent{
Parent(){
System.out.println("Parent");
}
}
class Children extends Parent{
Children(){
System.out.println("Children");
}
public static void main(String[] a){
new Children();
}
}
问题:若类GrandParent类定义如下,程序运行结果?
class GrandParent{
GrandParent(){}
GrandParent(String s){
System.out.println("GrandParent "+s);
}
}
思考 1. 对象的初始化时,父类的什么样的构造方法能自动执行? 2. 父类构造方法的执行时机? |
有关对象初始化的结论
继承时,初始化的顺序(包括构造方法):
主类中的静态成员初始化 | 运行父类的默认构造方法 (按级别高到低的顺序) | 主类中非静态成员初始化 | 调用主类的构造方法 |