初识Java:面向对象程序设计基础入门(4)封装性,包,修饰词

导引

面向对象程序设计的三大特性:继承性,封装性,多态性。
阅读本文前,依然需要思考这些问题,并带着它们阅读:
什么是封装性?
封装好的软件包对于编程有什么意义?
Java中各类修饰词分别是什么含义,起何种限制作用?

1.包

具有相关性的类、接口,可以封装进包package。包是第一层封装。
在cmd下编译Java源程序时,编译含有包声明语句的Java源程序文件的格式是:

javac -d ;路径 Java源程序文件名

其中,若根路径是当前路径,则路径名可以填写“.”。
在这里插入图片描述
在此路径下创建.txt文件并且编写内容如下:

在这里插入图片描述

package head;

public class heads{
  public static void main(String[] args){
    System.out.println("Heads");
	 }
}

下面在cmd下进行操作:
在这里插入图片描述
这表示heads.java被编译成功。此时D:目录下出现了:
在这里插入图片描述
由于源文件指引了package head,立刻就出现了文件夹head。这一层文件夹就是系统实现包封装的表现。
在这里插入图片描述
这就实现了一个包的编译,但是对于这个位于包当中的源文件,我们却不能执行。不论是进入.class所在位置,还是采用绝对地址来使用java指令,都不能有效地直接运行这个源文件。

我们用两种技术来实验package在系统中的表现。
1.IDE环境下
在这里插入图片描述
我们先把两个包nothing_inside_package & whatever都放在同一个项目的src文件夹当中。
在这里插入图片描述
在这里插入图片描述
这个程序运用了import语句直接完成了包间共享。import语句有三种用法:

import 包名.*;
import 包名.类型名;
import static 包名.类型名.静态成员方法;

其中第一个语句表示导入包里一切类、接口、枚举。
一旦把此包移除出同一个java project文件夹,import语句即报错。
工程中,我们可以先把导入包放入源程序所在包同级目录,然后直接用import导入。

2.不借助IDE
我们引入一个例子。
下面的三个文件都选择E:\作为workplace。
第一个源文件:J_Employee.java
地址:E:\

package cn.edu.tsinghua.universityOrganization;

public class J_Employee {
	public int m_workYear;
	public J_Employee()
	{
		m_workYear=1;
	}
	public void mb_printInfo()
	{
		System.out.println("该职工的工作年限为"+m_workYear);
	}
}

第二个源文件:J_Teacher.java
地址:E:\

package cn.edu.tsinghua.universityOrganization;

import cn.edu.tsinghua.universityOrganization.*;

public class J_Teacher extends J_Employee{
	public int m_classHour;
	public J_Teacher()
	{
		super();
		m_classHour=96;
	}
	public void mb_printInfo()
	{
		System.out.println("该员工的工作年限为:"+m_workYear);
		System.out.println("该教师的授课时长为:"+m_classHour);
	}
}

第三个源文件:J_University.java
地址:E:\

import cn.edu.tsinghua.universityOrganization.J_Employee;
import cn.edu.tsinghua.universityOrganization.J_Teacher;

public class J_University {
	public static void main(String[] args)
	{
		J_Employee a = new J_Employee();
		a.mb_printInfo();
		a=new J_Teacher();
		a.mb_printInfo();
	}
}

在初环境下直接进行java编译解释,package 包名声明语句的意义在于:编译指令执行到此处(javac指令),将会从当前目录出发,在目标地址的文件夹内建立当前类的源文件.class,若文件夹逐级并不存在,先补充建立所描述的文件夹。
所以采用javac指令编译J_Employee.java、 J_Teacher.java 时,java virtual machine 会在从当前路径(根路径)出发建立package 语句所指定的包。比如上述两个源文件的包声明为:

package cn.edu.tsinghua.universityOrganization;

这说明从当前根目录B:\出发,将会建立:
E:\cn\edu\tsinghua\universityOrganization 的逐级文件夹,最终随着编译:
在这里插入图片描述
回到根目录,第三个源文件J_University.java 是停留在根目录的。
编译J_University.java,

import cn.edu.tsinghua.universityOrganization.J_Employee;
import cn.edu.tsinghua.universityOrganization.J_Teacher; 

import语句指导java virtual machine 从根目录出发,前往cn.edu.tsinghua.universityOrganization 逐级寻找目标class。最终,将刚刚建立起来的源文件加入到当前代码的编译当中。
在DOS上进行的操作如下:
在这里插入图片描述
而在IDE环境下,上述的这些物理上的过程都变成不可视的。

2.封装性

访问是一个各种高级语言都会涉及的名词。在C语言当中,调用函数也可以说是对于函数内容的一次访问。
若类修饰词并不包含:public protected default private 这四个词,那么系统默认填入default(默认)。不同的修饰词规定了可以涉及的访问范围:
在这里插入图片描述
这四个修饰词对于成员方法、成员域都是一样的作用原理。
正确利用访问控制模式的方法是,先确定允许访问该成员的类有哪些,这些类与当前类是否是父子,是否在同一个类当中。
构造方法一般设置为公共模式,将有特殊限制的成员域的访问控制方式设置成私有模式
这时,可以添加两个成员方法分别来读取和设置这个具有特殊限制的成员域的值。其中一个往往被称为get成员方法,另一个被称为set成员方法,分别用于读取private成员域和设置private成员域值。

public class J_Month {
	private int m_month = 1;
	public int mb_getMonth()
	{
		return m_month;
	}
	public int mb_setMonth(int m)
	{
		if(m<1)m_month++;
		else if(m>12)m_month=12;
		else m_month=m;
		return m_month;
	}
}

m_month变量是一个private变量,若要访问,仅有同类内的成员方法才能完成。外界访问m_month只能借助get和set方法的帮助。

除去上面,还有以下一些修饰词用以修饰类:

1.abstract

abstract 可以修饰类和成员方法。
abstract class 抽象类表示特殊的一种类,这样的类存在构造方法,理应可以实例化而人为地规定其不允许直接调用构造方法实例化。虽然不能创建abstract类的实例,然而可以创建一个变量,其类型是一个抽象类,并让它指向具体子类的一个实例。
我们在前面进行过这样的实验:
J_Employee.java

package J_abs;

public class J_Employee {
	int workHour;
	public J_Employee()
	{
		workHour = 1;
	}
	public void mb_print()
	{
		System.out.println("This Employee's work hour is:"+workHour);
	}
}

J_Teacher.java

   package J_abs;

public class J_Teacher extends J_Employee {
	int classHour;
	public J_Teacher()
	{
		super();
		classHour = 96;
	}
	public static void main(String[] args)
	{
		J_Employee tom= new J_Employee();
		tom.mb_print();
	}
}

这里指出,J_Employee tom 变量显然能够接收子类J_Teacher()构造方法构造的实例对象的初始化。
现在我们改变一下程序,展示abstract修饰词的特性:
将父类J_Employee设置为abstract 抽象类。
J_Employee.java

package J_abs;

public abstract class J_Employee {
	int workHour;
	public J_Employee()
	{
		workHour = 1;
	}
	public void mb_print()
	{
		System.out.println("This Employee's work hour is:"+workHour);
	}
}

J_Teacher.java

package J_abs;

public class J_Teacher extends J_Employee {
	int classHour;
	public J_Teacher()
	{
		super();
		classHour = 96;
	}
	public static void main(String[] args)
	{
		J_Employee tom= new J_Teacher();
		tom.mb_print();
	}
}

运行程序仍然是一样的结果。这表明abstract限制了当前类的直接构造,但是鼓励使用继承性间接地创建子类实例对象。
抽象成员方法不能被直接调用,不能声明方法体。例如:

abstract class J_Shape
{
	public int m_shapeID=0;
	public abstract double mb_getArea();
}

这个类表示抽象类“形状”。诸如长方形,正方形等类都可以作为该抽象类的子类。
如果抽象类型的子类型不是抽象类型,则要求在该子类型当中定义覆盖父类抽象类型的全部抽象方法。
空的子类J_Triangle 由于没有声明所继承的抽象成员方法,被系统标识报错
abstract 不能修饰成员域。

2.static

static表示静态属性。
除了内部类,类不能拥有静态属性。
类的构造方法不能拥有静态属性,成员域与成员方法都可以拥有静态属性。
静态的成员域有两个特性:
1.实例对象若拥有静态成员域,一经赋值不鼓励再更改(但不禁止);
在这里插入图片描述
2.静态成员域(也包括静态成员方法)可以透过类本身作为对象调用,比如J_Book.mb_print()
像这样调用的静态成员域,往往用于反映整个类的实时特性,比如
J_Book.m_bookNumber 初始化为0,表示当前的书的总数
J_Book() 构造方法定义为:

public J_Book()
{
	m_bookNumber++;
}

也就是说,每次实例化J_Book,新增一本书,那么上述静态变量会增加1.
访问作:
J_Book.m_bookNumber 变量就反应了书的当前数目。
若类拥有静态成员域,实例化后每个实例对象拥有一套彼此独立的不具有静态属性的成员域。

3.final

final 表示类没有子类。
final 成员域若同时具有静态属性,只能定义赋值,无法重新赋值;若没有静态属性,可以在定义或构造方法中赋值,但一样无法重新赋值。

猜你喜欢

转载自blog.csdn.net/Quaint_Senator/article/details/88186949
今日推荐