• 1. 1面向对象的概念OO程序设计围绕以下几个核心概念: 抽象数据类型 类 类型层次(子类) 继承性 多态性
  • 2. 数据抽象类型2class Car { int color_number; int door_number; int speed; void brake() { … } void speedUp() {…}; void slowDown() { … } } 计算机中的对象的原型 现实生活中的对象
  • 3. 什么是类?类是描述对象的“基本原型”,它定义一种对象所能拥有的数据和能完成的操作,在面向对象的程序设计中,类是程序的基本单元。 程序中的对象是类的一个实例,是一个软件单元,它由一组结构化的数据和在其上的一组操作构成。 数据:即指对象的状态 操作:指对象的功能单元。 3
  • 4. 什么是消息?软件对象通过相互间传递消息来相互作用和通信。 一个消息由三部分组成: 1. 接受消息的对象 2. 要完成方法的名字 3. 方法需要的参数 4
  • 5. 实例class Hello { private String s; public void showString () { System.out.println(s);} public void changeString(String str) { s=str; return s;} } 5在程序中操作对象是类的一个实例:即对象 创建一个对象 Hello obj=new Hello(); 调用方法 obj.showString(“Hello World!”)
  • 6. OO概念 – 封装封装就是指利用抽象数据类型将数据和基于数据的操作封装在一起,数据被保护在抽象类型的内部,系统的其他部分只有通过包裹在数据外面的被授权的操作,才能够与这个抽象数据类型交流与交互!6
  • 7. OO概念 – 继承继承实际上是存在于面向对象程序中的两个类之间的关系。当一个类拥有另一个类的所有数据和操作时,就称这两个类之间具有继承关系! 子类(派生类):作为另一个类(父类、超类)的扩充或修正所定义的一个类 7
  • 8. OO概念 – 多态(Polymorphism)指的是同样的消息能被不同对象接收,不同的对象做出不同的响应。 分类: 子类型多态(覆写,override) 类型参数化多态(重载,泛型) 8博大精深!
  • 9. Java 类概念:对象的模板或蓝图 Java类所包含的成员: 构造器(constructor) 成员变量(field) 成员方法 静态初始化块 内部类(inner class) 常量9
  • 10. 类声明(定义)10类声明语法: [ 类修饰符] class 类名 [ extends 超类名 ] [ implements 接口名 ] { 成员变量定义; 构造器定义; 方法定义; 常量定义; 内部类定义 }
  • 11. 类声明(续)11类修饰符(Modifier): public:允许其他类(没有限制)访问本类,一个源文件仅可以有一个public类 abstract:不能实例化的抽象概念类 final:不能再被扩展,不包含子类的类;易于安全性的实现,或用于创建固定功能的类 缺省:可被当前包中的其他类访问 父类继承声明:extends 父类名 实现接口(interface):implements 接口名
  • 12. 类成员变量的声明12声明成员变量〔member〕的语法 [修饰符] 数据类型 变量名; 引用:对象名.变量 修饰符 访问控制符 public:可被所有其他类引用 private:仅可被该类自身引用和修改,不能被其他任何类(包括子类)引用 protected:该类自身、子类、同一包中的其他类 缺省:本包中的类 static:类成员变量,对所有的实例一致,引用是前缀可使用类名或对象名 final:数值不变常量,定义同时应对其进行初始化
  • 13. 类成员变量的声明(续)13例: class shape{    private int x;    private int y;    static final float MaxArea=100.0f; …………………….. }常量定义,通常采用”final static”修饰,为什么?
  • 14. 方法声明14定义对类内成员变量(数据)的操作 方法声明的语法: [修饰符] 返回类型 方法名(参数列表) [ throws 例外名 ] { 方法体; } 谁可以调用方法、接受哪些参数、如何返回信息
  • 15. 方法声明(续)15修饰符(Modifier): 访问控制符: public、private、protected static:静态方法,又称类方法 使用类名或对象名作为前缀,建议使用类名 在方法体中只能使用static变量和static方法 abstract:只有接口没有语句,要在子类中通过重新定义(override)来实现 final:不能被重新定义(override)
  • 16. 方法声明(续)16返回值类型:方法要返回的结果的数据类型。 返回值:方法在执行完毕后返还给调用它的程序的数据,return。 void:指明方法无返回值 参数列表:值传递 形式参数:在方法被调用时用于接收外部传入的数据的变量。 参数类型:就是该形式参数的数据类型。 实参:调用方法时实际传给方法形式参数的数据。 throws:声明方法的异常规格 通告本方法中会产生的例外(异常)类型,提醒调用者要对相应的可能例外进行处理。当执行此方法并发生了例外时,程序会转入调用者编制的例外处理程序段。
  • 17. 方法声明(续)17示例: class shape{    private int x;    static float MaxArea=100.0f;    public void setx(int newx){x=newx;}    public static void setMA(float newMA){         MaxArea=newMA;    }    public final getx( ){return x} }
  • 18. 练习18编写一个Shape类,使他具有一个方法为: public int getArea(int i, int j) 并返回i * j的值。 再从外部调用这个方法 传入相应参数,并打印出结果值
  • 19. 方法调用19方法调用的格式 在方法中使用return提前返回 方法调用的过程分析
  • 20. 方法重载20方法的重载就是在同一个类中允许同时存在一个以上的同名方法,只要它们的参数个数或类型不同即可。 如: public class Test { public static void main(String [] args){ int isum; double fsum; isum=add(3,5); isum=add(3,5,6); fsum=add(3.2,6.5); } public static int add(int x,int y) { reutrn x+y; } public static int add(int x,int y,int z) { return x+y+z; } public static double add(double x,double y) { return x+y; } }
  • 21. 方法的覆盖(override)21方法覆盖即指在子类中重新实现父类中已有的方法。 Java运行时系统根据调用该方法的实例的类型来决定调用哪个实现。 方法覆盖时应遵循的原则: 覆盖后的方法不能比被覆盖的方法有更严格的访问条件。
  • 22. override22覆盖使得在子类中可以重新定义父类中已有的方法,从而是子类具有自己的行为。class Employee { protected String name; public void showInfo() { System.out.println(name); } } class Manager extends Employee {  private String department; public void showInfo() { System.out.println(name); System.out.println(“Manager of ” + department); } }
  • 23. Override 练习23有一个父类Car,内有属性: int maxSpeed 方法:void stop(); 有两个子类BMW, QQ继承父类 请调用父类构造方法,初始化赋值maxSpeed 请重写stop()方法,要求 BMW当maxSpeed >= 300; 打印语句“停车” QQ当maxSpeed >= 120; 打印语句“停车”
  • 24. 静态变量24当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。有时候我们希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份,例如所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量。 练习:编写使用静态变量统计一个类产生的实例对象的个数的程序
  • 25. 静态方法25在静态方法里只能直接调用同类中其它的静态成员(包括变量和方法),而不能直接访问类中的非静态成员。这是因为,对于非静态的方法和变量,需要先创建类的实例对象后才可使用,而静态方法在使用前不用创建任何对象。 静态方法不能以任何方式引用this和super关键字。与上面的道理一样,因为静态方法在使用前不用创建任何实例对象,当静态方法被调用时,this所引用的对象根本就没有产生。 main() 方法是静态的,因此JVM在执行main方法时不创建main方法所在的类的实例对象,因而在main()方法中,我们不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员,这种情况,我们在以后的例子中会多次碰到。
  • 26. 静态初始化块26一个类中可以使用不包含在任何方法体中的静态代码块(static block ),当类被载入时,静态代码块被执行,且只被执行一次,静态块经常用来进行类属性的初始化。 类中的静态代码块被自动执行,尽管我们产生了类的多个实例对象,但其中的静态代码块只被执行了一次。当一个程序中用到了其他的类,类是在第一次被使用的时候才被装载,而不是在程序启动时就装载程序中所有可能要用到的类。
  • 27. static block练习27下面这个类声明了静态变量,并且使用了静态代码块初始化变量 public class StaticClass { private static int i; static { i = 3; } public static void main(String[] args) { System.out.print(StaticClass.i); } }
  • 28. 实现类的封装性28如果外面的程序可以随意修改一个类的成员变量,会造成不可预料的程序错误。 在定义一个类的成员(包括变量和方法)时,使用private关键字说明这个成员的访问权限,这个成员成了类的私有成员,只能被这个类的其他成员方法调用,而不能被其他的类中的方法所调用。 为了实现良好的封装性,我们通常将类的成员变量声明为private,再通过public的方法来对这个变量进行访问。对一个变量的操作,一般都有读取和赋值操作,通常,一个是getXxx()(Xxx表示要访问的成员变量的名字),用来读取这个成员变量操作,另外一个是setXxx()用来对这个成员变量赋值。 一个类通常就是一个小模块,我们应该让模块仅仅公开必须要让外界知道的内容,而隐藏其它一切内容。我们在进行程序的详细设计时,应尽量避免一个模块直接修改或操作另一个模块的数据,模块设计追求强内聚(许多功能尽量在类的内部独立完成,不让外面干预),弱耦合(提供给外部尽量少的方法调用)。用总统指挥一支军队的例子来说明这种效果。
  • 29. 类的封装带来的优点29隐藏类的实现细节; 让使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作; 便于修改,增强代码的可维护性;
  • 30. 对象30Person p1 = new Person();执行完后的内存状态
  • 31. 对象创建31当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值。除了基本数据类型之外的变量都是引用类型,如上面的Person及前面讲过的数组。
  • 32. 对象的使用32创建新的对象之后,我们就可以使用“ 对象名.对象成员 ”的格式,来访问对象的成员(包括属性和方法) class TestPerson { public static void main(String[] args) { Person p1 = new Person(); Person p2 =new Person(); p1.age = -30; p1.shout(); p2.shout(); } } 程序运行的内存格局如右图
  • 33. 对象生命周期33与基本类型的生命周期一样
  • 34. 对象比较34“==”运算符与equals()方法的区别 怎样比较两个数组对象的内容是否相等 调用Arrays.equals()
  • 35. 构造方法的定义与作用 35构造方法的特征 它具有与类相同的名称; 它不含返回值; 它不能在方法中用return语句返回一个值 注意:在构造方法里不含返回值的概念是不同于“void”的,在定义构造方法时加了“void”,结果这个方法就不再被自动调用了。 构造方法的作用:当一个类的实例对象刚产生时,这个类的构造方法就会被自动调用,我们可以在这个方法中加入要完成初始化工作的代码。
  • 36. 构造方法的重载 36和一般的方法重载一样,重载的构造方法具有不同个数或不同类型的参数,编译器就可以根据这一点判断出用new 关键字产生对象时,该调用哪个构造方法了。 创建对象的格式是:new 类名(参数列表) ; 重载构造方法可以完成不同初始化的操作。 如:p3=new Person(“Tom”,18);语句,会做这样几件事:创建指定类的新实例对象,在堆内存中为实例对象分配内存空间,并调用指定类的构造方法,最后将实例对象的首地址赋值给引用变量p3。
  • 37. 构造方法的一些细节37在java每个类里都至少有一个构造方法,如果程序员没有在一个类里定义构造方法,系统会自动为这个类产生一个默认的构造方法,这个默认构造方法没有参数,在其方法体中也没有任何代码,即什么也不做。 由于系统提供的默认构造方法往往不能满足编程者的需求,我们可以自己定义类的构造方法,来满足我们的需要,一旦编程者为该类定义了构造方法,系统就不再提供默认的构造方法了。 声明构造方法,如无特殊需要,应使用public关键字,在我们前面例子中,可以使用private访问修饰符吗?
  • 38. this38如果func2方法被调用 ,一定是事先已经有了一个存在的对象,func2被作为那个对象的方法被使用。 在func2内部能引用别的对象 ,同样也能引用func2所属的那个对象。 在func2中,自己所属的那个对象的引用名称是什么呢? this关键字在java程序里的作用和它的词义很接近,它在方法内部就是这个方法所属的对象的引用变量。
  • 39. this引用句柄的存放位置39 每个成员方法内部,都有一个this引用变量,指向调用这个方法的对象,类中的成员方法与this之间的关系如图
  • 40. this的应用40一个类中的成员方法可以直接调用同类中的其他成员,其实我们在一个方法内使用“this.成员”的引用方式和直接使用“其他成员”的效果是一样的,那this还有多大的作用呢?在有些情况下,我们还是非得用this关键字不可的 : 让类的成员变量名和对其进行赋值的成员方法的形参变量同名是必要的,这样的代码谁看了都能明白这两个变量是彼此相关的,老手看到方法的定义,就能揣摩出方法中的代码,大大节省了别人和自己日后阅读程序的时间。 假设我们有一个容器类和一个部件类,在容器类的某个方法中要创建部件类的实例对象,而部件类的构造方法要接收一个代表其所在容器的参数。 class Container { public void xxx() { new Component(this); } } 在构造方法里调用其他构造方法:this(参数列表)
  • 41. 类的继承41继承使得子类可以利用父类中定义的方法和变量,就像它们属于子类本身一样。class Employee { protected String name; public void showInfo() { System.out.println(name); } } class Manager extends Employee { private String department; public void showInfo() { System.out.println(name); System.out.println(“Manager of ” + department); } }
  • 42. 继承42继承性是面向对象程序设计语言的一个基本特征,通过继承可以实现代码的复用。继承而得到的类为子类,被继承的类为父类,父类包括所有直接或间接被继承的类。Java中不支持多重继承。通过在类的声明中加入extends子句来创建一个类的子类: class SubClass extends SuperClass { } 如果省略extends子句,则该类为Object的子类。 子类可以继承父类中访问权限设定为public、protected和default的成员变量和方法,但是不能继承访问权限为private的成员变量和方法。
  • 43. 调用父类构造方法43super(x,…); 调用父类构造方法时应遵循的原则: 只能在子类中调用父类的构造方法. 调用父类构造方法时,必须使用super(…) 不要在父类构造方法前放任何子类构造方法代码。 如果子类中没有调用父类构造,会默认调用无参数的super()
  • 44. 接口44“对实现我的类,看起来都应该是我的模样” 接口规定了一个类的基本形式:常量,方法.但不规定方法的实现(定义). 接口的数据类型:都默认为”final static” 只是一种形式,不涉及细节 可用来实现不同类之间的常量共享 引入接口的目的是为了克服Java单继承机制带来的缺陷,实现类的多继承的功能
  • 45. 接口(续)45[public/abstract] interface interfaceName [extends SuperInterfaceList] { …… //常量定义和方法定义 } 接口的修饰符可以是public或abstract,其中public或abstract可以缺省。public的含义与类修饰符是一致的。但是缺省public或abstract修饰符时,定义的接口只能被同一个包中的其他类和接口使用。接口(interface)作为特殊形式的抽象类,和类(class)在使用上具有类似的约束。 一个public接口只能定义在同名的.java文件中
  • 46. 接口(续)46下面是一个接口定义的例子: public interface Shape { float width=9.8f; float height=6.6f; public float girth(); public float area(); } 上面程序段定义了一个名为Shape的接口,其中有两常量width和height,以及两个抽象方法girth()和area()。 与类一样,接口也具有继承性。定义接口时可以使用extends关键字定义该新接口是某个已经存在的父接口的派生接口,它将继承父接口的所有属性和方法。与类的单继承不同,一个接口可以有多个父接口,接口名称之间用“,”分隔。新的接口将继承所有父接口的属性和方法。
  • 47. 类对接口的实现47用implements子句来表示一个类实现某个接口。 在类体中可以使用接口中定义的常量,而且非抽象类必须实现接口中定义的所有方法。 利用接口可实现多重 继承,即一个类可以实现多个接口,在implements子句中用逗号分隔。实现接口时,需要注意以下问题: 1.如果实现接口的类不是抽象类,那么在类的定义部分必须实现接口中定义的所有方法,并给出具体的实现代码。这是因为非抽象类中不可以存在抽象方法。 2.如果实现接口的类是abstract修饰的抽象类,那么它可以不实现该接口的所有抽象方法。 3.在实现接口方法时,必须将方法声明为公共方法(public),而且还要将方法的参数列表、名称和返回值与接口中定义的完全一致。 4.如果在实现接口的类中所实现的方法与抽象方法有相同的方法名称和不同的参数列表,则只是重载了一个新的方法,并没有实现接口中的抽象方法。 5.接口的抽象方法的访问修饰符规定为public,则类在实现这些抽象方法时,必须显式地使用public修饰符,否则系统提示出错警告。 6.如果接口中的方法的返回类型不是void,则在类中实现该方法时,方法体中至少要有一条return语句。
  • 48. 接口 练习48接口的实现示例。 interface Shape //定义一个接口Shape { double PI=3.14; void print(); } class Circle implements Shape // 实现接口Shape { public void print() { System.out.println("我实现了接口"+PI); } } public class InterfaceImplementDemo { public static void main(String args[]) { Circle circle=new Circle(); circle.print(); } }
  • 49. 接口实例49// Jpro8_7.java interface CanFight { void fight(); } interface CanSwim { void swim(); } interface CanFly { void fly(); } class ActionCharacter { public void fight() { System.out.println("can fight!"); } } class Hero extends ActionCharacter implements CanFight,CanSwim,CanFly { public void swim() { System.out.println("can swim"); } public void fly() { System.out.println("can fly"); } }
  • 50. 接口实例(续)50public class Jpro8_7 { public static void t(CanFight x) { x.fight(); } public static void u(CanSwim x) { x.swim(); } public static void v(CanFly x) { x.fly(); } public static void w(ActionCharacter x) { x.fight(); } public static void main(String args[]) { Hero h=new Hero(); t(h); u(h); v(h); w(h); } }
  • 51. 覆盖与重载51多态:同名的不同方法共存 重载(overload):同名方法被多次重新定义 同名提高了抽象程度,降低维护工作量 定义、调用时如何区别被重载的方法 同类中的同名方法 用不同的参数列表来区别同名的不同方法 不能用返回值(可忽略)来区别 不同类中的同名方法:冠以类名以示区别
  • 52. 练习任务52银行业务的程序结构 银行帐户类BankAccount 数据:余额、利率 操作:查询余额、存款、取款 查询利率、设置利率(选做) 主类UseAccount main()方法,创建BankAccount 类的对象,并完成相应操作
  • 53. 练习任务53实现以下的类 toString() 为返回所有内容。 写个测试类 TestEmployee
  • 54. 练习任务54在之前的基础上,增加红色部分的内容。 toString() 为返回所有内容。 getMonthlyPay() 为抽象方法。 SalesEmployee.getMonthlyPay() monthlyPay = salary + (perfit * 20%) Manager.getMonthlyPay() monthlyPay = salary + bonus 写个测试类 TestEmployee
  • 55. 抽象类55抽象类的定义与一般类一样都有数据和方法,定义格式与一般类也非常类似,只是在定义类的class前增加一个关键字abstract就表示定义一个抽象类,即用abstract说明的类称为抽象类。 例如,定义一个抽象类Animal。 public abstract class Animal { String name; int age; public abstract void go() { } }
  • 56. 抽象类(续)56抽象方法一定包含在抽象类中,抽象方法同样不能直接实现,它只能在子类中被实现。 接口类似于抽象类,只是接口中的所有方法都是抽象的。这些方法必须由实现这一接口的类来实现。 Java接口和Java抽象类最大的一个区别,就在于Java抽象类可以提供非抽象方法方法的实现,而Java接口中的所有方法都是抽象的。所以,如果向一个抽象类里加入一个新的具体方法时,那么它所有的子类都能很快得到这个新方法,而Java接口做不到这一点,如果向一个Java接口里加入一个新方法,所有实现这个接口的类就无法成功通过编译了,因为必须让每一个类都再实现这个方法才可以。
  • 57. 抽象类实例57例8.6下面例子定义一个抽象类,然后通过继承实现该抽象类。 abstract class Animal { String name; abstract void go() ; } class Cat extends Animal { Cat(String name) { this.name=name; } public void go() { System.out.println(name+" can run.") ; } } class Bird extends Animal { Bird(String name) { this.name=name; } public void go() { System.out.println(name+" can fly.") ; } } public class Jpro8_6 { public static void main(String args[]) { Cat c = new Cat("Cady") ; Bird b = new Bird("Bird") ; c.go() ; b.go() ; } }