第一节 继承
第二节 内部类
先来看一段简单的代码:
从代码中就可以看出,内部类的好处。
内部类:将一个类定义在另一个类之中。
一、访问规则(即使用内部类的好处):
1、内部类方法可以访问该类所在的类中作用域的成员,包括私有成员变量。
2、内部类可以对同一个包中的其他类隐藏起来,从而不被访问
3、使用匿名内部类是比较便捷简单的,这种情况较多的用于AWT设计中。
注:为何内部类可直接访问外部类:
由于成员可被对象访问,内部类中持有了一个外部类的引用,,因此就可以直接用:外部类名.this.成员
二、访问格式:
1当内部类定义在外部类的成员位置上,而且非私有,可在外部其他类中直接建立内部类对象
格式:外部类名.内部类名 变量名 = 外部类对象.内部类对象
2、当内部类在成员变量的位置上,可被成员修饰符修饰
·private:将内部类在外部类中进行封装
·static:内部类具备了static的特性,当内部类被static修饰(下面说到的静态内部类),只可访问外部类中的static的成员,访问则受限。
注:(Outer为外部类名,Inner为内部类名,function为非静态成员)
在其他类中,如何访问静态内部类中非静态成员:new Outer.Inner.function();(建立对象访问)
在其他类中,如何访问静态内部类中的静态成员:Outer.Inner.function();(可直接访问)
注意:
1、当内部类中定义了静态成员,该内部类必须为静态的
2、当外部类中静态方法访问内部类时,内部类必须为静态的
3、内部类一般定义为private的,而很少定义为public的。
三、内部类定义原则:------->多在程序设计中使用
1、当描述事物时,事物的内部还有事物,则该事物使用内部类来描述,因为内部事物要使用外部事物内容
举例来说:楼房内部还有家庭住户,家庭住户中还有房间,这就可以用内部类描述。(总不能访问一个住户,就建立一个楼房对象吧,那就可真是有钱人的风范了。)
2、何时定义内部类:
当一个类需要直接访问另一个类中的成员时,则当这个类放入另一个类中,并将内部类封装。
3、内部类生成文件:
我们在编译一个源文件是,如果代码中有内部类,你会发现,生成的class文件中含有例如这样的文件:A$C.class。这是为什么呢?因为内部类是一种编译现象,与虚拟机无关。编译器将会把内部类翻译成用$(美元符号)分隔外部类名和内部类名的常规类文件,而虚拟机对此却一无所知。
四、局部内部类(也称局部类)
局部内部类:当内部类只在外部类中的某个方法中,创建了这个类型的对象时,且仅使用了一次,那么可在这个方法中定义局部类。
注:
1、局部内部类不可用public或者private访问修饰符声明,它的作用域被限定在了声明这个局部类的代码块中
2、局部类的优势:
a.对外界完全隐藏,即使此方法所在的类也不可访问,也就是说,除此方法外,无任何方法知道它的存在。
b.可访问包含他们的外部类,因还持有外部类的引用;还可访问局部变量,但是局部变量必须被声明为final。
需要注意:局部内部类不可被成员修饰符修饰,如static
五、匿名内部类:
1、匿名内部类:就是内部类的一种简写格式。
当只创建该类的一个对象,可不用再为其命名。所以称之为匿名内部类。代码示例:
内部类必须继承一个类或实现接口。
但是有一种很特殊,可以不直接继承一个父类,仍可定义一个匿名内部类。因为任何类都是Object的子类
3、格式:
new 父类或接口(参数){定义子类的内容};
4、要点说明:
A.其实匿名内部类就是一个匿名子类对象,可以理解为带有内容的对象。
B.匿名内部类中的方法最好少于3个,方法少,比较方便简单,匿名内部类一定要简化,否则就违背了初衷。
六、静态内部类
1、概述:
上面提到当内部类在成员变量的位置上,可被成员修饰符static修饰,这就是静态内部类
2、使用前提:
某些情况下,会把内部类作为一个隐藏的类,不需要使用内部类引用外部类的对象。因此,可以将外部类声明为static,就可以消除产生的引用。在内部类不需要访问外部类对象的时候,应该使用静态内部类。
匿名内部类的应用:
第三节 多态
多态:可理解为事物存在的多种体现形态。又称为动态绑定,是java的核心机制之一。
理解:多态是在运行期间,判断引用实际类型,根据实际类型调用相应的方法。
比如说人又男女之分,动物有猫、狗等之分
一、多态的体现形式:
1、父类的引用指向了自己子类的对象。
2、父类的引用可接收子类的对象。
比如说Person p = new Student();中p指向了Student中的一个对象。如图:
二、多态的前提:
1、必须是类与类之间的关系,如继承和实现关系
2、要存在覆盖的操作,父类中必须由方法被子类覆盖,即重写
3、有父类引用指向子类对象
三、多态的利弊:
1、好处:大大提高了程序的扩展性
2、弊端:虽然提高扩展性,但是只能使用父类的引用访问父类中的成员,不可预先使用子类。这是由于,子类在父类之后加载,此时还没有子类被加载。
在下面的代码中,Animal a = new Cat();是一种“类型提升,向上转型”的过程。如果要实现Cat中的其他Animal没有的功能,那么就需要强制将父类的引用转换成子类类型,然后再调用子类的方法:
注意:
1、一定不能将父类的对象转换成子类类型。
2、可转换的:父类引用指向自己子类的对象时,该引用可被提升,也可被强制转化。
3、多态自始至终均为子类对象在做变化
四、多态的特点:
1、在多态中成员函数的特点:
·编译时期:参阅引用型变量所属的类中,是否有调用的方法,如果有,则编译通过,若没有,则编译失败。如上面的代码中,引用型变量a是父类Animal的类型,其中有eat 的方法,所以没问题,但是如果调用a.catchM()就会编译失败。
·运行时期:参与对象所属的类中,是否有调用的方法。如引用型变量c是所属于Cat类型的,可以调用c.catchM()
总结:成员函数在多态调用时,编译看左边,运行看右边。子类中局部有变量就访问局部的,没有就访问成员的变量,成员中没有的就在父类中找;如果父类中没有,编译失败。
2、在多态中成员变量(和静态成员)的特点:
·无论编译和运行,都参考左边的,即引用型变量所属的类型。也就是说父类中有自己的变量,则先找父类自己的成员。
·非静态有重写的特点,静态一般不被重写。
原因:因为当调用静态方法时,只要建立子类对象,父类与子类中的静态方法都会随之加载入内存,是不需要调用就可直接用类名.方法名的,而不需要对象。只要引用还存在,就看引用变量的类型。
只要这些猫狗都继承动物就可以了!!
五、多态的应用
1、定义好工具类,即将共同行为封装在一个类中。
2、对类型进行抽取,---->多态的产生。
3、操作同一个大类型,对其中的小类型均可操作
第五节 抽象类
一、抽象类含义的概括:
当多个类出现相同功能时,但功能主体不同,这样可以向上抽取,抽取时只抽取功能定义,而不抽取功能主体。也就是说,我们在从下往上看继承这个体系结构时,位于上层的类要比下层更具有通用性,也就是说更加抽象,即最上层的祖先(即超类)最具通用性。这时只讲上层的类作为遗传(或者说派生)下层类的基本的类,而不考虑特定的实例对象。
二、抽象类的特点:
1、抽象方法一定在抽象类中,就是说,一个类中含有抽象方法,这个类也必须是抽象的。
2、抽象方法和抽象类必须被abstract修饰,这是作为抽象(类或方法)的一个标志。
3、抽象类不可用new创建对象,因为调用抽象方法没有意义(抽象方法为类中的成员)。
4、抽象类中的方法要被使用,必须由子类复写所有的抽象方法后,建立子类对象调用,也就是说,如果子类中只覆盖了部分抽象方法,那么这个子类仍为抽象的,是个抽象类。
总结来说,抽象类,是提供功能的,具体实现形式还是需要由子类来实现的,这就强迫了子类复写抽象类中的抽象方法。需要注意的是,抽象类中是可以有非抽象方法(子类可不必对其复写)的。
在此,我个人补充一点关于抽象类可以创建数组的东西。
因为数组也是一种特殊的对象,但是像下面这样就可以用new。代码如下:
三、抽象类与一般类无多大区别:
1、描述事物还依然照常描述,只是抽象类中出现了一些看不懂的东西,即功能定义,这些不确定的部分也为事物的功能,需要明确出来,但无法定义主体。通过抽象方法来表示。
2、抽象类比一般类多了抽象函数,类中可以定义抽象方法,但是不必创建主体内容。
3、抽象类不可以实例化,因为抽象方法没意义,无法创建对象
4、特殊之处:抽象类中可以不定义抽象方
第六节 接口
接口:是一种实现关系
一、接口:
接口可理解为一种特殊的抽象类(但不是),当抽象类中的方法全为抽象的(即不包含任何非抽象方法),可通过接口表示。---- class用来定义类;而interface定义接口
二、定义接口的格式特点:
接口:interface 实现:implements
1、接口中常见定义:常量、抽象方法
2、接口中成员的固定修饰符:
常量:public static final
方法:public abstract
注意:
A、接口中的成员全为public,当然那些修饰符是可以省略的,因为接口会自动设为相应的权限,但是还是最好加上。
B、当接口中的常量赋值后,不可再进行第二次赋值操作。
C、接口不可创建对象,因为其中全为抽象方法,需要被子类实现后,对接口中抽象方法全覆盖后,子类才可以实现实例化。
三、接口可被类多实现,即将java中的多继承改良成多实现。
1、多继承不可以:
是因为父类中的方法有方法体,若多个父类存在相同方法(而方法体不同),子类如果多继承这些父类的话,那么在运行子类的时候,并不能判断出要运行这些父类中的哪个方法,因此程序会出现异常。所以多继承不可以。
2、多实现可以:
是因为接口中的方法是抽象的,并无方法体,无论这些接口中存在多少个同名的方法,由于无方法体,子类只需要覆盖一次即可,这个方法的具体实现只是通过子类这一个方法实现的。
3、接口之间是可以多继承的:
因为接口中存在的是抽象的方法,接口与接口之间无论是否存在同名函数,这些都是需要子类覆盖的,这样就不会出现无法判断覆盖哪一个的问题了。
四、接口的特点:
1、接口是对外暴露的规则
2、接口可以用来多实现
3、接口是程序的扩展功能
4、接口与接口之间可有继承关系
5、接口降低了耦合性
6、类与接口之间是实现关系,且类可以继承一个类的同时实现多个接口
接口关系:like-a; 类关系:has-a
需要注意的是:两个或多个接口中不可有不同返回类型的同名抽象函数。
第七节 抽象类和接口的异同
一、概述:
1、抽象类(abstract class):------->一般仅用于被子类继承。
当多个类出现相同功能时,但功能主体不同,这样可以向上抽取,抽取时只抽取功能定义,而不抽取功能主体。也就是说,我们在从下往上看继承这个体系结构时,位于上层的类要比下层更具有通用性,也就是说更加抽象,即最上层的祖先(即超类)最具通用性。这时只讲上层的类作为遗传(或者说派生)下层类的基本的类,而不考虑特定的实例对象。
2、接口(interface):------->用来建立类与类之间关联的标准
接口可理解为一种特殊的抽象类(但不是),当抽象类中的方法全为抽象的
(即不包含任何非抽象方法),可通过接口表示。
二)联系:
1.其实接口是抽象类的延伸,可以将它看做是纯粹的抽象类,就是说接口比抽象类还抽象。
2、抽象类和接口都必须被一个类(子类)复写里面的全部抽象方法。
3、接口和抽象类都不可创建对象,因为其中含有抽象方法,需要被子类实现后,
对接口中抽象方法全覆盖后,子类才可以实现实例化。
补充:
Java接口和Java抽象类有太多相似的地方,又有太多特别的地方,究竟在什么地方,才是它们的最佳位置呢?把它们比较一下,你就可以发现了。
1、Java接口和Java抽象类最大的一个区别,就在于Java抽象类可以提供某些方法的部分实现,而Java接口不可以,这大概就是Java抽象类唯一的优点吧,但这个优点非常有用。
如果向一个抽象类里加入一个新的具体方法时,那么它所有的子类都一下子都得到了这个新方法,而Java接口做不到这一点,如果向一个Java接口里加入一个新方法,所有实现这个接口的类就无法成功通过编译了,因为你必须让每一个类都再实现这个方法才行,这显然是Java接口的缺点。
2、一个抽象类的实现只能由这个抽象类的子类给出,也就是说,这个实现处在抽象类所定义出的继承的等级结构中,而由于Java语言的单继承性,所以抽象类作为类型定义工具的效能大打折扣。
在这一点上,Java接口的优势就出来了,任何一个实现了一个Java接口所规定的方法的类都可以具有这个接口的类型,而一个类可以实现任意多个Java接口,从而这个类就有了多种类型。
3、从第2点不难看出,Java接口是定义混合类型的理想工具,混合类表明一个类不仅仅具有某个主类型的行为,而且具有其他的次要行为。
4、结合1、2点中抽象类和Java接口的各自优势,具精典的设计模式就出来了:声明类型的工作仍然由Java接口承担,但是同时给出一个Java抽象类,且实现了这个接口,而其他同属于这个抽象类型的具体类可以选择实现这个Java接口,也可以选择继承这个抽象类,也就是说在层次结构中,Java接口在最上面,然后紧跟着抽象类,哈,这下两个的最大优点都能发挥到极至了。这个模式就是“缺省适配模式”。
在Java语言API中用了这种模式,而且全都遵循一定的命名规范:Abstract +接口名。
Java接口和Java抽象类的存在就是为了用于具体类的实现和继承的,如果你准备写一个具体类去继承另一个具体类的话,那你的设计就有很大问题了。Java抽象类就是为了继承而存在的,它的抽象方法就是为了强制子类必须去实现的。
使用Java接口和抽象Java类进行变量的类型声明、参数是类型声明、方法的返还类型说明,以及数据类型的转换等。而不要用具体Java类进行变量的类型声明、参数是类型声明、方法的返还类型说明,以及数据类型的转换等。
我想,如果你编的代码里面连一个接口和抽象类都没有的话,也许我可以说你根本没有用到任何设计模式,任何一个设计模式都是和抽象分不开的,而抽象与Java接口和抽象Java类又是分不开的。
理解抽象,理解Java接口和抽象Java类,我想就应该是真正开始用面向对象的思想去分析问题,解决问题了吧。