面向对象的三大特征是:封装,继承,多态。也有四大特征的说法:多了一个抽象。抽象我会穿插在其他的3大特征中进行解读。 所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。这里的可信与不可信通过四大修饰符(public private 默认 protected)来划分界限的。好处就是,对象对内部数据通过四大修饰符提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。另外,封装技术可创建出新的数据类型(在另一个类中当作变量类型)。通过对具体实施的细节的隐藏,可将接口与实施细节分离,使所有细节成为private。然而,多态涉及对“类型”的分解。目前最常见的封装就是JavaBean,可能对这个专业术语陌生或者一时对不上号,其实就是我们平时私有化成员变量,public方法,生成setter\getter\toString\有参构造、无参构造那个就是JavaBean。提到构造函数,构造函数就是:函数名和类型与本类完全相同,包括大小写一致。之前学过BeanUtils工具类是对JavaBean操作的。 扩展: 刚才提到了四大修饰符,有个小原则,一般我们在没有定义某个方法时,但是在一个地方需要调用到这个方法,我们会先写这个方法的名字和括号,也就是调用操作,然后用快捷键快速生成该方法,你会发现生成的方法默认修饰符是private或者protected,这是因为编程软件认为该方法不需要用范围更大的修饰符,这也是间接的考虑到程序的安全性问题。一般成员变量或方法,尽量用private修饰,权限不够的话,再逐渐提升。 所谓继承是指可以让某个类型的对象获得另一个类型的对象的属性的方法。也就是子父类之间、接口之间的关系。 子父类之间的继承的特点就是,子类可以使用父级类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。继承的类称为“子类”,也可以叫作“派生类”,被继承的类称为“基类”、“父类”或“超类”。 子类初始化前,要先初始化父类,防止,子类有调用父类的引用。 super和this关键字: super是子类指向父类的引用。 this指的是当前对象。(谁调用我,我就指的谁) 在构造函数中,调用父类变量或方法,用super,必须在函数体的第一行, 一般默认都有一个super(),调用的是父类的无参构造。调用父类的有参构造一般用的是super(参数),调用的就是父类的有参构造函数。 一般不定义构造函数,类中有默认一个无参构造函数,若是定义了有参构造函数,而不定义无参构造,此类中是不会有无参构造函数的。 一个类中,同时定义了有参和无参构造函数,可以用this()和this(有参)互相调用,一般不能同时互相调用,不能形成死循环,要有出口。 this和super关键字都是比较霸道的,都是定义在第一行,也就说,一个方法中不能同时调用this和super的。 *注意:super引用没有单独使用的语法 关于继承,通过继承可将一个对象当作它自己的类型或者它自己的基础类型对待。这种能力是十分重要的,因为多个类型(从相同的基础类型中衍生出来)可被当作同一种类型对待。这里涉及的是多态,稍后再做详细分析。 我分了3种情况: 第一种是,普通类之间的继承,子类可以使用父类的所有非私有变量或者方法。子类同时也可以有自己的特有变量和方法。 第二种是,普通类继承抽象类。抽象类是用abstract修饰的类。 抽象类这里又为分2个情况: 1.有抽象方法:必须重写抽象方法 重写的概念:一般出现在子父类中,子类中的方法名和参数列表,修饰符等等与父类中的完全一样。说白了就是方法体可以不同,剩下都必须相同。 2.没抽象方法:这个跟普通类之间的继承一样的特点。 第三种是,抽象类与抽象类之间的继承,若是有抽象方法,可以不用重写,这里类似于接口与接口之间的继承。 第四种是, 接口之间的继承的特点就是,使用属性和方法的名称。刚开始学习接口的时候,可能会觉得接口有些鸡肋,纯属于多此一举。实际上,接口可以提供一种规范,让我们知道该实现什么方法。接口继承接口,里面的所有方法都不用实现,交给实现类去实现所有的方法。 继承关键字是extends, 类与类之间是单继承、多级继承 -- 类似封建帝制中的继承皇位。嘉庆皇帝继承乾隆皇帝的皇位,不能同时继承美国总统的位置一样,这是单继承,而乾隆皇帝又继承康熙皇帝的皇位这是多级继承了。接口与接口之间的继承关系是多继承多级继承,就是想怎么来就怎么来。 关于同时出现继承和实现的时候,值得注意的是,若是一个类或者接口同时继承一个类,同时实现多个接口的时候,格式规则为先继承,再实现,多个实现是implements 第一个接口 逗号第二个接口 逗号 第三个接口 。。。。也就是说,定义在一个类上的关键字implement只能出现一次。之前咱们做过这个题目的。 在接口中,所有的变量都自动具有public、static和final属性,也就是说,即使在接口中定义了其他的修饰符,也是public属性的。所以接口是对常数值进行分组的一个好工具。 再说能体现出多态的好处例子:现有Dog和Cat类,想再添加一个Lion类,假如从白板一张的开始给lion类定义,一般人都会想到的是lion的特性,反而容易忽略掉某些作为动物的共有属性。致命的是,编译器不会对此作出提示,简单来说,比如动物都有eat、run等动作,你忘了定义run,但是有一个Animal类的话,起码在动物共性上来说,不用再多加考虑。省时、省力。这样说来,这是继承和多态共同导致的好处。 扩展: 1.一个抽象类中没有抽象方法,一般我们都认为该类抽象了没啥用,但实际上,可以防止这个类被实例化。顺便补充一点:java中防止一个类被实例化,有两种方式,一种就是上述的,将类定义成抽象类(网上说在后面学习的框架spring中经常会使用到。),一种就是将类的构造方法私有化。(单例设计模式就是基于这个原理) 2.关于接口有一道面试题:接口中是否可以包含成员变量和方法实现。。 其实实际编程过程中还是有意义的,比如定义一些全局的常量来用,如果把一些不常变的东西放到文件或数据库中,使用时比较麻烦,还要做读取操作,放到接口内的常量中,就很方便了。接口中是不能有方法的实现的,必须是抽象方法。这是跟抽象类之间的区别之一。 3.使用接口还是抽象类? 若使用接口,我们可以同时获得抽象类及接口的好处(抽象类的好处,提取共性,抽象化特殊方法,使子类继承。接口的特殊好处就是多实现。),所以假如想创建的父级(这里所说的父级,指的是要被继承或者实现的父类或者接口)中,没有任何方法定义或者成员变量,那么无论如何都愿意使用接口,而不要选择抽象类,事实上,如果事先知道某个类会成为父类,那么第一个选择就是把它变成一个接口。只有在必须使用方法定义或者成员变量时,才应该考虑采用抽象类。比如动物类Animal是父类,Dog和Cat都是继承自Animal类的子类。不同的子类可以实现不同的功能的同时,还可以通过对父类修改后,能影响到所有子类。 多态:从一定角度来看,封装和继承几乎都是为多态而准备的。 指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用) 。通俗来讲,就是指只需要一段代码,即可对所有不同的类型进行同样的处理。实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。多态机制,使其具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。利用多态的方法调用,一种类型可将自己与另一种相似的类型区分开,只要他们都是同一个父类的子类。多态的作用:消除类型之间的耦合关系。 多态存在的三个必要条件:一、要有继承;二、要有重写;三、父类引用指向子类对象。 多态的好处: 1.可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。(个人理解:子类可以代替父类出现的位置,指功能方面) 2.可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。(个人理解:新创建的子类或者已经存在的子类中更改代码,不会对父类产生影响,从而实现功能的扩展) 3.接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如图8.3 所示。图中超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如Circle和Sphere为了实现多态,完善或者覆盖这两个接口方法。(个人理解:父级接口向所有子级类提供一个共同的接口,由子类完善或覆盖以及实现。) 4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。 5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。(降低耦合) Java中多态的实现方式:接口实现,继承父类进行方法重写,同一个类中进行方法重载。 1.Java中除了static和final方法外,其他所有的方法都是运行时绑定的。private方法都被隐式指定为final的,因此final的方法不会在运行时绑定。当在派生类中重写基类中static、final、或private方法时,实质上是创建了一个新的方法。 2.在派生类中,对于基类中的private方法,最好采用不同的名字。 3.包含抽象方法的类叫做抽象类。注意定义里面包含这样的意思,只要类中包含一个抽象方法,该类就是抽象类。抽象类在派生中就是作为基类的角色,为不同的子类提供通用的接口。 4.对象清理的顺序和创建的顺序相反,当然前提是自己想手动清理对象,因为大家都知道Java垃圾回收器。 5.在基类的构造方法中小心调用基类中被重写的方法,这里涉及到对象初始化顺序。 6.构造方法是被隐式声明为static方法。 7.用继承表达行为间的差异,用字段表达状态上的变化。 在JAVA中有两种多态是指:运行时多态和编译时多态。 1、类多态性表现 (1)方法重载 重载表现为同一个类中方法的多态性.一个类生命多个重载方法就是为一种功能提供多种实现.编译时,根据方法实际参数的数据类型\个数和次序,决定究竟应该执行重载方法中的哪一个. (2)子类重定义从父类继承来的成员(即方法重写) 当子类从父类继承来的成员不适合子类时,子类不能删除它们,但可以重定义它们,使父类成员适应子类的新需求.子类重定义父类成员,同名成员在父类与子类之间表现出多态性,父类对象引用父类成员,子类对象引用子类成员,不会产生冲突和混乱。 子类可重定义父类的同名成员变量,称子类隐藏父类成员变量.子类也可以重定义父类的同名成员方法,当子类方法的参数列表与父类方法参数列表完全相同时,称为子类方法覆盖(override)父类方法。覆盖父类方法时,子类方法的访问权限不能小于父类方法的权限。 由于Object类的equals()方法比较两个对象的引用是否相等而不是值是否相等,因此一个类要覆盖Object类的equals()方法,提供本类两个对象比较相等方法. 覆盖表现为父类与子类之间方法的多态性.java 寻找执行方法的原则是:从对象所属的类开始,寻找匹配的方法执行,如果当前类中没有匹配的方法,则逐层向上依次在父类或祖先类中寻找匹配方法,直到Object类. 多态性有两种: 1)编译时多态性:对于多个同名方法,如果在编译时能够确定执行同名方法中的哪一个,则称为编译时多态性. 2)运行时多态性:如果在编译时不能确定,只能在运行时才能确定执行多个同名方法中的哪一个,则称为运行时多态性. 方法覆盖表现出两种多态性,当对象获得本类实例时,为编译时多态性,否则为运行时多态性 比如动物类Animal是父类,Dog和Cat都是继承自Animal类的子类。不同的子类可以实现不同的功能的同时,还可以通过对父类修改后,能影响到所有子类。 再说能体现出多态的好处例子:现有Dog和Cat类,想再添加一个Lion类,假如从白板一张的开始给lion类定义,一般人都会想到的是lion的特性,反而容易忽略掉某些作为动物的共同属性。致命的是,编译器不会对此作出提示,简单来说,比如动物都有eat、run等动作,你忘了定义run,但是有一个Animal类的话,起码在动物共性上来说,不用再多加考虑。省时、省力。这样说来,这是继承和多态共同导致的好处。
|