当前位置:文档之家› Java技术讲义编程技术篇(6)-李铁英

Java技术讲义编程技术篇(6)-李铁英

Java技术讲义编程技术篇(6)-李铁英
Java技术讲义编程技术篇(6)-李铁英

Object类

Object类是所有Java类的祖先。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。在不明确给出超类的情况下,Java会自动把Object作为要定义类的超类。可以使用类型为Object的变量指向任意类型的对象。Object类有一个默认构造方法pubilc Object(),在构造子类实例时,都会先调用这个默认构造方法。Object类的变量只能用作各种值的通用持有者。要对他们进行任何专门的操作,都需要知道它们的原始类型并进行类型转换。例如:Object obj = new MyObject();

MyObject x = (MyObject)obj;

当创建一个类时,如果没有使用extends关键字继承指定的类,则编译器总是默认直接继承Object类,如果指定了继承其他类,那么也会间接继承Object类。对自定义的类也继承于Object类。由于所有类都是Object子类,所以在定义时,省略了extends Object关键字。如下图。

Object类有11个方法,其中getClass()、notify()、notifyAll()、wait()等方法不能被重写,因为这些方法为final类型。而clone()、finalize()、equals()、toString()为可以重写方法,对equals()和toString是常用的方法。

Object的基本方法

Object()

默认构造方法

clone()

创建并返回此对象的一个副本。

equals(Object obj)

指示某个其他对象是否与此对象“相等”。

finalize()

当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。

getClass()

返回一个对象的运行时类。

hashCode()

返回该对象的哈希码值。

notify()

唤醒在此对象监视器上等待的单个线程。

notifyAll()

唤醒在此对象监视器上等待的所有线程。

toString()

返回该对象的字符串表示。

wait()

导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。

wait(long timeout)

导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。

wait(long timeout, int nanos)

导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。

方法使用说明

1、equals()方法:用于测试某个对象是否同另一个对象相等。它在Object类中的实现是判断两个对象是否指向同一块内存区域。这种测试用处不大,因为即使内容相同的对象,内存区域也是不同的。如果想测试对象是否相等,就需要覆盖此方法,进行更有意义的比较。例如:实例化该类并在main方法中运行。

class Employee{

public boolean equals(Object otherObj){

//快速测试是否是同一个对象

if(this == otherObj) return true;

//如果显式参数为null,必须返回false

if(otherObj == null) reutrn false;

//如果类不匹配,就不可能相等

if(getClass() != otherObj.getClass()) return false;

//现在已经知道otherObj是个非空的Employee对象

Employee other = (Employee)otherObj;

//测试所有的字段是否相等

return name.equals(otherName)

&& salary == other.salary

&& hireDay.equals(other.hireDay);

}

}

Java语言规范要求equals方法具有下面的特点:

自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。

传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回true。

一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。

于任何非空引用值 x,x.equals(null) 都应返回 false。从这里看出,上面的例子是Java规范的equals方法的标准实现,推荐用上面例子的写法实现类的equals方法

equals()方法

给该方法用于判断是否相同,大部分子类都重写了该方法,用于比较指定类型的对象,如String、Integer等都重写了该方法。如果没有重写equals()方法,该方法将默认使用“==”运算符判断两个对象。

equals()方法的原始代码如下:

练习1:

自定义TempClass类,用于测试,在创建Testequals类,在该方法创建String类的两个实例对象s1s2,在创建TempClass类的两个对象v1和v2,分别输出s1、s2、v1、v2的equals()方法调用结果。

执行结果:

上例中,自定义的类使用equals()方法进行比较时,返回的是false。这是因为equals()方法默认实现的是“==”运算符对两个对象引用地址,而不是比较对象的内容。因此,要比较两个对象的内容,需要在自定义的类中重写equasl()方法。

toString()方法

该方法非功能的将一个对象转换为字符串形式,当一个对象与字符串的“+”连接时,也会调用该方法将对象转换为字符串,然后在和另一个字符串连接。toString()返回一个String实例。在实际应用中通常重写toString()方法,为对象通过一个特定的输出模式,当这个类转换为字符串或字符连接时将自动调用重写的toString()方法。

练习2:

在自定义类中重写Object的toString()方法,并在main方法中输出该类的对象。

执行结果:

在本例中重写了父类Object的toString()方法,定义一段输出字符串,当用户打印该类实例时,将自动调用toString()方法。

多态数组

多态数组就是使用父类说明,而数组中的的元素都是子类的实例对象,它们有父类同名的方法,但是方法实现却不一样。

练习3:

创建Quadragle四边类型的类,作为其他类的父类。在创建Square正方形类、Rectangle()长方形类和Parallelogram平行四边形类,这些类都继承Quadrangel类,并重写draw()方法。使用父类定义一个四边形的数组。数组的元素分别是每个子类的实例对象,在foreach()循环中遍历数组,调用每个数组的元素的draw()方法。

⒈创建Quadrangle父类,为该类定义draw()方法。

创建Square()正方形类,并继承父类,同时重写draw()方法,实现自己的绘图能力。

⒊创建Rectagle类,继承父类,重写draw()方法,实现自己的绘图功能。

⒋创建Parallelogram类,继承父类,重写draw()方法,实现自己的绘图功能。

⒌创建主类Demo,在main方法中演示多态数组的定义和使用。

执行结果:

说明:什么是多态:多态是指程序中同一操作,在不同环境中有不同的语义解释。要理解多态,首先要理解类的继承、向上转型、方法的重载与重写等知识特点。

向上转型就是可以声明父类的引用变量但是赋值为子类的实例对象。也就是,对象变量的声明与赋值可以不是一个类型。

例如,把子类对象赋值给父类的对象变量。

Quadrangle obj=new Square(); //声明父类对象,初始化为子类

声明的变量obj是Quadrangle类型,而赋值时却是Square类型的实例变量。通过使用父类类型的引用,可以定义多态数组或多态方法等。

练习4:

创建一个多态数组,然后后调用数组所以元素的bellow()方法,让动物发出吼叫。

参数多态

练习5:

问题:主人养了3只爱喝酒的小老鼠,它们分别是白鼠、灰鼠和花鼠。有一天主人买了两瓶好酒。主人想让3只小老鼠试一试酒劲有多大。可是这3只小老鼠酒后反应都不一样,通过下面实例阐述这些小老鼠喝酒以后分别是什么反应。

分别创建主人类、鼠类和3个试酒的鼠类,使用Java的多态性实现主人给3只老鼠喂酒的动作,并分别给出每只老鼠喝酒后的反应。另外,3个试酒的鼠类都继承Mouse鼠类。其UML类图如下。

⒈创建Mouse鼠类,并定义drink()饮酒方法。

⒉继承Mouse类,创建小白鼠WhiteMouse类,重写父类drink()方法,实现小白鼠酒后状态输出。

⒊继承Mouse类,创建小灰鼠WhiteMouse类,重写父类drink()方法,实现小灰鼠酒后状态输出。

⒋继承Mouse类,创建小花鼠WhiteMouse类,重写父类drink()方法,实现小花鼠酒后状态输出。

⒌创建主人类Master。主人将用不同的老鼠试酒。

⒍创建Demo类

该类是本例的主类,用于执行程序。

执行结果:

从实例运行结果可以看出,feedinVino()方法传递的参数是多态的,不同的参数会有不同的表现。

实现多态

实现多态可以通过参数实现多态,例如,定义一个print()方法,该方法定义Quadrangle类型的参数,但是在调用print()方法时可以传递子类对象的实参。例如:

说明:方法返回类型可以是多态的,例如,定义一个getQuadrangle()方法,方法的返回值可以是Quadrangle类,方法体中的return语句可以返回该类的任何增长率子类。例如:

类型7:

创建一个Cat类,在Cat类中定义look方法,通过该方法的参数多态性实现输出不同老鼠看到猫的反应。

抽象类

在面向对象的程序开发中,子类可以通过继承父类获得父类已经

定义的一些方法,还可以在此基础上进行扩充和改造,添加新的属性和方法,或者重写从父类继承过来的方法。

例如,有一个用于描述动物的Animal父类,其中定义了getInfo 方法,用于获取动物的相关信息。它有三个子类,分别是描述马的子类Horse,描述人的子类Person和描述鱼的子类Fish,如图下所示。三个子类中都重写了getInfo方法,用于根据具体的动物类型获取相关信息。

在这种情况下,父类的getInfo方法实际上是没有必要确定实现细节。因为在子类中都对getInfo方法进行了重写。之所以声明父类的getInfo方法,可以理解为它只是子类的一种“规划”,说明子类必须具备这样的特性或功能。实际上,程序员是不会直接创建Animal 类的对象的,而只是根据具体的动物类型去创建具体动物类型的类(Horse类、Person类或Fish类)的对象。这时候,我们可以在类声明时将Animal类声明为抽象的(用abstract作为非访问修饰符),也就是说它是概括性的、不具体的类。被abstract修饰的类称为抽象类。同样的,对于那些抽象的、不需要在父类中实现的方法也可以声明为抽象方法。例如:

抽象类是指在类中,部分方法只有声明、没有实现的类,它是某一类型事物的抽象。注意:抽象类是不能被实例化的(因为它是抽象的、不具体的类),它只能在继承中发挥作用;而抽象方法也只能在子类中被重写(实现)后才能用子类的对象调用。在UML图中一般用斜体字表示抽象元素。将Animal类及其getInfo方法改为abstract 之后的UML图如下所示。

练习8:

在Person类中实现其抽象父类中的抽象方法。

目的:掌握抽象类和抽象方法的使用。

分析:该程序在Person类中实现其抽象父类Animal中的抽象方法getInfo。

使用抽象类和抽象方法还需要注意如下几点:

⒈在一个类中,如果有一个方法是抽象的,该类就必须声明为抽象的(当然,将不含有抽象方法的类声明为抽象类也是可以的,不过很少这样用)。

⒉如果子类没有实现父类中所有的抽象方法,那么该子类也必须声明为抽象的。

⒊一个类不能同时被声明为final和abstract。因为被声明为final的类是最终类,而被声明为abstract的类又必须在子类化后才能使用,这是两个相反意义的修饰符。

相关主题
文本预览
相关文档 最新文档