学校门户网站建设研究综述,优化人员是什么意思,手机网站制作 费怎么做分录,jn建站系统官网面向对象编程有三大特性#xff1a;封装、继承、多态。封装隐藏了类的内部实现机制#xff0c;可以在不影响使用的情况下改变类的内部结构#xff0c;同时也保护了数据。对外界而已它的内部细节是隐藏的#xff0c;暴露给外界的只是它的访问方法。继承是为了重用父类代码。…面向对象编程有三大特性封装、继承、多态。封装隐藏了类的内部实现机制可以在不影响使用的情况下改变类的内部结构同时也保护了数据。对外界而已它的内部细节是隐藏的暴露给外界的只是它的访问方法。继承是为了重用父类代码。两个类若存在IS-A的关系就可以使用继承。同时继承也为实现多态做了铺垫。那么什么是多态呢多态的实现机制又是什么请看我一一为你揭开所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定而是在程序运行期间才确定即一个引用变量倒底会指向哪个类的实例对象该引用变量发出的方法调用到底是哪个类中实现的方法必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类这样不用修改源程序代码就可以让引用变量绑定到各种不同的类实现上从而导致该引用调用的具体方法随之改变即不修改程序代码就可以改变程序运行时所绑定的具体代码让程序可以选择多个运行状态这就是多态性。比如你是一个酒神对酒情有独钟。某日回家发现桌上有几个杯子里面都装了白酒从外面看我们是不可能知道这是些什么酒只有喝了之后才能够猜出来是何种酒。你一喝这是剑南春、再喝这是五粮液、再喝这是酒鬼酒….在这里我们可以描述成如下酒 a 剑南春酒 b 五粮液酒 c 酒鬼酒…这里所表现的的就是多态。剑南春、五粮液、酒鬼酒都是酒的子类我们只是通过酒这一个父类就能够引用不同的子类这就是多态——我们只有在运行的时候才会知道引用变量所指向的具体实例对象。诚然要理解多态我们就必须要明白什么是“向上转型”。在继承中我们简单介绍了向上转型这里就在啰嗦下在上面的喝酒例子中酒(Win)是父类剑南春(JNC)、五粮液(WLY)、酒鬼酒(JGJ)是子类。我们定义如下代码JNC a new JNC();对于这个代码我们非常容易理解无非就是实例化了一个剑南春的对象嘛但是这样呢Wine a new JNC();在这里我们这样理解这里定义了一个Wine 类型的a它指向JNC对象实例。由于JNC是继承与Wine所以JNC可以自动向上转型为Wine所以a是可以指向JNC实例对象的。这样做存在一个非常大的好处在继承中我们知道子类是父类的扩展它可以提供比父类更加强大的功能如果我们定义了一个指向子类的父类引用类型那么它除了能够引用父类的共性外还可以使用子类强大的功能。但是向上转型存在一些缺憾那就是它必定会导致一些方法和属性的丢失而导致我们不能够获取它们。所以父类类型的引用可以调用父类中定义的所有属性和方法对于只存在与子类中的方法和属性它就望尘莫及了---1。public classWine {public voidfun1(){System.out.println(Wine 的Fun.....);fun2();}public voidfun2(){System.out.println(Wine 的Fun2...);}}public class JNC extendsWine{/*** desc 子类重载父类方法* 父类中不存在该方法向上转型后父类是不能引用该方法的*parama*returnvoid*/public voidfun1(String a){System.out.println(JNC 的 Fun1...);fun2();}/*** 子类重写父类方法* 指向子类的父类引用调用fun2时必定是调用该方法*/public voidfun2(){System.out.println(JNC 的Fun2...);}}public classTest {public static voidmain(String[] args) {Wine a newJNC();a.fun1();}}-------------------------------------------------Output:Wine 的Fun.....JNC 的Fun2...从程序的运行结果中我们发现a.fun1()首先是运行父类Wine中的fun1().然后再运行子类JNC中的fun2()。分析在这个程序中子类JNC重载了父类Wine的方法fun1()重写fun2()而且重载后的fun1(String a)与 fun1()不是同一个方法由于父类中没有该方法向上转型后会丢失该方法所以执行JNC的Wine类型引用是不能引用fun1(String a)方法。而子类JNC重写了fun2() 那么指向JNC的Wine引用会调用JNC中fun2()方法。所以对于多态我们可以总结如下指向子类的父类引用由于向上转型了它只能访问父类中拥有的方法和属性而对于子类中存在而父类中不存在的方法该引用是不能使用的尽管是重载该方法。若子类重写了父类中的某些方法在调用该些方法的时候必定是使用子类中定义的这些方法(动态连接、动态调用)。对于面向对象而已多态分为编译时多态和运行时多态。其中编译时多态是静态的主要是指方法的重载它是根据参数列表的不同来区分不同的函数通过编辑之后会变成两个不同的函数在运行时谈不上多态。而运行时多态是动态的它是通过动态绑定来实现的也就是我们所说的多态性。多态的实现2.1实现条件在刚刚开始就提到了继承在为多态的实现做了准备。子类Child继承父类Father我们可以编写一个指向子类的父类类型引用该引用既可以处理父类Father对象也可以处理子类Child对象当相同的消息发送给子类或者父类对象时该对象就会根据自己所属的引用而执行不同的行为这就是多态。即多态性就是相同的消息使得不同的类做出不同的响应。Java实现多态有三个必要条件继承、重写、向上转型。继承在多态中必须存在有继承关系的子类和父类。重写子类对父类中某些方法进行重新定义在调用这些方法时就会调用子类的方法。向上转型在多态中需要将子类的引用赋给父类对象只有这样该引用才能够具备技能调用父类的方法和子类的方法。只有满足了上述三个条件我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象从而达到执行不同的行为。对于Java而言多态的实现机制遵循一个原则当超类对象引用变量引用子类对象时被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法但是这个被调用的方法必须是在超类中定义过的也就是说被子类覆盖的方法。2.2实现形式在Java中有两种形式可以实现多态。继承和接口。2.2.1、基于继承实现的多态基于继承的实现机制主要表现在父类和继承该父类的一个或多个子类对某些方法的重写多个子类对同一方法的重写可以表现出不同的行为。public classWine {privateString name;publicString getName() {returnname;}public voidsetName(String name) {this.name name;}publicWine(){}publicString drink(){return 喝的是 getName();}/*** 重写toString()*/publicString toString(){return null;}}public class JNC extendsWine{publicJNC(){setName(JNC);}/*** 重写父类方法实现多态*/publicString drink(){return 喝的是 getName();}/*** 重写toString()*/publicString toString(){return Wine : getName();}}public class JGJ extendsWine{publicJGJ(){setName(JGJ);}/*** 重写父类方法实现多态*/publicString drink(){return 喝的是 getName();}/*** 重写toString()*/publicString toString(){return Wine : getName();}}public classTest {public static voidmain(String[] args) {//定义父类数组Wine[] wines new Wine[2];//定义两个子类JNC jnc newJNC();JGJ jgj newJGJ();//父类引用子类对象wines[0] jnc;wines[1] jgj;for(int i 0 ; i 2 ; i){System.out.println(wines[i].toString() -- wines[i].drink());}System.out.println(-------------------------------);}}OUTPUT:Wine : JNC--喝的是 JNCWine : JGJ--喝的是 JGJ-------------------------------在上面的代码中JNC、JGJ继承Wine并且重写了drink()、toString()方法程序运行结果是调用子类中方法输出JNC、JGJ的名称这就是多态的表现。不同的对象可以执行相同的行为但是他们都需要通过自己的实现方式来执行这就要得益于向上转型了。我们都知道所有的类都继承自超类ObjecttoString()方法也是Object中方法当我们这样写时Object o newJGJ();System.out.println(o.toString());输出的结果是Wine : JGJ。Object、Wine、JGJ三者继承链关系是JGJ—Wine—Object。所以我们可以这样说当子类重写父类的方法被调用时只有对象继承链中的最末端的方法才会被调用。但是注意如果这样写Object o newWine();System.out.println(o.toString());输出的结果应该是Null因为JGJ并不存在于该对象继承链中。所以基于继承实现的多态可以总结如下对于引用子类的父类类型在处理该引用时它适用于继承该父类的所有子类子类对象的不同对方法的实现也就不同执行相同动作产生的行为也就不同。如果父类是抽象类那么子类必须要实现父类中所有的抽象方法这样该父类所有的子类一定存在统一的对外接口但其内部的具体实现可以各异。这样我们就可以使用顶层类提供的统一接口来处理该层次的方法。2.2.2、基于接口实现的多态继承是通过重写父类的同一方法的几个不同子类来体现的那么就可就是通过实现接口并覆盖接口中同一方法的几不同的类体现的。在接口的多态中指向接口的引用必须是指定这实现了该接口的一个类的实例程序在运行时根据对象引用的实际类型来执行对应的方法。继承都是单继承只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现它能够利用一组相关或者不相关的接口进行组合与扩充能够对外提供一致的服务接口。所以它相对于继承来说有更好的灵活性。经典实例public classA {publicString show(D obj) {return (A and D);}publicString show(A obj) {return (A and A);}}public class B extendsA{publicString show(B obj){return (B and B);}publicString show(A obj){return (B and A);}}public class C extendsB{}public class D extendsB{}public classTest {public static voidmain(String[] args) {A a1 newA();A a2 newB();B b newB();C c newC();D d newD();System.out.println(1-- a1.show(b));System.out.println(2-- a1.show(c));System.out.println(3-- a1.show(d));System.out.println(4-- a2.show(b));System.out.println(5-- a2.show(c));System.out.println(6-- a2.show(d));System.out.println(7-- b.show(b));System.out.println(8-- b.show(c));System.out.println(9-- b.show(d));}}运行结果1--A and A2--A and A3--A and D4--B and A5--B and A6--A and D7--B and B8--B and B9--A and D在这里看结果1、2、3还好理解从4开始就开始糊涂了对于4来说为什么输出不是“B and B”呢首先我们先看一句话当超类对象引用变量引用子类对象时被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法但是这个被调用的方法必须是在超类中定义过的也就是说被子类覆盖的方法。这句话对多态进行了一个概括。其实在继承链中对象方法的调用存在一个优先级this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。分析从上面的程序中我们可以看出A、B、C、D存在如下关系。首先我们分析5a2.show(c)a2是A类型的引用变量所以this就代表了Aa2.show(c),它在A类中找发现没有找到于是到A的超类中找(super)由于A没有超类(Object除外)所以跳到第三级也就是this.show((super)O)C的超类有B、A所以(super)O为B、Athis同样是A这里在A中找到了show(A obj)同时由于a2是B类的一个引用且B类重写了show(A obj)因此最终会调用子类B类的show(A obj)方法结果也就是B and A。按照同样的方法我也可以确认其他的答案。方法已经找到了但是我们这里还是存在一点疑问我们还是来看这句话当超类对象引用变量引用子类对象时被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法但是这个被调用的方法必须是在超类中定义过的也就是说被子类覆盖的方法。这我们用一个例子来说明这句话所代表的含义a2.show(b)这里a2是引用变量为A类型它引用的是B对象因此按照上面那句话的意思是说有B来决定调用谁的方法,所以a2.show(b)应该要调用B中的show(B obj)产生的结果应该是“B and B”但是为什么会与前面的运行结果产生差异呢这里我们忽略了后面那句话“但是这儿被调用的方法必须是在超类中定义过的”那么show(B obj)在A类中存在吗根本就不存在所以这句话在这里不适用那么难道是这句话错误了非也其实这句话还隐含这这句话它仍然要按照继承链中调用方法的优先级来确认。所以它才会在A类中找到show(A obj)同时由于B重写了该方法所以才会调用B类中的方法否则就会调用A类中的方法。所以多态机制遵循的原则概括为当超类对象引用变量引用子类对象时被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法但是这个被调用的方法必须是在超类中定义过的也就是说被子类覆盖的方法但是它仍然要根据继承链中方法调用的优先级来确认方法该优先级为this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。对最后的一个例子补充。深入理解多态的性质(上下例子其实一样上面的蓝色部分是总结)深入理解java多态性昨天看到一个关于多态性的帖子参考了回帖者的理解加入了一些自己的看法整理出来供大家参考不一定完全正确欢迎大家批评指正。(一)相关类classA...{publicString show(D obj)...{return(A and D); }publicString show(A obj)...{return(A and A); }}classBextendsA...{publicString show(B obj)...{return(B and B); }publicString show(A obj)...{return(B and A); }}classCextendsB...{}classDextendsB...{}(二)问题以下输出结果是什么 A a1newA(); A a2newB(); B b newB(); C cnewC(); D dnewD(); System.out.println(a1.show(b)); ① System.out.println(a1.show(c)); ② System.out.println(a1.show(d)); ③ System.out.println(a2.show(b)); ④ System.out.println(a2.show(c)); ⑤ System.out.println(a2.show(d)); ⑥ System.out.println(b.show(b)); ⑦ System.out.println(b.show(c)); ⑧ System.out.println(b.show(d)); ⑨(三)答案① A and A② A and A③ A and D④ B and A⑤ B and A⑥ A and D⑦ B and B⑧ B and B⑨ A and D(四)分析①②③比较好理解一般不会出错。④⑤就有点糊涂了为什么输出的不是B and B”呢先来回顾一下多态性。运行时多态性是面向对象程序设计代码重用的一个最强大机制动态性的概念也可以被说成“一个接口多个方法”。Java实现运行时多态性的基础是动态方法调度它是一种在运行时而不是在编译期调用重载方法的机制。方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数我们说该方法被重写(Overriding)。子类的对象使用这个方法时将调用子类中的定义对它而言父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法它们或有不同的参数个数或有不同的参数类型则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。当超类对象引用变量引用子类对象时被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法但是这个被调用的方法必须是在超类中定义过的也就是说被子类覆盖的方法。 (但是如果强制把超类转换成子类的话就可以调用子类中新添加而超类没有的方法了。)好了先温习到这里言归正传实际上这里涉及方法调用的优先问题 优先级由高到低依次为this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。这里的this指引用变量所在的类。让我们来看看它是怎么工作的。注意点如果this指向的是基类的引用那么对于this.show(O)、this.show((super)O)如果在this所在的类中找到对应的方法时候还要继续判断子类中是否重写该方法(子类.show(O)、子类.show((super)O))如果实现重写覆盖那么最终的执行就锁定在子类的方法中否则就执行基类中的相关方法(基类.show(O)、基类.show((super)O))比如④a2.show(b)a2是一个引用变量类型为A则this为a2b是B的一个实例于是它到类A里面找show(B obj)方法没有找到于是到A的super(超类)找而A没有超类因此转到第三优先级this.show((super)O)this仍然是a2这里O为B(super)O即(super)B即A因此它到类A里面找show(A obj)的方法类A有这个方法但是由于a2引用的是类B的一个对象B覆盖了A的show(Aobj)方法因此最终锁定到类B的show(A obj)输出为B and A”。再比如⑧b.show(c)b是一个引用变量类型为B则this为bc是C的一个实例于是它到类B找show(C obj)方法没有找到转而到B的超类A里面找A里面也没有因此也转到第三优先级this.show((super)O)this为bO为C(super)O即(super)C即B因此它到B里面找show(B obj)方法找到了由于b引用的是类B的一个对象因此直接锁定到类B的show(B obj)输出为Band B”。按照上面的方法可以正确得到其他的结果。问题还要继续现在我们再来看上面的分析过程是怎么体现出蓝色字体那句话的内涵的。它说当超类对象引用变量引用子类对象时被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法但是这个被调用的方法必须是在超类中定义过的也就是说被子类覆盖的方法。还是拿a2.show(b)来说吧。a2是一个引用变量类型为A它引用的是B的一个对象因此这句话的意思是由B来决定调用的是哪个方法。因此应该调用B的show(B obj)从而输出B and B”才对。但是为什么跟前面的分析得到的结果不相符呢问题在于我们不要忽略了蓝色字体的后半部分那里特别指明这个被调用的方法必须是在超类中定义过的也就是被子类覆盖的方法。B里面的show(B obj)在超类A中有定义吗没有那就更谈不上被覆盖了。实际上这句话隐藏了一条信息它仍然是按照方法调用的优先级来确定的。它在类A中找到了show(Aobj)如果子类B没有覆盖show(A obj)方法那么它就调用A的show(A obj)(由于B继承A虽然没有覆盖这个方法但从超类A那里继承了这个方法从某种意义上说还是由B确定调用的方法只是方法是在A中实现而已)现在子类B覆盖了show(A obj)因此它最终锁定到B的show(A obj)。这就是那句话的意义所在。在这里面向对象的三大特性已经介绍完成下一步继续是java基础部分—巩固基础提高技术不惧困难攀登高峰