960 likes | 1.09k Views
第 3 章 Java 与面向对象技术. 广东工业大学计算机学院. 本章内容. 3.1 面向对象编程基础 3.2 类的编程实现 3.3 对象的使用 3.4 包. 3.5 文档注释 3.6 类设计技巧 3.7 类的继承实例 3.8 多态. 什么是面向对象. 面向对象 — 将现实世界的复杂事物抽象为一个个对象 如 : 灯泡 对象的二要素 — 状态和行为 如:灯泡的状态有:亮或灭,功率,电压 行为有:开、关 软件对象 — 对现实对象进行模拟,状态用变量表示,行为用方法实现。
E N D
第3章Java与面向对象技术 广东工业大学计算机学院
本章内容 • 3.1 面向对象编程基础 • 3.2 类的编程实现 • 3.3 对象的使用 • 3.4 包 • 3.5 文档注释 • 3.6 类设计技巧 • 3.7 类的继承实例 • 3.8 多态 广东工业大学计算机学院
什么是面向对象 • 面向对象 —将现实世界的复杂事物抽象为一个个对象 如: 灯泡 • 对象的二要素 —状态和行为 如:灯泡的状态有:亮或灭,功率,电压 行为有:开、关 • 软件对象 —对现实对象进行模拟,状态用变量表示,行为用方法实现。 —由数据(变量)和相关方法组成的软件包。 • 面向对象程序设计—以对象作为编程基础的程序设计方法。 广东工业大学计算机学院
面向对象的基本概念(1) 类 :对有共同特点的软件对象的抽象。 Car类 class Car { int color_number; int door_number; int speed; void brake() { … }; void speedUp() {…}; void slowDown() { … }; } • 货车 抽象 • 小轿车 • 公交车 … 广东工业大学计算机学院
面向对象的基本概念(2) • 类是描述一类对象的“基本原型”,它定义一种对象所拥有的数据和能完成的操作,在面向对象的程序设计中,类是程序的基本单元。 • 对象在程序中的是类的一个实例。类产生实例的过程充分体现了类的可重用性。 广东工业大学计算机学院
封装把对象的所有组成部分组合在一起,并使用方法将类的数据隐藏起来,控制用户对类的修改和访问数据的程度。封装把对象的所有组成部分组合在一起,并使用方法将类的数据隐藏起来,控制用户对类的修改和访问数据的程度。 面向对象基本概念(3) 公有数据 数据 私有数据 方法 方法 对象A 对象B 封装定义程序如何引用对象的数据 6 广东工业大学计算机学院 广东工业大学计算机学院
面向对象的基本概念(4) • 一个新类可以通过继承已有类的数据和方法的基础上,添加部分新的数据和方法得到,这种性质称为类的继承性。 • 用继承方法得到的新类称为原类的子类, 而原类对子类而言成为超类。父类与子类是一般与特殊的关系。 广东工业大学计算机学院
面向对象基本概念(5) 重载- 一个类可包含多个名字相同的方法,但这些方法的参数不同。 void show(int int_num) 123 1.23 void show(double double_num) 类 123,1.23 void show(int int_ um, float float_um) 8 广东工业大学计算机学院 广东工业大学计算机学院
面向对象基本概念(6) • 多态性:允许将父对象设置成为一个或多个它的子类对象相等,在赋值之后,父对象就可以根据当前赋值给它的子类对象的特性以不同的方式运作的特性。 Manager getSalary( ) Employee e; Manager m; TeamLeader t; … e=m; e.getsalary(); getSalary( ) Employee TeamLeader getSalary( ) getSalary( ) Programmer 广东工业大学计算机学院
本章内容 • 3.1 面向对象编程基础 • 3.2 类的编程实现 • 3.3 对象的使用 • 3.4 包 • 3.5 文档注释 • 3.6 类设计技巧 • 3.7 类的继承实例 • 3.8 多态 广东工业大学计算机学院
类定义 Java中,类定义的基本语法如下: [Specifier] class ClassName[extends SuperClassName] [implements InterfaceName] { //类的域(成员变量)定义 //类的方法定义 … } 例如: public class School{ private ArrayList students; private void addStudent(Person person) { students.add(person); } } 广东工业大学计算机学院
域的定义 域(成员变量/属性/字段)定义的方式如下: [Specifier]typevariableName; 例如: int x = 3, y; //定义了整型变量x和y public Date today; //定义了Date型类变量today private Char [ ] m; //定义了字符型数组变量m 广东工业大学计算机学院
方法的定义 方法由方法头和方法体构成,方法定义的语法如下: [Specifier][static]returnTypemethodName([parameterList]) { //method body } 例如: private String getName(Person person) { …… return …; } public static void main(String[] args) { …… } 广东工业大学计算机学院
类定义举例 public class Person { // 方法定义 public String getName( ) { return name; } public void setName(String s) { name = s; } public double getIncome( ) { return salary; } public void setIncome(double d) { salary = d; } // 域定义 private String name; //姓名 private int sex; //性别 private double salary; //薪水 privateint age; //年龄 } 一种常用的编程风格是: 1. 方法位于域的前面 2.公有(public)方法位于所有方法的最前面 3. 一般情况下,将成员变量定义为private 广东工业大学计算机学院
final的类成员变量 • 被定义为final的类成员变量在对象初始化之后,不会再被修改。例如: public class Employee { …… private final String name; } • 注意:final修饰符大多应用于基本数据类型(primitive)的数据,或者不可变(immutable)类的域。如果类中每个方法都不会改变对象的状态,这种类就是不可变类。 广东工业大学计算机学院
final应用于可变对象有可能造成混乱 • 对于可变的类,使用final修饰符有可能对读者造成混乱。例如: public class Employee { private final Date hireDate; } • 此语句仅仅意味着定义了一个Date类型的引用hireDate,该引用在Employee对象初始化之后不能改变; • 但不是指该引用指向的hireDate对象的状态不能发生改变。 广东工业大学计算机学院
静态(static)域(1) • 如果将某个类中的域定义为static,那么该类的所有对象都会共享这个域。 • 例如:假定需要给每一个雇员赋予一个唯一的标识码,可对Employee类添加一个实例域id和一个静态域nextId。 public class Employee { private int id; private static int nextId = 1; } 广东工业大学计算机学院
静态(static)域(2) • 则每个雇员对象都有一个自己的Id域,但这个类的所有实例却共享一个nextId域。 nextId域有何用途? public void setId() { id = nextId; nextId++; } • 假定为harry雇员设定标识码:harry.setId();那么harry对象的Id域将被设置,并且静态域nextId的值加1. nextId的用途是:指示下一个雇员应当分配的ID。 广东工业大学计算机学院
静态域的注意事项 • 1. 静态(static)域不同于final域。静态不等于不变,静态域在程序运行过程中可以改变值。 • 2. 静态域在装载类的时候被分配内存并初始化,类只能被装载一次,所以静态变量在内存中只有一个拷贝,即使没有对象被建立,该静态域仍然存在;所有对象都共享一个静态域。 区别:非静态域在创建对象时被分配内存并初始化,所以每个对象都有各自的非静态域 • 3. 静态域用类名访问,而不是用对象访问。 广东工业大学计算机学院
常量 • 静态常量(类常量): public class Math { public static final double PI = ……; } 在程序中,可以通过Math.PI来访问该常量。 广东工业大学计算机学院
静态变量和实例变量示例 public class Count { public Count() { counter++; serialNumber = counter; System.out.println("My serialNumber is " + serialNumber); } public static void main(String args[]){ System.out.println("At first,counter="+ counter); Count count1=new Count(); System.out.println("after creat count1, counter="+counter); Count count2=new Count(); System.out.println("At last counter="+counter); System.out.println("count1.serialNumber="+count1.serialNumber); System.out.println("count2.serialNumber="+count2.serialNumber); System.out.println("count1.counter="+count1.counter); System.out.println("Count.counter="+counter); } private int serialNumber; private static int counter; } 广东工业大学计算机学院
方法的隐式与显式参数 public class Person { // 方法定义 …… public void setIncome(double d) { salary = d; } // 域定义 …… private double salary; privateint age; } • 如果新建一个对象: • Person menber007 = new Person(); • 并调用setIncome方法: • menber007.setIncome(8888.88); • setIncome方法有两个参数: • 隐式参数this • 显式参数double d 广东工业大学计算机学院
方法的注意事项(1) • 参数名可以与类的域名相同,如果相同,那么参数名将在方法体内隐藏同名的域。例如: public class Rectangle{ double x; double y; double computeArea(double x, double y){ double s = 0; s = x * y; return s; } } 当需要同时使用同名的方法参数和类的域名时,可以使用this关键字: double computeArea(double x, double y){ double s = 0; if (this.x > x) s = x * y; return s; } 广东工业大学计算机学院
方法的注意事项(2) 注意:不要编写返回引用可变对象的域的方法。 public class Employee { …… public Date getHireDay( ) { return hireDay; } private Date hireDay; } 当遇到下面的代码,就能使hireDay字段的封装性被破坏: Employee harry = new Employee(); Datedate = harry.getHireDay(); double tenYearsInMilliSeconds = 10 * 365.25 * 24 * 60 * 60 *1000; date.setTime(date.getTime() – (long)tenYearsInMilliSeconds); 广东工业大学计算机学院
Employee Date harry = name = salary = hireDay = years/months/days d = 破坏封装的过程 • 原因:上面的代码提供了另一条直接更改可变对象的状态的途径。 • 解决办法:对于可变对象,仅由访问器方法提供一个对象副本。 public class Employee { public Date getHireDay( ) { return (Date)hireDay.clone(); } private Date hireDay; } 经验:如果需要返回一个可变数据域的拷贝,就应该实现克隆。 广东工业大学计算机学院
方法的参数传递方式 • 在程序设计语言中,有两种常见的参数传递方式: • 1.值调用(call by value):表示方法接收的是调用者提供的值。 • 2.引用调用(call by reference):表示方法接收的是调用者特供的变量地址。 • Java采用的是值调用。即方法得到的是所有参数值的一个拷贝,方法并不能改变实参的值。 广东工业大学计算机学院
方法参数的类型 • 一个方法不能修改一个基本数据类型的参数。例如: public static doubleValue(double x) { x = 2 * x; } …… double percent = 10; doubleValue(percent); • 这样的调用语句并不能改变percent变量的值。 广东工业大学计算机学院
方法参数的类型(续) • 然而,方法参数有两种类型: • 基本数类型(数值、布尔值) • 对象引用 • 下列方法能够改变引用所指向的对象的状态: public static doubleValue(Employee e) { e.raiseSalary(200); //将e对象的薪金提高200 } …… Employee harry = new Employee(…); doubleValue(harry); • Java对“对象引用”这种参数仍然是使用值传递的方式。 广东工业大学计算机学院
Java对“对象引用”类型参数的传递 • 在Java中,对对象引用参数是采用值传递的方式。 public static void swap (Employee x, Employee y) { Employee temp = x; x = y; y = temp; } …… Employee alice = new Employee (“Alice”, …); Employee bob = new Employee (“Bob”, …); swap(alice, bob); …… • 在执行了swap(alice, bob)后,alice仍然是“Alice”,bob仍然是“Bob”。Why? • 原因是:Java采用值传递方式,将alice和bob的副本传给了swap方法作参数,而alice和bob是对象的地址。 广东工业大学计算机学院
Java中引用的值传递图示 在swap(x, y)中,引用x和引用y的值已经被交换; 但在swap(x, y)执行完毕后,x和y都被丢弃,原来的实参alice和bob的值不变。 广东工业大学计算机学院
静态方法 • 静态方法是不能向对象实施操作的方法。又称为类方法。 例如 public static int getNextId() { return nextId; } • 注意: 1. 静态方法没有this参数。 2. 静态方法不能操作任何实例对象。 3. 静态方法不能访问任何实例域。 4. 静态方法不属于任何对象。 广东工业大学计算机学院
静态方法注意 • 1. 静态方法也和静态变量一样,不需创建类的实例,可以直接通过类名被访问。 • 2. static方法不能被修饰成protected和abstract。 广东工业大学计算机学院
静态方法示例 public class GeneralFunction { public static int addUp(int x, int y) { return x + y; } } public class UseGeneral { public static void main (String[] args) { int a = 9; int b = 10; int c = GeneralFunction.addUp(a, b); System.out.println("addUp() gives " + c); } } 演示UseGeneral.java 广东工业大学计算机学院
Math类 • 所有的Math成员都是静态的, 不必为该类创建实例, 直接用 Math.method(variable) 调用这些方法 例如: int a=-1; a=Math.abs(a); // 将a作绝对值运算后所得的结果赋给a • public static double sin(double a) public static double cos(double a) public static double tan(double a) public static double asin(double a) public static double acos(double a) 广东工业大学计算机学院
对象的构造 • 对象的构造有几种方式: 1.构造器 2.在域的声明中赋值 3.初始化块 广东工业大学计算机学院
构造器(constructor) • 构造器(构造方法)- 用来初始化新创建的对象的方法,在创建对象时自动调用,名字与类名相同,无返回参数。 (即构造函数总是伴随着new操作符使用) 举例: class Employee { public Employee(String n, double s,) { name = n; salary = s; } private String name; private double salary; } Employee e=new Employee(“张三”,5000.0); 广东工业大学计算机学院
构造方法特点(1) • 所有的Java类都有构造方法,并且一个类可以包含一个或者多个构造方法。所有的构造方法的名字都与类名相同,但所带参数的个数和类型不同。(又称为重载构造方法) 举例: class Employee { public Employee(String n, double s, int year, int month, int day) { …… } public Employee(String n, double s,) { …… } } 广东工业大学计算机学院
构造方法特点(2) • 一个构造方法可以调用同一个类的另一个构造方法。 public class Employee { public Employee(String aName, double aSalary) { name = aName; salary = aSalary; } public Employee(double aSalary) { this(“Emplyoee #” + this.nextId, aSalary); //调用上一个构造方法 } public Employee( ) { } 。。。。。。 private String name; private double salary; private static int nextId; } • 注意:调用另一个构造方法的this语句必须放在构造方法的第一个语句。 广东工业大学计算机学院
默认的构造方法 • 在编写一个类的时候,如果没有编写构造方法,则系统会自动提供一个默认的构造方法。 • 默认构造方法:没有参数,其功能为将该类各域值初始化成Java规定的对应默认值(0,false, null)。 例如: 若Employee类没有定义构造方法,则默认有如下构造方法: public class Employee{ public Employee( ) { name = “”; salary = 0; hireDay = new Date(); } …… private String name; private double salary; Date hireDay; } 注意:若有编写构造方法,则不存在默认构造方法。 广东工业大学计算机学院
构造方法——小结 • 注意: 1. 构造器与类同名,没有返回值。(不用写出返回值为void,非构造函数则需要) 2. 每个类可以不显式定义构造方法。 3. 构造器可以有0个、1个或以上的参数。 4. 构造方法总是伴随着new操作符一起使用。 广东工业大学计算机学院
在域的声明中赋值 • 在域的声明语句中,可以同时给域赋一个初始值,这赋值语句会在创建对象时被自动执行。 例如: class Employee { public Employee ( ) { …… } private static int nextId=1000; private int id=0; } 广东工业大学计算机学院
初始化块 • 在一个类的声明中,可以有多个代码块,只要构造类的对象,这些块就会被执行。 • 例如: class Employee { public Employee ( ) { …… } private static int nextId; private int id; { id = nextId; nextId++; } } 注意:在构造对象的过程中,首先会运行初始化块,然后才运行构造器方法的主体部分。 广东工业大学计算机学院
静态初始化块 • 静态初始化块 - 在类第一次加载时(第一次放到类空间准备运行时),执行静态初始化块。静态初始化块只执行一次。 例如: class Employee { public Employee ( ) { …… } private static int nextId; private int id; static { Random generator = new Random; //为nextId赋一个随机值 nextId = generator.nextInt(10000); } } 广东工业大学计算机学院
对象初始化顺序 • 创建一个对象时,对该对象的初始化处理顺序如下: 1、执行静态初始化块;(只在创建第一个对象时执行一次); 2、所有数据被初始化为默认值 (0, false, null); 3、进入所调用构造方法(即方法参数赋值); 4、按照类定义中出现的次序依次执行所有域初始化语句和初始化块;(暂不执行构造方法中的语句) 5、如果所调用的构造方法调用了第二个构造方法,则执行第二个构造方法主体; 6、执行第一个构造方法的主体; 广东工业大学计算机学院
对象初始化顺序举例 class Employee { public Employee(String n, double s) { name = n; salary = s; } public Employee(double s) { this("Employee #" + nextId, s); int i=0; i=i+1; } …… private static int nextId; private int id=10; private String name = ""; private double salary; static { Random generator = new Random(); nextId = generator.nextInt(10000); } { id = nextId; nextId++; } } import java.util.*; public class ConstructorTest { public static void main(String[] args) { Employee[] staff = new Employee[2]; staff[0] = new Employee("Harry", 40000); staff[1] = new Employee(60000); //显示Employee对象的域值 …… } } 广东工业大学计算机学院
类的结束方法finalize() • 当一个对象没有任何引用指向它的时候,该对象就会被Java虚拟机认为是可回收的“垃圾”。 • Java有自动的垃圾回收机制,它实际上是一条虚拟机线程,周期性地把不再被引用的对象从内存中清除。 • 这个垃圾收集器是自动执行的,我们也可以通过调用系统类的System.gc()方法来显式地运行垃圾收集程序(比如在创建大量垃圾代码之后或者在需要大量内存代码之前运行垃圾收集器)。 • 在一个对象被系统垃圾收集器处理之前,对象也可调用自己的finalize()方法进行析构处理,这个过程就是所说的最后处理,也有的参考资料称之为结束方法。 广东工业大学计算机学院
类的结束方法finalize() • 尤其是结束方法在一般情况下是不需要的,而提供结束方法finalize()的目的是让程序员有机会释放掉不能被自动内存管理器直接使用的资源或是不能自动释放掉的资源。 • 但调用系统类的System.gc()方法,显式调用finalize()方法并不能保证垃圾回收线程立即被唤醒,实际情况与操作系统有关。 • Java中构造方法和结束方法在类中均是可选的。 广东工业大学计算机学院
本章内容 • 3.1 面向对象编程基础 • 3.2 类的编程实现 • 3.3 对象的使用 • 3.4 包 • 3.5 文档注释 • 3.6 类设计技巧 • 3.7 类的继承实例 • 3.8 多态 广东工业大学计算机学院
对象的使用1 • 可以用点“.”操作符来调用对象实例的域和方法。 1.域的引用 形式如下: objectreference.variablename; 例如: firstPerson.name = “Henry”; 2. 静态域的应用 className.variablename; 例如: System.out.println(“hello”); 广东工业大学计算机学院
对象的使用2 2.方法的调用 一般形式如下: objectreference.methodname(para1,para2,…) ; 例如: Person firstPerson = new Person(); firstPerson.setName(“Harry”); 3.静态方法的调用 className.methodname(para1,para2,…); 例如: double d= Math.pow(x,a);//计算x的a次幂; 广东工业大学计算机学院