第 4章 类和对象
4.1 抽象与封装
4.2 类和对象的定义
4.3 对象与基本数据类型变量的区别
4.4 数据成员的初始化
4.5 包
4.6 访问权限修饰符第 4章 类和对象(续)
4.7 作用域
4.8 关键字 this
4.9 关键字 static
4.10 类库
4.11 习题
4.1 抽象与封装
数据抽象描述某类对象的公共属性;行为抽象描述某类对象的行为特征。
数据抽象和行为抽象被封装成一个有机的整体。 Java语言通过类来实现封装。
类是数据及其相关操作的封装体,是对对象的抽象和描述,对象是类的实例。
类实现了数据的隐藏。
4.2 类和对象的定义
class Cat //定义猫类
{
int age; //数据成员,描述猫的年龄
int weight; //数据成员,描述猫的重量
void meow() //方法,定义猫的行为(猫叫)
{
System.out.println("Meow...");
}
}
4.2 类和对象的定义(续)
创建对象的一般形式如下:
类名 对象名= new 类名 ()
注意,Java对象只能采用下述表达式创建:
new 类名 ()
而如下形式:
类名 对象名只是声明了一个用来操作该类对象的引用。
4.2 类和对象的定义(续)
访问对象成员的形式如下:
对象名,成员例:
Cat cat1=new Cat();
cat1.age=2;
cat1.weight=5;
cat1.meow();
4.2 类和对象的定义(续)
通过某对象引用访问对象成员前,
必须确保它已经连接到了一个实际的对象。
例:
Cat cat1;
cat1.age=2; //错误
cat1=new Cat();
cat1.weight=5;
4.2 类和对象的定义(续)
如果单独创建一个对象,而没有将创建对象时返回的引用值赋给一个对象引用,这个对象就是一个匿名对象。
例:
new Cat();
注意,匿名对象没有相应的对象引用,程序中的其他语句将无法访问它,也即只能在创建匿名对象的同时访问其成员。
例,new Cat().meow();
4.3 对象与基本数据类型变量的区别
4.3.1 运算
4.3.2 引用传递
4.3.1 运算
1
c2,C a t
基本数据类型赋值
i = j
赋值前,
i
2 j 2
赋值后,
i 2
j
对象类型赋值
c 2 = c 1
赋值前,
c2
c1
赋值后,
c2
c1
c1,C a t
4.3.1 运算(续)
“=”,,==”,,!=”可以作用于对象 。
运算符实际操作的是对象引用 。
例 4-2 对象运算源代码 编译运行
4.3.2 引用传递
对象可以作为参数传递给方法。
传递对象是将对象的引用值传递给形参。
通常,这种传递被称作引用传递。
例 4-3 引用传递源代码 编译运行
4.4 数据成员的初始化
局部变量在使用前必须赋值。
例:
void method()
{
int i;
System.out.println(“i=”+i); //错误
}
Java语言能确保每个类数据成员的初始化。
例 4-4 数据成员的默认值源代码 编译运行
4.4 数据成员的初始化(续)
可以明确地为数据成员指定初值:
– 类定义时指定初值。
– 使用构造方法。
4.4.1类定义时指定初值
class A{}
class B
{
boolean bool=true;
char c='A';
byte b=6;
short s=60;
int i=600;
long l=700;
float f=2.2f;
double d=3.6;
A a=new A();
}
4.4.1类定义时指定初值(续)
class B
{
int i=2;
int k=f(j); //错误
int j=i*3;
int f(int x)
{
return x*x;
}
}
4.4.2 构造方法
构造方法一般用于初始化类的对象。
例 4-5 构造方法
构造方法可以重载。
例 4-6 构造方法重载源代码 编译运行源代码 编译运行
4.4.2 构造方法(续)
不带任何参数的构造方法称为默认构造方法。
如果某个类中没有明确定义任何构造方法,编译器会自动为之生成一个默认构造方法。
4.5 包
4.5.1 在包中添加类
4.5.2 包的命名
4.5.3 包的使用
4.5.4 默认包
4.5.5 JAR压缩工具
4.5.1 在包中添加类
在文件的起始位置使用如下代码可以将某个文件中的类组织到一个指定包中:
package packagename;
包名与文件系统的目录结构一一对应,换句话说,一个包实际上是一个包括类文件的目录。
4.5.1 在包中添加类(续)
//Dog.java
package mypackage;
public class Dog
{
public void bark()
{
System.out.println("Bowwow...");
}
}
4.5.2 包的命名
命名包时,程序员习惯上以自己
Internet域名的倒序作为包名的前缀。
比如,读者拥有的域名是 namexxx.com.cn,如果想建立一个包 mypackage,包名应取:
cn.com.namexxx.mypackage
即在文件的起始位置使用如下代码:
package cn.com.namexxx.mypackage;
4.5.2 包的命名(续)
包可以嵌套。
比如,如果希望在包 mypackage中嵌套一个包
mysubpackage,应使用,.” 号将 mysubpackage连接在 mypackage后面,形式如下:
package cn.com.namexxx.mypackage.mysubpackage;
上述包名的对应目录是
cn\com\namexxx\mypackage\mysubpackage
4.5.2 包的命名(续)
//Wolf.java
package mypackage.animal;
public class Wolf
{
public void howl()
{
System.out.println("Howl...");
}
}
//Tiger.java
package mypackage.animal;
public class Tiger
{
public void growl()
{
System.out.println("Growl...");
}
}
4.5.3 包的使用
必须保证 CLASSPATH中含有包的起始目录。
应使用关键字 import将包导入,否则就必须给出完整的名称。
例:
mypackage.Dog d=
new mypackage.Dog();
4.5.3 包的使用(续)
import mypackage.Dog;
import mypackage.animal.*;
public class UsePackage
{
public static void main(String[] args)
{
Dog d=new Dog();
Wolf w=new Wolf();
Tiger t=new Tiger();
w.howl();
t.growl();
d.bark();
}
}
4.5.3 包的使用(续)
如果一次导入两个或两个以上的包,可能存在使用上的问题。
比如,使用下述语句导入了两个包 pack1,pack2。
import pack1,*;
import pack2.*;
如果包 pack1,pack2中都存在类 MyClass,就可能存在使用上的冲突。当然,如果不使用类 Myclass,程序不会有任何问题,但如果使用类 MyClass,就会引起混淆。编译器将报告错误,要求必须明确指定其名称。如果希望使用包 pack1中的类 MyClass,就应该这样写:
pack1.MyClass m=new pcak1.MyClass();
4.5.4 默认包
如果 Java源代码文件的起始位置没有关键字 package,编译时,类将被组织到当前目录,即默认包中。
同一包中的类可以相互直接使用,无需使用关键字 import导入。
例 4-10 默认包源代码 编译运行
4.5.5 JAR压缩工具
JAR压缩工具可以将众多的类文件封装压缩到一个,jar文件中。
将,jar文件包含到 CLASSPATH中时,必须指定它所在的路径和文件名。
4.6 访问权限修饰符
类访问权限控制:
– public修饰的类不仅可以在同一包中使用,还能在包外使用。不过,必须注意:每个源文件中最多只能有一个 public类,而且该源文件的文件名必须与文件中 public类的类名相同;如果文件中没有 public
类,文件名则可以任意指定。
– 没有用访问权限修饰符修饰的类的访问权限就是默认的,通常称之为 friendly(友好)。在这种情况下,
类具有“包访问”权限,即同一包中的类都能使用它,但包外不能使用。
4.6 访问权限修饰符(续)
成员访问权限控制,
– public修饰的成员能被所有的类访问;
– protected修饰的成员可以被其所属类及所属类的子类、同一个包中所有的其他类访问。
– 默认访问权限的成员可以被同一包中的所有类访问。
– private修饰的成员只能被其所属的类访问。
4.6 访问权限修饰符(续)
类的数据成员一般应声明为 private,并另外为这些私有数据成员添加相应的读取 ( getter) 和设置 ( setter) 方法 。
例 4-11 成员访问权限源代码 编译运行
4.7 作用域
4.7.1 类成员的作用域
4.7.2 局部变量的作用域
4.7.3 对象的存在时间与垃圾回收器
4.7.1 类成员的作用域
类成员的作用域是整个类。因此,类定义中,成员之间的顺序是任意的。
例:
class A
{
void f()
{
i++;
System.out.println("i="+i);
}
private int i=2;
}
4.7.2 局部变量的作用域
局部变量的作用域从它的声明开始延续到包含它的块尾。
例:
void f()
{
int i=10; //变量 i作用域的起始处
if(i>0)
{
...
int j=2; //变量 j作用域的起始处
...
} //变量 j作用域的结束处
} //变量 i作用域的结束处
4.7.2 局部变量的作用域(续)
void f()
{
int i=10;
{
...
int i =2; //错误
...
}
}
4.7.2 局部变量的作用域(续)
void f()
{
int x=0;
int y=0;
for(int i=1;i<10;i++)
x+=i;
for(int i=1;i<10;i++)
y+=i;
}
4.7.3 对象的存在时间与垃圾回收器
连接到某个对象的所有对象引用都退出作用域后,
该对象会依然存在,继续占用内存。不过,程序无法访问它,也即产生了垃圾对象。
为了回收垃圾对象所占内存,Java系统提供了一个被称作垃圾回收器的机制。垃圾回收器能自动监测所有对象,如果发现垃圾对象,便释放其所占内存。
void f()
{
...
{
...
Cat cat=new Cat();
...
} //对象引用 cat退出作用域
}
4.8 关键字 this
关键字 this代表当前对象的引用。
例 4-12 返回当前对象例 4-13 访问被隐藏的数据成员例 4-14 调用构造方法源代码 编译运行源代码 编译运行源代码 编译运行
4.9 关键字 static
用关键字 static修饰的数据成员是类变量(也称静态变量)。
用关键字 static修饰的方法是类方法
(也称静态方法)。
类变量和类方法属于整个类。
4.9.1 类变量
一个类变量只有一份存储空间 。
可以直接通过类名访问类变量 。
例 4-15 类变量的声明及访问源代码 编译运行
4.9.1 类变量(续)
类变量可以采用 static从句初始化 。
类变量的初始化只会在第一次创建该类的对象或访问该类的 static成员时进行 。
例 4-16 类变量的初始化源代码 编译运行
4.9.2 类方法
类方法中没有相应的 this引用。
类方法中不能直接访问非 static成员。
类方法可以通过类名访问。
例 4-17 类方法源代码 编译运行
4.10 类库
java.lang:
包含 Java语言的基础类,比如,Object,String、
StringBuffer,System,Thread,Math,Number、
Character,Boolean,Byte,Short,Integer,Long、
Float,Double等。每个 java程序都会自动导入该包,无需使用关键字 import导入。
java.util:
包含许多工具类,比如,Date,Calendar,Arrays、
Collection,List,Set,ArrayList,LinkedList、
Map,Collections等。
4.10 类库(续)
java.io:
包含用于输入输出数据流和文件的类,比如:
BufferedInputStream、
BufferedOutputStream,Reader,Writer、
File等。
java.applet:
包含支持 applet(小应用程序)的类,比如:
Applet。
4.10 类库(续)
java.awt:
包含绘制几何图形、管理组件布局和创建基于本地资源的组件(所谓重型组件)的类,比如:
Window,Frame,Button,Font,Graphics、
Color,BorderLayout等。
java.awt.event:
包含处理图形程序事件的类,比如:
ActionEvent,TextEvent,MouseEvent、
KeyEvent等。
4.10 类库(续)
javax.swing:
包含轻型图形用户接口组件,比如,JButton、
JPanel,JWindow,JMenu,JApplet等。
java.net:
包含支持网络通信的类,比如,Socket、
ServerSocket,URL等。
4.11 习 题