C#的面向对象特性
初级特性,OO最基本的概念,即类和对象,包。
中级特性,OO最核心的概念,即封装、
继承和多态。
高级特性:由初级特性和中级特性引出的一些问题,如构造函数的使用、覆盖的规则、静态变量和函数等。
A-PDF Split DEMO
初级特性
面向对象技术最基本的概念是类和对象:
– 类是一个样板,以操作、表示和算法的形式完整地定义了一组对象的行为。它通常也是面向对象语言中的模块化、封装和数据抽象的基础。
– 对象是类的一个实例,是一个软件单元,它由一组结构化的数据和在其上的一组操作构成。
变量方法对象
A-PDF Split DEMO
抽象数据类型
class Car {
int colorNumber;
int doorNumber;
int speed;
void Brake() { … }
void SpeedUp() {…};
void SlowDown() { … }
}
Car myCar = new Car();
myCar.SpeedUp();
计算机中对象的原型现实生活中的对象
类实际上为实际的物体在计算机中定义了一种抽象数据类型。
– 抽象数据类型是仅由数据类型和可能在这个数据类型上进行的操作定义的。
– 使用者只能通过操作方法来访问其属性,不用知道这个数据类型内部各种操作是如何实现的。
A-PDF Split DEMO
变量、方法和消息
对象的三个基本要素:
– 变量:指对象的数据,用来保存对象的状态,又称为实例字段。
– 方法:指对象的功能单元。
– 消息:软件对象通过相互间传递消息来相互作用和通信。
对象 B
对象 A
消息一个消息由三部分组成,
1,接受消息的对象
2,要完成方法的名字
3,方法需要的参数如 myCar.SpeedUP(10);
A-PDF Split DEMO
类、对象和引用
类,C#所有的代码都是在某一个类中,因此不可能在类之外的全局区域有变量和方法。
对象,C#中的对象相当于一块内存区域,保存对象特有的类中所定义的数据。
引用,C#中对于对象的操作全部通过引用进行。
引用类似于 C++中的对象指针。但又有区别:
– 在 C#中,引用,是指向一个对象在内存中的位置,在本质上是一种带有很强的完整性和安全性的限制的指针。
– 当声明某个类、接口或数组类型的一个变量时,变量的值总是某个对象的引用或者是 null引用。
– 指针就是简单的地址而已,而引用除了表示地址而外,还是被引用的数据对象的缩影,可以提供其他信息。
– 指针可以有 ++,--运算,引用不可以运算。
A-PDF Split DEMO
类、对象和引用的声明
声明一个类,class 类名 {变量声明,方法声明 }
class Student{
long id; //学号
char gender; //性别
int classID; //班级号,注意不能用 class作属性名
void ChangeClass(int aClassID) //更改班级
{…
}

声明一个对象引用:类名 引用名
Student student;
创建一个对象,new 类构造函数
student = new Student(); //如果缺少这一步编译器会报错
使用对象:引用名, 变量名 /方法名 (参数 )
student.id = 200328013203194;
A-PDF Split DEMO
存储器分配
Student student; //声明一个 Student对象引用
student
student = new Student(); //创建一个对象
new Student() student =
student student
Student student2 = student; //对象赋值
– student student2
00000000
0000000000000000
0000
00000000
00000000 0x01abcdef
0000000000000000
0000
00000000
0x01abcdef
200328013203194
0000
00000000
0x01abcdef
A-PDF Split DEMO
引用与对象举例
Student xiaoMing = new Student();
Student xiaoFang = new Student();
xiaoMing.gender = ‘M’;
xiaoFang.gender = ‘F’;
说明:
结果 xiaoMing.gender为 ‘M’,因为引用 xiaoMing和 xiaoFang指向不同的对象。
( xiaoMing= = xiaoFang)的结果为
false。 此时对象相等的判断应该用 equals方法。
0x01abcdef
‘M’

xiaoMing
0x01abcdf5xiaoFang

‘F’

两个引用指向不同的对象
Student xiaoMing = new Student();
Student xiaoFang = xiaoMing;
xiaoMing.gender = ‘M’;
xiaoFang.gender = ‘F’;
说明:
结果 xiaoMing.gender为 ‘F’,因为引用 xiaoMing和 xiaoFang指向同一个对象。
( xiaoMing= = xiaoFang)的结果为
true。 xiaoMing.equals(xiaoFang)结果也为 true。
两个引用指向同一个对象
0x01abcdef
‘F’

xiaoMing
0x01abcdf5xiaoFang
A-PDF Split DEMO
值的内存分配
int xiaoMing = 100;
int xiaoFang = xiaoMing;
xiaoFang = 200;
说明:
结果 xiaoMing为 100,因为预定义数据类型不存在指向同一个对象的问题。
( xiaoMing= = xiaoFang)的结果为 false。
100xiaoMing
200xiaoFang
A-PDF Split DEMO
参数传递
C#编程语言支持的参数传递方式包括:
– 值传递:方法中的变量是传入变量的一个拷贝,方法中对形参做的修改,不会影响方法外面的实参。
对于值类型数据,值传递就是传递了变量的值。
对于引用类型数据,值传递传递的是引用的值,即方法中的形参和方法外的实参将指向同一对象。因此,通过形参也能修改对象的实际内容。
– 地址传递:方法中的变量是传入变量的一个引用,
方法中对形参做的修改,也会影响方法外面的实参。
ref关键字,可以将参数声明为传址调用。
out关键字,声明只用于返回值的参数,可以不用初始化就作为参数传递给方法。
A-PDF Split DEMO
值传递 -值类型
class HelloWorld
{ static void change100(int x)
{ System.Console.WriteLine("Inside method,x=" + x);
x = 100;
System.Console.WriteLine("Inside method,x=" + x);
}
static void Main(string[] args)
{ int y = 10;
System.Console.WriteLine("Outside method,y=" + y);
change100(y);
System.Console.WriteLine("Outside method,y=" + y);
}
}
对方法中形参的操作不会改变方法外实参的值。
Outside method,y=10
Inside method,x=10
Inside method,x=100
Outside method,y=10
形参实参
A-PDF Split DEMO
值传递 -引用类型
class Student
{ public int No;}
class HelloWorld
{ static void change100(Student x)
{ x.No = 100;
}
static void Main(string[] args)
{
Student s = new Student();
s.No = 10;
change100(s);
System.Console.WriteLine("s.No = " + s.No);
}
}
对方法中引用的操作会改变方法外实际对象的内容。
s.No = 100
A-PDF Split DEMO
地址传递 -ref
class HelloWorld
{ static void change100(ref int x)
{ System.Console.WriteLine("Inside method,x=" + x);
x = 100;
System.Console.WriteLine("Inside method,x=" + x);
}
static void Main(string[] args)
{ int y = 10;
System.Console.WriteLine("Outside method,y=" + y);
change100(ref y);
System.Console.WriteLine("Outside method,y=" + y);
}
}
对方法中形参的操作会改变方法外实参的值。
Outside method,y=10
Inside method,x=10
Inside method,x=100
Outside method,y=100
A-PDF Split DEMO
地址传递 -out
class HelloWorld
{ static void change100(int x,out int y)
{y = x;
}
static void Main(string[] args)
{ int x = 10,y;
change100(x,out y);
System.Console.WriteLine("y=" + y);
}
}
使用 out关键字,可以将未初始化的变量传递给方法,可以避免多余的初始化。
y=10
A-PDF Split DEMO
变量和作用域
局部 (local)变量:在一个方法内定义的变量,也被称作自动( automatic)、临时( temporary)或栈( stack)变量。
局部变量只在方法内部起作用。
– 当一个方法被执行时,局部变量被创建;当一个方法被终止时,
局部变量被清除。
– 局部变量必须使用之前初始化,否则编译时将出错。
– 方法 (包括构造函数 )的入口参数是局部变量。
实例变量:在方法外而类的内部定义的变量,在使用
new Xxxx ()调用构造一个对象时被创建。
– 类的实例变量有默认的初始值,可以不用显式初始化。
局部变量可以取消非局部变量的作用
– 方法内声明的局部变量与类变量或实例变量可以重名。
– 此时缺省为局部变量。
– 若要使用类变量或实例变量,应使用 this关键字。
A-PDF Split DEMO
变量作用域举例
class Student
{
long id;
char gender;
int classID;
void changeClass(int classID)
{
this.classID = classID;
int y = 0;
for (int x=0; x<10; x++) { y += x; }
for (int x=0; x<100; x++) { y += x; }
}
};
实例变量局部变量
A-PDF Split DEMO
命名空间
定义,C#允许把多个类收集在一起成为一组。
目的:便于组织代码,使自己的任务和他人提供的代码库分离;还可以提高编译速度。
分级:命名空间可以嵌套,从而分成层次,类似于硬盘上的目录组织。一可以使每个命名空间中的类不至于过多,二可以保证类名的唯一性。
.Net框架由许多命名空间组成,其中最重要的是 System。
类命名空间类
A-PDF Split DEMO
namespace关键字
关键字 namespace将后面大括号中的所有类添加到一个命名空间中。如:
namespace MyNamespace{
public class Hello{……}
}
那么,上述类的完整命名为,MyNamespace.Hello
一个文件中可以有多个 namespace语句。
即使未显式声明命名空间,也会创建默认命名空间。
全局命名空间中的任何标识符都可用于命名的命名空间中。
namespace语句中包含的类可以使用 private或 public修饰符,缺省为 public。
namespace语句对于源文件的存放位置并无要求。编译器编译时也不对文件位置做检查。
A-PDF Split DEMO
using关键字
使用其它命名空间中的类,可以使用完整的类名称。但如果命名空间层次很多,那么导致完整的名称很长。为了方便,可以使用 using关键字。
– 类名前加上完整的包名,如:
MyNamespace.Hello hello = new MyNamespace.Hello();
– 使用 using关键字,using的作用是导入命名空间中的所有公开类。
using MyNamespace;
Hello hello = new Hello();
注意:
–using只引入一个命名空间中的所有类,并不能嵌套引入下层命名空间。
– 当前命名空间的类,会隐藏其他命名空间中的类。
– 要在两个程序集间共享类定义,则需要通过,创建类库、生成 dll文件,添加引用,的方法。
A-PDF Split DEMO
同名类的问题
问题:两个不同命名空间中含有同名类,会出现编译错误,因为编译器不知道使用哪个类:
namespace N1{ class A {}}
namespace N2{ class A {}}
namespace N3{
using N1;
using N2;
A a(); // 编译错误
}
解决方法:为重名类启用一个别名。
namespace N3{
using N1;
using N2;
using A = N1.A;
A a() // A means N1.A
}
C#中的所有预定义类型都是别名,实际上都为 System命名空间中的类。
若两个类都要使用,则可以使用完整的类名,或者分别指定不同的别名。
A-PDF Split DEMO
中级特性
面向对象技术的三个核心概念:
– 封装:将数据和操作组合到一起,并决定哪些数据和操作对外是可见的。
– 继承:父类中的变量和行为,子类可以同样使用。本质是代码重用。
– 多态:由继承引出的一种机制,父类型的引用变量可以指向子类型的对象。
A-PDF Split DEMO
封装
封装把对象的所有组成部分组合在一起,有三个作用
– 隐藏类的实现细节:使用方法将类的数据隐藏起来。
– 迫使用户去使用一个界面去访问数据:定义程序如何引用对象的数据,控制用户对类的修改和访问数据的程度。
– 使代码更好维护:类的内部实现改变,对外接口可以不变。
私有数据方法方法数据对象 A 对象 B
公有数据
A-PDF Split DEMO
可见性
在类、类中变量和方法声明时,加可见性修饰:
– public:任何其它类、对象只要可以看到这个类,就可以存取变量,或使用方法。
–private:不允许任何其他类存取和调用。
–protected:子类可以使用,同一包中的其他类也可以使用。
–internal:在同一程序集中的类可以直接使用的数据和方法。程序集是组成一个程序的所有文件的集合。
– protected internal:等价于 protected或者 internal,满足其一即可。
一些缺省的可见性规则:
– 命名空间、类、结构、枚举,默认为 public的;
– 类成员、结构的成员,默认为 private的;
– 枚举、接口的成员,默认为 public的。
A-PDF Split DEMO
可见性举例
class Student{
private long id; // 变量一般都声明为私有
private char gender; // 以防止其他对象任意更改
private int classID;
public long getID() {return id;} // 方法一般是对外提供服务的
public boolean setID(long aID) { // 所以声明为公共的
if(aID>=0){id = aID;return true;}
else {return false;}
}
public static void main(String[] args)
{

}
}
A-PDF Split DEMO
属性
属性是一种类成员,可以用来控制其他对象对本对象数据的访问。属性集合了变量的方便性和方法的安全性。
class Student{
public int No;
}
class Student {
private int No;
public int GetNo(){
return No;
}
public void SetNo(int aNo){
if(aNo > 0)No = aNo;
else No = 0;
}
}
class Student3{
private int no;
public int No{
get{ return no; }
set{ if(value > 0) no = value;
else no = 0;
}
}
}
class HelloWorld
{ static void Main(string[] args)
{ Student3 s = new Student3();
s.No = 1;
}
}
A-PDF Split DEMO
属性说明
声明属性的形式为:
属性名称 {
get{…}
set{…}
}
可以创建只读或只写属性,即只有 get或
set方法。
可以创建静态属性,用 static关键字。
A-PDF Split DEMO
构造函数
构造函数是一种用于对象初始化的特殊方法,
有以下特点。
– 构造函数只能在对象创建时调用,即和 new运算符一起被调用。
– 构造函数和类具有相同的名字,必须是 public可见。
– 构造函数可以有 0个,1个或多个参数。
– 构造函数没有返回值。
– 每个类至少有一个构造函数,一个类可以有多个构造函数。
– 如果没有为类定义构造函数,系统会自动为其定义一个缺省的构造函数。缺省构造函数不带参数,作用是将实例变量都清零。
– 一旦为类定义了构造函数,则系统不会再为其定义缺省构造函数。
A-PDF Split DEMO
构造函数举例
class Student{
long id; //学号
char gender; //性别
int classID; //班级号,注意不能用 class作属性名
public Student()
{ id = 0;
gender = 'F';
classID = 0;
}
public Student(long aID,char aGender,int aClassID)
{id = aID;
gender = aGender;
classID = aClassID;
}
}
A-PDF Split DEMO
对象析构
C#支持析构函数。虽然 C#能够自动进行垃圾回收,但对于某些资源,.Net不知道如何回收,所以需要人工的内存回收。
在,net 编程环境中,系统的资源分为托管资源和非托管资源。
– 托管资源,如简单的 int,string,float,DateTime等等,是不需要人工干预回收的。
– 非托管资源,例如文件,窗口或网络连接,对于这类资源虽然垃圾回收器可以跟踪封装非托管资源的对象的生存期,但它不了解具体如何清理这些资源。在使用完之后,必须显式的释放他们,否则会占用系统的内存和资源,而且可能会出现意想不到的错误。
.net中超过 80%的资源都是托管资源。
,NET Framework 提供 Object.Finalize方法,默认情况下,Finalize
方法不执行任何操作。如果需要可以覆盖 Finalize方法。通过析构函数可以自动生成 Finalize方法和对基类的 Finalize方法的调用。
Finalize方法通常和 Close,Dispose方法结合使用。
A-PDF Split DEMO
对象析构举例
Close方法用于释放资源;
Dispose方法是编程人员需要立即释放资源时调用,所以在 Dispose
方法中调用 Close,并通知 GC在回收垃圾时不需要再释放资源。
析构函数是编程人员如果没有调用 Dispose方法释放资源的情况下由 GC在回收垃圾时调用,所以在析构函数中调用 Close方法,以确保释放资源。
为确保这三个方法能正确定义,C#还提供了 IDisposable接口。
using System;
class MyFile{
public MyFile(){//…Open File}
public void Close(){//…Close File}
public void Dispose(){
Close();
GC.SuppressFinalize(this);
}
~MyFile(){ Close(); }
}
A-PDF Split DEMO
继承
继承提供了创建新类的一种方法,本质特征是行为共享。继承对开发者来说就是代码共享。
– 通过继承创建的子类是作为另一个类的扩充或修正所定义的一个类。
– 子类从超类 (父类 )中继承所有方法和变量。
– 子类和超类之间是特化与范化的关系。
自行车
(超类 )
山地车赛车双座自行车子类
A-PDF Split DEMO
子类的声明
语法:子类声明,父类 {子类体 }
子类可以使用父类的 protect和 public可见的变量和方法,
就像这些变量和方法是自己定义的一样。
C#中,如果类声明时没有声明父类,那么缺省为 Object
类的子类。 C#中的所有类都是 System.Object类的子类。
Object类定义了类的一些基本行为,如 Finalize,ToString,
Equals等。
class Car
{ int colorNumber;
int doorNumber;
int speed;
void PushBreak() { … }
void AddOil() { … }
}
class TrashCar, Car
{ double amount;
void FillTrash() { … }
}
TrashCar myCar = new TrashCar();
myCar.AddOil();
A-PDF Split DEMO
C#中继承的特点
子类不从超类继承构造函数 。
单继承性:C#编程语言允许一个类仅能直接扩展自一个其它类,即,:”后面只能跟一个类名。
单继承性使代码更可靠。
C#中,如果类声明时没有声明父类,那么缺省为 Object类的子类。 C#中的所有类都是 Object类的子类。
类库文档:对一个继承的方法或变量的描述只存在于对该成员进行定义的类的 API文档中。
A-PDF Split DEMO
覆盖
当用于子类的行为与父类的行为不同时,覆盖机制允许子类可以修改从父类继承来的行为。
覆盖就是在子类中创建一个与父类方法有不同功能的方法,但具有相同的名称、返回类型和参数表。
– 若参数表不同,则不是覆盖,而是重载。
– 若参数表相同,但返回值不同,则编译出错。
C#中声明覆盖时,父类方法前加 virtual关键字,表示该方法可以被覆盖;子类方法前加 override,表示覆盖。
class Car
{ int colorNumber;
int doorNumber;
protected int speed;
public virtual void PushBreak()
{ speed=0; }
void AddOil() { … }
}
class TrashCar, Car
{ double amount;
void fillTrash() { … }
public override void PushBreak()
{ speed=speed-10; }
}
A-PDF Split DEMO
base关键字
通常当覆盖一个方法时,实际目的不是要更换现有的行为,而是要在某种程度上扩展该行为。
此时应先执行父类的行为,然后再执行扩展部分的行为。这种情况下用 base关键字调用父类的行为。
class Car
{ int colorNumber;
int doorNumber;
int speed;
public virtual void PushBreak()
{ speed=0; }
void AddOil() { … }
}
class TrashCar, Car
{ double amount;
void FillTrash() { … }
public override void PushBreak()
{ base.pushBreak();
speed += 5;
}
}
A-PDF Split DEMO
重载
重载指在同一个类中至少有两个方法用同一个名字,
但有不同的参数。
重载使得从外部来看,一个操作对于不同的对象有不同的处理方法。
调用时,根据参数的不同来区别调用哪个方法。
方法的返回类型可以各不相同,但它不足以使返回类型变成唯一的差异。重载方法的参数表必须不同。
class Car
{ int colorNumber;
int doorNumber;
int speed;
void PushBreak() { speed=0; }
void PushBreak(int aDeltaSpeed) { speed -= aDeltaSpeed; }
void Add_oil() { … }
}
A-PDF Split DEMO
重载和覆盖的区别
相同点:
– 都涉及两个同名的方法。
不同点:
– 类层次
重载涉及的是同一个类的两个同名方法;
覆盖涉及的是子类的一个方法和父类的一个方法,这两个方法同名。
– 参数和返回值
重载的两个方法具有不同的参数,可以有不同返回值类型;
覆盖的两个方法具有相同的参数,返回值类型必需相同。
A-PDF Split DEMO
多态
继承机制引出多态机制
某一类型的引用变量可能是指向该类 或者其子类 的对象。
由于 C#中 System.Object类是所有类的祖先,所以可以用 Object类型的引用指向所有类型的对象。而 object是
System.Object的别名,所以 object等价于 System.Object。
class Car
{ int colorNumber;
int doorNumber;
int speed;
void PushBreak() { … }
void AddOil() { … }
}
class TrashCar, Car
{ double amount;
Fill_trash() { … }
}
Car myCar = new TrashCar();
A-PDF Split DEMO
动态绑定
由于多态机制,C#调用一个对象的方法时采用动态绑定的方式。
动态绑定就是根据对象的类型决定调用哪个方法,而不是引用的类型。
例如:
class GeometricObject{
public virtual void Draw(){…}
}
class Ellipse, GeometricObject{
public override void Draw(){…}
public void GetCenter(){…}
}
class Circle, Ellipse{
public override void Draw(){…}
public double GetArea(){…}
}
GeometricObject g = new Circle(); //父类型引用指向子类型对象
g.draw(); //draw调用的是哪个类的方法?如果 g换成 Circle类引用呢?
//如果 Circle类不覆盖 draw方法,调用的是哪个类的方法?
double d = g.GetArea(); //编译时能否通过。
A-PDF Split DEMO
方法的隐藏
若覆盖时没有使用 virtual和 override关键字,则称为子类的方法隐藏了父类的方法。此时编译器报警告。若要消除掉警告,可以使用 new修饰符。
C#会根据引用的类型决定调用哪个类的方法。
例如:
class GeometricObject{
public void Draw(){…}
}
class Ellipse, GeometricObject{
public void Draw(){…}
public void GetCenter(){…}
}
class Circle, Ellipse{
public new void Draw(){…}
public double GetArea(){…}
}
GeometricObject g = new Circle(); //父类型引用指向子类型对象
g.draw(); //draw调用的是哪个类的方法?如果 g换成 Circle类引用呢?
A-PDF Split DEMO
动态绑定示意图
Circle引用
Circle对象
Circle类
Ellipse类
GeometricObject类
Draw
GetCenter
GetArea
GeometricObject引用
Circle对象
Circle类
Ellipse类
GeometricObject类
Draw
引用的类型限制了能够看到的对象的能力。
实际调用的是对象所属类的方法,与引用的类型无关。
A-PDF Split DEMO
单继承性和接口
C#的单继承性使得类结构成为以 System.Object类为根的一棵树。
Object
Class11 Class12
ClassXX


C#用接口 (interface)来获得多继承性。
接口克服了多继承性带来的一些问题。
录音机
U盘
Mp3播放器相机数码相机
A-PDF Split DEMO
Object类
Object类是 C#中所有类的超类。
单继承性带来的好处:
– Object类定义了类应该提供的一些基本功能,几个重要方法如
(自定义的类一般都要覆盖定义 ):
Equals方法:用于测试一个对象的内容是否和另一个对象相等,
注意与两个对象引用相等的区别。
ToString方法:将对象内容写到字符串中,可用于将对象打印输出。
MemberwiseClone方法:将对象复制一份。
– 由于多态性,可以用 Object类型的引用指向所有类型的对象。
因此,许多通用编程成为可能,如动态数组、集合、堆栈、
链表等等。
A-PDF Split DEMO
接口
声明:用 interface关键字,
声明中只指定原型,不直接定义方法的内容。
实现:类要实现某个接口用,:”,在类的定义中给出接口中所定义方法的实际实现。
接口中可以声明属性。
一个类可以实现多个接口。
interface Comparable
{
int CompareTo(object other);
}
class Student, Comparable
{
private long id;
public void SetID(long aID){…};
public int CompareTo(object otherObject);
{
Student other = (Student)otherObject;
if(id < other.id) return –1;
if(id > other.id) return 1;
return 0;
}
}
Student类的对象数组可以在 Arrays中进行排序等操作。
A-PDF Split DEMO
使用接口
接口用于下面一些情况:
– 声明方法,期望一个或更多的类来实现该方法。
– 决定一个对象的编程界面,而不揭示类的实际程序体。
– 捕获无关类之间的相似性,而不强迫类关系。
– 回调功能,如排序 (sort)方法需要用到比较 (CompareTo)方法等。
接口与对象:
– 接口不是类,所以不能用接口创建对象,即不能用 new运算符。
x = new Comparable(); //错误
– 可以声明接口类型的引用,该引用只能指向实现了该接口的对象。
class Student, Comparable
{...}
Comparable x;
x = new Student();
A-PDF Split DEMO
接口继承
接口也可以继承,同类继承一样,也使用,:”关键字。
如:
interface ListIterator, Iterator
{
void add(Object o);
}
子接口继承父接口的所有变量和方法声明,用于扩大接口的功能。
实现子接口的类必须实现父接口和子接口中的所有方法。
A-PDF Split DEMO
作业
1、设计类,使用对象和引用
– 设计以下几个类及其继承关系:几何形状 (GeometricObject)、
正方形 (Square)、矩形 (Rectangle),(Ellipse)、圆形 (Circle)。
– 根据自己的理解,将下面的属性和方法添加到相应的类的声明中:
属性:名称 (name)、宽 (width)、高 (height)、半径 (radius)、焦半径
(focalRadius)。
方法:设置上述属性的方法 (setXxx,也可直接用构造函数代替 )、
求面积 (getArea,椭圆不用实现此方法 )、取名称 (getName)、取类型 (getType)。
– 理解多态:用 GeometricObject类型的引用来操作 Square型的对象,看哪些方法能用,哪些不能;能用的方法调用的是哪个类中实现的方法。
A-PDF Split DEMO