《8面向对象程序设计进阶(下)a.ppt》由会员分享,可在线阅读,更多相关《8面向对象程序设计进阶(下)a.ppt(43页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、静态(static)static关键字1、修饰变量 静态变量(类变量)country=“中国”在JVM中,该变量只有一份拷贝,通过任何该类的实例或类本身去修改静态变量的值都是在修改同一个值2、修饰方法(静态方法)A、可以通过类直接访问B、静态方法只能直接访问其它的静态变量或静态方法.3、修饰块(静态块)一个类中可以使用不包含在任何方法体中的静态代码块(static block),当类被载入时,静态代码块被执行,且只被执行一次,静态块经常用来进行类属性的初始化。静态(static)Static 静态变量:当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过ne
2、w关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份,例如所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量。静态(static)静态方法:1.在静态方法里只能直接调用同类中其它的静态成员(包括变量和方法),而不能直接访问类中的非静态成员。这是因为,对于非静态的方法和变量,需要先创建类的实例对象后才可使用,而静态方法在使用前不用创建任何对象。2.静态方法不能以任何方式引用this和super关键字
3、。与上面的道理一样,因为静态方法在使用前不用创建任何实例对象,当静态方法被调用时,this所引用的对象根本就没有产生。3.main()方法是静态的,因此JVM在执行main方法时不创建main方法所在的类的实例对象,因而在main()方法中,我们不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员,这种情况,我们在以后的例子中会多次碰到。静态(static)理解main方法由于java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public,又因为java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static的
4、,该方法接收一个String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数。静态(static)静态块一个类中可以使用不包含在任何方法体中的静态代码块(static block),当类被载入时,静态代码块被执行,且只被执行一次,静态块经常用来进行类属性的初始化。例如类加载时的初始化工作,那些一次性加载不再作修改的内容。(构造器通常作实例变量初始化)类中的静态代码块被自动执行,尽管我们产生了类的多个实例对象,但其中的静态代码块只被执行了一次。final1、修饰变量(常量)2、修饰方法A、该方法不能被覆盖B、JVM会对final方法自动优化,其执行效率会比普通方法更高3、修饰
5、类类不能被继承抽象类(abstract)Java中可以定义一些不含方法体的方法,它的方法体的实现交给该类的子类根据自己的情况去实现.这样的方法就是抽象方法,包含抽象方法的类就叫做抽象类。一个类中可以有一个或多个抽象方法。抽象类(abstract)A、抽象方法只需声明,而不需实现。含有抽象方法的类必须被声明为抽象类,抽象类的子类必须覆盖所有的抽象方法后才能被实例化,否则这个子类也必须声明为抽象类。B、抽象类不能实例化(即就是不能用new关键字去产生对象),抽象类的作用就是为了被继承C、抽象类可以包含具体方法D、当一个类继承抽象类时,必须实现抽象类中的所有抽象方法,否则,这个子类也必须声明为一个抽
6、象类注意:含有抽象方法的类肯定是抽象类,而抽象类不一定注意:含有抽象方法的类肯定是抽象类,而抽象类不一定包含抽象方法包含抽象方法.动态绑定静态绑定,就是前期绑定,也叫编译期绑定 编译的时候,已经确切知道调用的是哪个类的哪个方法。动态邦定 又叫后期绑定 也叫运行时绑定。简单的说 就是在编译的时候不知道具体调用的是哪个方法(是父类的还是子类的,因为继承有个方法重写的问题)java默认的是后期绑定默认的是后期绑定,不加特殊的修饰关键字,所有的方法子类都是可以重写的。静态绑定是在编译时绑定,而动态绑定是在运行时根据对象的实际情况来选择绑定父类或者是某个子类的方法。在执行效率上,静态绑定要优于动态绑定,
7、但丧失了灵活性。Java中变量是静态绑定的,实例方法是动态绑定的中变量是静态绑定的,实例方法是动态绑定的。在进行“向上转型”的时候子类会覆盖父类的实例方法而不会覆盖父类的变量接口(interface)如果一个抽象类中的所有方法都是抽象的,我们就可以将这个类用另外一种方式来定义,也就是接口定义。接口是抽象方法和常量值的定义的集合,从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。但是接口和抽象类的意义就有非常大的区别但是接口和抽象类的意义就有非常大的区别接口(interface)A、接口中所有方法都是抽象方法(abstract关键字可以省略)B、接口
8、中可以有属性,所有属性将默认包含public、static、final修饰符C、我们可以定义一个新的接口用extends关键字去继承一个已有的接口,我们也可以定义一个类用implements关键字去实现一个接口中的所有方法,我们还可以去定义一个抽象类用implements关键字去实现一个接口中定义的部分方法。D、如果一个类实现了某个接口而未能实现接口中定义的所有抽象方法,则该类必须声明为抽象类E、一个类可以继承一个父类的同时,实现一个或多个接口,extends关键字必须位于implemnets关键字之前。(Java多继承的实现多继承的实现)接口(interface)为什么接口里面只能定义常量?
9、为什么接口里面只能定义常量?接口就是提供一种统一的”协议”,而接口中的属性也属于“协议”中的成员。它们是公共的,静态的,最终的常量。相当于全局常量。如果接口可以定义变量,但是接口中的方法又都是抽象的,在接口中无法通过行为来修改属性。有的人会说了,没有关系,可以通过实现接口的对象的行为来修改接口中的属性。这当然没有问题,但是考虑这样的情况。如果接口 A 中有一个public 访问权限的静态变量 a。按照 Java 的语义,我们可以不通过实现接口的对象来访问变量 a,通过 A.a=xxx;就可以改变接口中的变量 a 的值了。那么实现接口 A 的所有对象也都会自动拥有这一改变后的 a 的值了,也就是
10、说一个地方改变了 a,所有这些对象中 a 的值也都跟着变了。这和抽象类有什么区别呢,怎么体现接口更高的抽象级别呢,怎么体现接口提供的统一的协议呢,那还要接口这种抽象来做什么呢?所以接口中不能出现变量,如果有变量,就和接口提供的统一的抽象这种思想是抵触的。所以接口中的属性必然是常量,只能读不能改,这样才能为实现接口的对象提供一个统一的属性。你认为是要变化的东西,就放在你自己的实现中,不能放在接口中去,接口只是对一类事物的属性和行为更高层次的抽象。接口(interface)在Java中设计接口的目的是为了让类不必受限于单一继承的关系,而可以灵活地同时继承一些共有的特性,从而达到多继承的目的,并且避
11、免了C+中多继承的复杂关系所产生的问题(多重继承的危险性在于一个类有可能继承了同一个方法的不同实现,对于接口来说就决不会发生这种情况,因为接口是没有任何实现的)。接口使得程序更加灵活,最终带来很大的自由.接口(interface)抽象类里面用来定义一些公共的功能。抽象类可以理解为一个框架,根据他来派生出活生生的具体的子类.由这些具体的类在派生出新的类来适应新的要求.如果向一个抽象类里加入一个新的具体方法时,那么它所有的子类都一下子都得到了这个新方法.而Java接口做不到这一点,如果向一个Java接口里加入一个新方法,所有实现这个接口的类就无法成功通过编译了,因为你必须让每一个类都再实现这个方法
12、才行,这显然是Java接口的缺点.接口(interface)接口实际上是定义一个规范、标准。接口实际上是定义一个规范、标准。通过接口可以实现不同层次、不同体系对象的共同属性;以JAVA数据库连接为例子:JDBC制定标准;数据厂商实现标准;用户使用标准。接口通常用来屏蔽底层的差异。接口也因为上述原因被用来保持架构的稳定性.而接口(对象必须实现的承诺)与实现(对象如何履行这些承诺)相分离,允许多个类提供相同的功能,允许一个类同时实现多个接口,最终带来很大的自由.好的接口定义应该是具有专一功能性的,而不是多功能的,否则造成好的接口定义应该是具有专一功能性的,而不是多功能的,否则造成接口污染。接口污染
13、。(如果一个类只是实现了这个接口的中一个功能,而不得不如果一个类只是实现了这个接口的中一个功能,而不得不去实现接口中的其他方法,就叫接口污染去实现接口中的其他方法,就叫接口污染)多态 polymorphism 一个对象多种形态。一个对象多种表现方式。多态是面向对象里面非常重要的一个概念。多态多态分静态多态和动态多态。静态的多态就是指函数的重载,动态的多态就是指方法的覆盖。class Test void print()System.out.println(hello world);void print(int x)System.out.println(hello world+i);public
14、static void main(String args)Test ts=new Test();ts.print();ts.print(10);上面的程序就是在一个类中成员方法的重载例子。也就是一个静态的多态。系统会在你编译的时候根据你调用的方法的参数列表来动态的决定调用那一个函数。多态多态分静态多态和动态多态。静态的多态就是指函数的重载,动态的多态就是指方法的覆盖。class Test void print()System.out.println(hello Test);class A extends Test void print()System.out.println(hello A);
15、public static void main(String args)Test t=new A();t.print();这时由于子类覆写了父类的方法,所以调用的是子类覆写后的方法。这是动态的多态。多态多态有分两种:编译时多态:Ainmal ainmal=new Dog();运行时多态:ainmal.sleep();Animal a=new Dog();(编译时看左边)a.sleep();(运行时看右边)多态Animal a=new Dog();Dog d=(Dog)a。(强制转换)关系运算符:instanceofa instanceof Animal;(这个式子的结果是一个布尔表达式)a为对
16、象变量,Animal是类名。上面语句是判定a是否是Animal的子类。如果是则返回true,否则返回false。instanceof用于判断前面的对象变量是否是后面类的子类或者实现了同一个接口。多态对象的类型转换对象的类型转换A.子类能自动转换成父类。除此之外,程序还可以直接创建一个子类的实例对象,传递给需要父类的实例对象作为参数的方法,在参数传递过程中发生了隐式自动类型转换。理解子类能够自动转换成父类:人是父类,男人是子类。B.父类转换成子类需要进行强制类型转换。理解父类转换成子类需要进行强制类型转换:一个男人肯定是人,一个人却不一定是男人。在不确定一个人是男人还是女人的时候强行使用男人或女
17、人的特定方法是会出现问题的,所以编译不通过。在强制类型转换时,程序员是要对转换完后的后果负责的,也就是要确保在内存中存在的对象本身确实是可以被转换的类型,否则即使编译通过,运行还是会出错的。强制类型转换的前提是程序员提前就知道要转换的父类引用类型对象的本来面目确实是子类类型的。C.instanceof操作符对象 instanceof 类(或接口)返回值:ture or false 多态Java是静态语言,也就是说程序的运行结果是在编译时决定的,运行时是不可以改变的。那如何让Java语言具有动态语言的特点,能够在运行时动态改变程序运行的结果呢?多态性是OOP中的一个重要特性,主要是用来实现动态联
18、编的,换句话说,就是程序的最终状态只有在执行过程中才被决定而非在编译期间就决定了。使用多态就可以使用多态就可以在运行时为我们所需要的功能提供不同的实现在运行时为我们所需要的功能提供不同的实现.这样可以提这样可以提高程序的灵活性和扩展性。高程序的灵活性和扩展性。多态思考:子类的功能可以被父类的方法或引用变量调用,这叫做向后兼容向后兼容,可以提高程序的可扩充性和可维护性。以前写的程序可以被后来的程序调用不足为奇,现在写的程序能够调用以后写的程序(调用以后编写的子类)就非常了不起了。设计模式设计模式设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就想
19、是经典的棋谱,不同的棋局,我们用不同的棋谱,免得我们自己再去思考和摸索。失败为成功之母,但是要以大量的时间和精力为代价,如果有成功经验可借鉴,没有人再愿意去甘冒失败的风险,我们没有理由不去了解和掌握设计模式,这也是Java开发者提高自身素质的一个很好选择。使用设计模式也许会制约你去创新,但是创新业炫耀去了解和借鉴前人的成功经验。设计模式设计模式单例模式单例模式 Singleton所谓单例模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。设计模式设计模式单例模式的实现1.一个静态变量指向自己。2.私有构造器保证不能从外部创建对象。3.一个静态方法返回实例对象。设计模式
20、模版设计模式模版设计模式在类中定义了某个算法的骨架,但不具体实现,而在其子类中实现例如,银行计算利息,都是利率乘以本金和存款时间,但各种存款方式计算利率的方式不同,所以,在账户这个类的相关方法里,只搭出算法的骨架,但不具体实现。具体实现由各个子类来完成。模版设计模式例子abstract class LoanAccount/利息,本金private double Interest,Fund;public double calculateInterest()/取得利率double interest=getInterestRate();/用于计算利息的算法:本金*利率,但是利率的算法实现并没有在这个
21、类中实现Interest=getFund()*getInterestRate();return Interest;/*不同的存款类型有不同的利率,因此,不在这个父类中实现利率的计算方法,*而将它推迟到子类中实现*/protected abstract double getInterestRate();设计模式工厂模式工厂模式工厂模式就是在声明的时候不知道到要什么对象 在使用的时候再实例化!采用接口或者基类调用!以提高代码的复杂度为代价来增强灵活性、可复用性,维护的时候非常方便.它为系统结构提供了灵活的动态扩展机制它为系统结构提供了灵活的动态扩展机制.例子:fruit,farmer设计模式工厂模
22、式的实现:工厂模式根据工厂模式实现的类可以根据提供的数据生成一组类中某一个类的实例,通常这组类有一个公共的抽象父类或接口并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作。首先需要定义一个基类,该类的子类通过不同的方法实现了基类中的方法,然后需要定义一个工厂类,工厂类可以根据条件生成不同子类的实例。得到实例后,可以调用基类的方法而不必考虑到底返回的是哪个子类的实例。设计模式命令模式命令模式某个方法需要完成某个功能,完成这个功能的大部分步骤已经确定了,但是有少量步骤无法确定,必须等到执行方法时才能确定。例如:需要遍历一个数组,但是遍历完后做什么还不确定,我们必须把处理行为作为参数传
23、进去。实现方法和行为相分离,使程序更加灵活。封装类简单数据类型封装类 boolean Boolean byte Byte short Short int Integer long Long char Character float Float double Double对于简单类型数据,Java对它们进行了封装,使它们都有相应的封装类封装类的例子(案例6-11)public class WrapperClasspublic static void main(String args)Integer i=new Integer(10);Integer j=new Integer(10);Syste
24、m.out.println(i=j);内部类定义在类里面的类。成员内部类静态内部类局部内部类匿名内部类内部类成员内部类成员内部类 依赖于外部类存在依赖于外部类存在当一个类中的程序代码要用到另外一个类的实例对象,而另外一个类中的程序代码又要访问第一个类中的成员,将另外一个类做为第一个类的内部类,程序代码就要容易编写的多。1、可以访问外部类中所有的成员变量,所有的成员方法2、可以有自己的成员变量;(非静态)3、可以有自己的方法.(非静态)4、不能有自己的静态属性和静态方法;何时选用内部类:假如更多是内部外部类相互调用,很少涉及第3方调用。选择成员内部类问题为什么外部类不能访问成员内部类的实例属性?
25、为什么外部类不能访问成员内部类的实例属性?答:因为当成员内部类对象存在时,外部类肯定存在,而当外部类对象答:因为当成员内部类对象存在时,外部类肯定存在,而当外部类对象存在时,成员内部类的对象不一定存在。存在时,成员内部类的对象不一定存在。内部类静态内部类:静态内部类:1、只能访问外部类中静态的属性和方法。、只能访问外部类中静态的属性和方法。2、如果创建对象不需要外部类的对象就可以创建、如果创建对象不需要外部类的对象就可以创建;3、可以直接调用静态内部类中的静态方法、可以直接调用静态内部类中的静态方法.外部类名外部类名.内部类名内部类名.方法名方法名4、也可以有非静态的属性和方法、也可以有非静态
26、的属性和方法;但是在静态方法中不能调用非静态但是在静态方法中不能调用非静态的属性的属性;如果需要使用非静态的方法或属性需要对象进行调用;如果需要使用非静态的方法或属性需要对象进行调用;何时选择静态内部类何时选择静态内部类:假如更多只是面向第假如更多只是面向第3方客户方客户,而内部外部类相互调用机会较少选择静而内部外部类相互调用机会较少选择静态内部类。态内部类。问题为什么静态内部类实例方法也不能访问外部类的实例属性呢?为什么静态内部类实例方法也不能访问外部类的实例属性呢?答:因为静态内部类是和外部类相关的,而不是和外部类的对象相关答:因为静态内部类是和外部类相关的,而不是和外部类的对象相关的。也
27、就是说,当静态内部类的对象存在时,也许外部类的对象并不的。也就是说,当静态内部类的对象存在时,也许外部类的对象并不存在,静态内部类的对象里只有外部类的引用,而没有外部类对象的存在,静态内部类的对象里只有外部类的引用,而没有外部类对象的引用。如果允许访问会出现错误引用。如果允许访问会出现错误问题既然内部类是外部类的成员,是否可以为外部类定义子类,在子类中既然内部类是外部类的成员,是否可以为外部类定义子类,在子类中再定义一个内部类来重写其父类中的内部类?再定义一个内部类来重写其父类中的内部类?答:不可以!因为内部类的类名不再是简单地由内部类的类名组成,答:不可以!因为内部类的类名不再是简单地由内部
28、类的类名组成,它实际上还把外部类名作为一个命名空间,作为内部类类名的限制。它实际上还把外部类名作为一个命名空间,作为内部类类名的限制。因此子类中内部类和父类中的内部类不可能完全同名,即使二者所包因此子类中内部类和父类中的内部类不可能完全同名,即使二者所包含的内部类的类名相同,但因为它们所处的外部类空间不同,所以它含的内部类的类名相同,但因为它们所处的外部类空间不同,所以它们不可能是同一个类,也就不可能重写。们不可能是同一个类,也就不可能重写。内部类局部内部类:局部内部类:在一个方法中声明的类。在一个方法中声明的类。局部内部类只在定义它的代码段中可见,不能在它所属代码段之外的局部内部类只在定义它
29、的代码段中可见,不能在它所属代码段之外的代码中使用;因此也就没有代码中使用;因此也就没有public/private/default权限修饰符(无意权限修饰符(无意义)义)局部内部类可以访问外部类的实例变量,只能访问其所属代码段中局部内部类可以访问外部类的实例变量,只能访问其所属代码段中(方方法中法中)的的final局部变量局部变量(?),但不能访问方法中的局部变量。,但不能访问方法中的局部变量。在类外不可直接生成局部内部类(保证局部内部类对外是不可见的)。在类外不可直接生成局部内部类(保证局部内部类对外是不可见的)。要想使用局部内部类时需要生成对象,对象调用方法,在方法中才能要想使用局部内部
30、类时需要生成对象,对象调用方法,在方法中才能调用其局部内部类。调用其局部内部类。问题为什么只能访问声明为为什么只能访问声明为final的局部变量呢?的局部变量呢?我们知道,局部变量在其所属的代码段(譬如某个方法)执行完毕后我们知道,局部变量在其所属的代码段(譬如某个方法)执行完毕后就会被回收,而一个局部类的实例却可以在其类定义所属代码段执行就会被回收,而一个局部类的实例却可以在其类定义所属代码段执行完毕后依然存在(垃圾回收机制不确定时机回收),如果它可操控非完毕后依然存在(垃圾回收机制不确定时机回收),如果它可操控非final的局部变量,用户就可以通过该实例修改已不存在的局部变量,的局部变量,
31、用户就可以通过该实例修改已不存在的局部变量,这样就出错了。这样就出错了。不是final的局部变量,你的方法结束了就没了。但是你的内部类却不是和你的方法同时执行的,比如实现ActionListener,当你事件发生的时候才会执行,这时你的方法已经结束了,ActionListener到哪里去找这个局部变量呢?内部类匿名内部类(必须掌握):匿名内部类(必须掌握):匿名内部类是一种特殊的局部内部类,它是通过匿名类实现接口。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类,没有类名,根据多态,我们使用其父类名,结果产生的对象我们可以看成一个实现了这个接口或者继承父类的对象。因其为局部
32、内部类,那么局部内部类的所有限制都对其生效。匿名内部类是唯一一种无构造方法类。如果一个对象编译时的类型是接口,那么其运行的类型为实现这个接口的类。因匿名内部类无构造方法,所以其使用范围非常的有限。匿名内部类的使用:代码更加简洁,紧凑,但带来的是易读性下降。一般用在GUI编程中 实现事件处理.小结定义继承(inheritance)、多态(polymorphism)、重载(overloading)、覆盖(overriding)使用访问修饰符protected和“包友好”(package-friendly)修饰符描述构建器和方法的重载描述完整的对象构建和初始化的过程在Java程序中,能识别:被重载的方法和构建器使用this调用被重载的构建器被覆盖的方法调用父类的方法父类的构建器调用父类的构建器区分=和equals()封装类的构造及初始化