第四讲类的定义和使用
主要内容 面向对象程序技术基础 类的定义和对象创建 静态变量和静态方法 类的构造方法及其意义 初始化问题的讨论 |
面向对象程序技术基础
什么是面向对象程序设计?
简单的说,面向对象编程(Object Oriented Programming,简称OOP)描述的是对象之间的相互作用。
面向对象与面向过程的对照:
面向过程 |
面向对象 |
先确定算法,再确定数据结构 |
先确定数据结构,再确定运算 |
建立数据结构存放数据,定义方法(函数)来操作数据 |
构造一个对象模型,将数据与方法组织在一起 |
所以,对象是携带数据并可提供服务的。
对象和对象的特征
我们可以把现实世界的事物抽象成对象:
² 把现实世界对象的状态等属性保存在软件对象的变量中
² 现实世界对象的行为通过软件对象的方法来实现
所以,对象一般都有两个特征:属性和行为。
|
什么是类?
类是一个模板
把相似的对象划归成一个类。
需用对象,首先要定义类,类是产生对象的模板。
对象可提供的服务都是由类所赋予的。
所以,定义一个类要定义该类对象的属性和行为(即变量和方法)。
类创建对象
类是创建对象的模板,对象是类的实例。
Light lt=new Light();
lt.degree=40;
lt.on();
思考 用面向对象的方法求圆面积和周长,需如何定义类? |
类的定义和对象创建
从程序设计的角度看,类是面向对象程序中最基本的程序单元。
类的定义
例程阅读和理解
class Person{
int sex;
int salary;
void employed(){
System.out.print("Work state:");
if (salary==0) System.out.println("no job");
else System.out.println("job");
}
}
class Test{
public static void main(String[] aa){
Person ps=new Person();
ps.salary=300;
ps.employed();
ps.salary=0;
ps.employed();
}
}
得到认识:
² 用类名称可声明对象变量,所以类的本质是一种数据类型Person ps
² 类中可包含常数(final定义的符号常数)
² 类中包含有方法,可提供预设的服务
² 可以用运算符new创建对象实体new Person()
² 类中的方法可以接受参数,也可以有返回值
类的定义格式
[类修饰符] class类名 [extends 父类名]{ 变量定义 方法定义 } |
extends的含意:表示该类由父类继承而来
一个类可以表现成如下三种形态:
² 只有变量的类
² 只有方法的类
² 兼有变量和方法的类
关于变量的说明
封装在类中的变量也称为域(field),可以是一般的数据类型,也可以是对象类型。但不可是本类的对象。
方法的定义格式
[方法修饰符]返回值类型 方法名(参数){ 方法体 [return exp] } |
注意:
1) 如果无返回值,类型设为void
2) 可通过return exp语句返回方法的值
3) 返回的值应与设置的返回值类型一致。
练习:
1、 造一个矩形类Rectangle,包含求矩形周长和面积的方法。
2、 构造一个圆类Circle,包含求圆周长和面积的方法。
思考 1. 定义一个类应考虑哪些因素? 2. 类体的组成元素是什么? 3. 程序可通过载入import语句用到程序外的类吗? 4. 解析Math.PI、JOptionPane.showInputDialog(…) |
对象的创建和对象引用
对象的创建
new 类名([参数]) |
操作符new创建了一个指定类的对象,并为该对象开辟内存。
参数传递给构造方法(后述)
对象引用
对象变量的名即为对象引用。
Person ps;———————声明对象引用
ps=new Person();————创建对象,并将对象与对象引用联结
如需给对象提供数据,获取对象的服务,就必须声明对象引用,并将对象引用与对象相关联。
通过对象引用给对象提供数据
对象名.成员变量名 |
ps.sex=0;
ps.saraly=700;
访问(调用)对象的成员方法
对象名.方法名(参数) |
注意:在调用时注意参数的匹配
思考 1. new后的类名必须在本程序中定义吗? 2. 理解String s=new String("Hello"); 3. 试解读System.out.println(s.length()); |
练习 1、实例化圆类,求半径为3.5的圆周长和面积。 2、实例化矩形类,通过调用类的方法求长10,宽4的矩形周长和面积。 |
对象引用可以重定向
例:分析程序的运行结果
class ReferenceTest{
public static void main(String[] aa){
Person p1=new Person();
Person p2=new Person();
p1.salary=1;
p2.salary=2;
System.out.println("\nperson1.salary="+p1.salary);
System.out.println("person2.salary="+p2.salary);
p1=p2;
System.out.println("\nperson1.salary="+p1.salary);
System.out.println("person2.salary="+p2.salary);
p1.salary=8;
System.out.println("\nperson1.salary="+p1.salary);
System.out.println("person2.salary="+p2.salary);
}
}
思考 1. 解读语句Person p1,p2; 2. 解读语句p1=p2=new Person(); 3. 如果用上面两个语句替代程序中蓝色字体的两语句,结果将是怎样? 4. 对象如没有一个对象引用与之关联,可能会引起哪些问题? 5. 对象引用若没与对象关联,可否由对象引用去操纵对象所属类的数据和方法? |
对象可作为方法的参数
阅读程序,分析结果
class Person1{
int salary;
void setSalary(Person1 p){
p.salary=2;
}
public static void main(String[] a){
Person1 p1=new Person1();
Person1 p2=new Person1();
p1.salary=1;
System.out.println(p1.salary+"\t"+p2.salary);
p1.setSalary(p1);
System.out.println(p1.salary+"\t"+p2.salary);
p1.setSalary(p2);
System.out.println(p1.salary+"\t"+p2.salary);
}
}
在Java中,方法中的参数如果是基本数据类型,则为“传值”方法。如参数是复合类型的数据,则为“传址”的方式。
当对象作为方法中的参数时,通过参数传递的不是对象本身,是对象的引用。
思考 1. 对以上示例程序进行结果分析,对象中的数值型变量若没赋初值,其初值为什么? 2. 调用对象的方法时,如果参数是对象,则传递的是什么? 3. 如果在setSalary体内,将p.salary=2语句改写成salary=2语句,情况会如何? |
静态变量和静态方法
静态变量
类中的变量有两类:实例变量和静态变量
静态变量是由static修饰的变量。
阅读程序分析结果
程序一
class Aa{
static int num=0;
public static void main(String[] s){
Aa a=new Aa();
Aa b=new Aa();
a.num++;
b.num++;
System.out.println(a.num);
System.out.println(b.num);
System.out.println(Aa.num);
}
}
程序二
class Aa{
static int num=0;
void count(){
num++;
System.out.println("This is object "+num);
}
public static void main(String[] s){
Aa a=new Aa();
Aa b=new Aa();
Aa c=new Aa();
a.count();
b.count();
c.count();
System.out.println(Aa.num);
}
}
结论
² 无论对象有无,静态变量均有确定的内存分配。
² 对于不同的对象,都对应同一个内存区域,所以值相同,称为“类变量”。
² 类变量描述的是类的整体性能,而不是单个对象的属性
² 类变量可以在类体内的方法中变化,亦可以在类体外变化。
思考 1.对应于静态变量,另一类变量称为什么变量? 2.如何辨别一个变量是静态变量? 3.一个类的多个对象的静态变量,有一个还是多个存储位置? 4. 类不实例化成对象,可否直接可类访问静态变量? |
静态方法
静态方法是由static修饰的方法。
阅读程序分析结果
class Base{
static double pi=3.1415926;
static double s(double r){
return pi*r*r; //涉及到的pi须也是静态的!
}
}
class use{
public static void main(String[] a){
double r=4.5;
System.out.println(r+"\t"+Base.s(r));
}
}
结论
² 从使用的角度,不需要实例化即可直接引用
² 从定义的角度,在方法体内不能处理非静态的成员变量。
练习:
1. 设计静态方法isPrime(int m)判断一个整数m是否为素数。
2. 在main方法中调用isPrime方法,用来输出所有的三位素数。
3. 设计静态方法print(char c,int m)用于输出一行m个c代表的字符。在main方法中用print输出图案:
* * * * * * * * * * * * * * * * * * * * * * * * * |
4. 设计求圆周长的静态方法getS,在main方法中用getS方法分别求半径为3.5、5、12.3的圆周长。
练习 1.创建一个MyCal类,在其中有成员变量n,构建两个静态方法,getSum求累加和(到n),getFac求n的阶乘。 2.设计一个类,在其main方法中直接利用MyCal类的方法求: (1)前100个自然数的和; (2)8! |
类的构造方法
编译器自动提供缺省构造方法
javap.exe观察类框架
bin目录下的javap.exe,是一个反编译的类察看器。
D:\Javawork\Lesson4>javap Person
Compiled from "Person.java"
class Person extends java.lang.Object{
int sex;
int salary;
Person();
void employed();
}
观察:类框架中多了哪一项?
构造方法的初步认识
² 构造方法的名字和类名相同,无类型修饰,没有返回值。
² 凡Java类都有构造方法,如果程序中没定义,编译器会自动提供缺省的构造方法。
² 缺省的构造方法,是不带参数的构造方法。
主动在类中引入构造方法
阅读程序分析结果
class Person2{
int salary;
Person2(){
System.out.println("output of constructor");
}
void employed(){
System.out.print("Work state:");
if (salary==0) System.out.println("no job");
else System.out.println("job");
}
public static void main(String[] a){
Person2 p1=new Person2();
p1.salary=900;
p1.employed();
}
}
问题:在创建对象时,能否直接将薪水传递过去?试修改实现。
思考 1. 构造方法的执行时机。 2. 如果希望创建对象时,传递给对象中的变量初值,怎么实现? 3. 回顾new运算,new 类名(参数),其中的参数什么时候带,什么时候不带? |
说明:
1)构造方法不可声明返回类型(包括void)。如说明编译器将把它看作为一个一般的方法,而不是构造方法。
2)创建对象时的new操作符,会做两件事:
² 基本数据类型的变量初始化
² 自动调用构造方法
练习:构造一个Circle类,可接受变量半径,并有求圆面积的方法getS和求圆周长的方法getL。通过Circle类的实例化对象,分别求半径为:1、1.5、2.5的圆面积和圆周长。
初始化问题的讨论
类中的成员变量
类中的成员变量可以在类定义时给初值。
如果没有对基本数据类型的成员预先赋初值,则在创建变量时自动初始化。要点:
² 数值型,值为0
² 布尔型,值为false
² 字型串,值为空(null)
class TestInit{
int x;
String s;
boolean f;
public static void main( String[ ] args ){
TestInit l=new TestInit();
System.out.println( "\nx is " + l.x );
System.out.println( "s is " + l.s );
System.out.println("f is "+ l.f);
}
}
程序可以正确编译和运行!
类方法中的变量
如果一个变量在方法中定义,那么使用这个变量前必须赋值。
class TestInit{
public static void main( String[ ] args ){
int x;
System.out.println( "\nx is " + x );
}
}
错误信息:variable x might not have been initialized
对象的初始化
在用new运算符创建对象时,初始化开始,分成两步:
² 成员变量的初始化
² 自动执行构造方法
分析如下程序:
class TestInit{
int x=3;
TestInit(){
x=5;
}
public static void main( String[ ] args ){
TestInit t=new TestInit();
System.out.println(t.x );
}
}
class TestInit{
TestInit(int a){
x=a;
}
public static void main( String[ ] args ){
TestInit t=new TestInit(5);
System.out.println( t.x );
}
int x=3;
}
练习:
构造一个SpaceStar类,其中有两个静态方法:Space(int n)、Star(int n),分别可以返回n个空格和n个“*”号。于是以下程序可以输出由“*”号组成的三角形。
class TestS{
public static void main(String[] aa){
for(int i=1;i<8;i++){
System.out.print(SpaceStar.getSpace(40-i));
System.out.println(SpaceStar.getStar(2*i-1));
}
}
}
回顾与思考 1.类和对象的关系? 2.对象包含哪两大类内容? 3.对象提供的服务是在哪里定义的? 4.构造方法有什么用?它的形式和执行时机? 5.每个类都有构造方法吗? 6.构造方法的命名和类型修饰? 7.怎么创建对象?对象的初始化过程? 8.类的静态成员有什么特别之处? 9.如何定义类的静态成员? 10. 一个方法没有返回值,方法名前导什么词? 11. 没有返回值的方法有什么用? 12. 一个程序中可含多个类吗? 13. 一个类中可不含main方法吗? 14. 一个类中可含多个main方法吗? 15. 试理解Calendar.getInstance()。 |