转载 重新认识java(五) ---- 面向对象之多态(向上转型与向下转型)

<div id="article_content" class="article_content clearfix csdn-tracking-statistics" data-pid="blog" data-mod="popu_307" data-dsm="post">
        <div class="article-copyright">
     版权声明:本文为博主原创文章,未经博主允许不得转载。     https://blog.csdn.net/qq_31655965/article/details/54746235    </div>
                    <div class="markdown_views">
       <!-- flowchart 箭头图标 勿删 -->
       <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path></svg>
       <blockquote>
  <p>多态,大概每个人都知道。但是,又有几个人真的理解什么是多态、多态有哪些细节呢?如果你看到这篇文章的名字,脑海中对多态没有一个清晰的概念,不妨点进来看看,也许会有收获。</p>
</blockquote>

 

<h2 id="什么是多态"><a name="t0"></a><strong>什么是多态</strong></h2>

 

<h3 id="简单的理解多态"><a name="t1"></a><strong>简单的理解多态</strong></h3>

<p>多态,简而言之就是同一个行为具有多个不同表现形式或形态的能力。比如说,有一杯水,我不知道它是温的、冰的还是烫的,但是我一摸我就知道了。我摸水杯这个动作,对于不同温度的水,就会得到不同的结果。这就是多态。</p>

<p>那么,java中是怎么体现多态呢?我们来直接看代码:</p>

 

<pre class="prettyprint" name="code"><code class="language-java hljs  has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Water</span> {</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showTem</span>(){
        System.out.println(<span class="hljs-string">"我的温度是: 0度"</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IceWater</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Water</span> {</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showTem</span>(){
        System.out.println(<span class="hljs-string">"我的温度是: 0度"</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WarmWater</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Water</span> {</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showTem</span>(){
        System.out.println(<span class="hljs-string">"我的温度是: 40度"</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HotWater</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Water</span> {</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showTem</span>(){
        System.out.println(<span class="hljs-string">"我的温度是: 100度"</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestWater</span>{</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span>(String[] args) {
        Water w = <span class="hljs-keyword">new</span> WarmWater();
        w.showTem();

        w = <span class="hljs-keyword">new</span> IceWater();
        w.showTem();

        w = <span class="hljs-keyword">new</span> HotWater();
        w.showTem();

    }
}

<span class="hljs-comment">//结果:</span>
<span class="hljs-comment">//我的温度是: 40度</span>
<span class="hljs-comment">//我的温度是: 0度</span>
<span class="hljs-comment">//我的温度是: 100度</span></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li><li style="color: rgb(153, 153, 153);">6</li><li style="color: rgb(153, 153, 153);">7</li><li style="color: rgb(153, 153, 153);">8</li><li style="color: rgb(153, 153, 153);">9</li><li style="color: rgb(153, 153, 153);">10</li><li style="color: rgb(153, 153, 153);">11</li><li style="color: rgb(153, 153, 153);">12</li><li style="color: rgb(153, 153, 153);">13</li><li style="color: rgb(153, 153, 153);">14</li><li style="color: rgb(153, 153, 153);">15</li><li style="color: rgb(153, 153, 153);">16</li><li style="color: rgb(153, 153, 153);">17</li><li style="color: rgb(153, 153, 153);">18</li><li style="color: rgb(153, 153, 153);">19</li><li style="color: rgb(153, 153, 153);">20</li><li style="color: rgb(153, 153, 153);">21</li><li style="color: rgb(153, 153, 153);">22</li><li style="color: rgb(153, 153, 153);">23</li><li style="color: rgb(153, 153, 153);">24</li><li style="color: rgb(153, 153, 153);">25</li><li style="color: rgb(153, 153, 153);">26</li><li style="color: rgb(153, 153, 153);">27</li><li style="color: rgb(153, 153, 153);">28</li><li style="color: rgb(153, 153, 153);">29</li><li style="color: rgb(153, 153, 153);">30</li><li style="color: rgb(153, 153, 153);">31</li><li style="color: rgb(153, 153, 153);">32</li><li style="color: rgb(153, 153, 153);">33</li><li style="color: rgb(153, 153, 153);">34</li><li style="color: rgb(153, 153, 153);">35</li><li style="color: rgb(153, 153, 153);">36</li><li style="color: rgb(153, 153, 153);">37</li><li style="color: rgb(153, 153, 153);">38</li><li style="color: rgb(153, 153, 153);">39</li><li style="color: rgb(153, 153, 153);">40</li><li style="color: rgb(153, 153, 153);">41</li><li style="color: rgb(153, 153, 153);">42</li></ul></pre>

<p>这里的方法showTem()就相当于你去摸水杯。我们定义的water类型的引用变量w就相当于水杯,你在水杯里放了什么温度的水,那么我摸出来的感觉就是什么。就像代码中的那样,放置不同温度的水,得到的温度也就不同,但水杯是同一个。</p>

<p>想必你也看出来了,这段代码中最关键的就是这一句</p>

<pre class="prettyprint" name="code"><code class="language-java hljs  has-numbering">Water w = <span class="hljs-keyword">new</span> WarmWater();</code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li></ul></pre>

<p>看过我前几篇文章的应该知道,我说在讲多态的时候,会讲一个很重要的知识点 — 向上转型。</p>

<p>这句代码体现的就是向上转型。后面我会详细讲解这一知识点。</p>

 

<h3 id="多态的分类"><a name="t2"></a><strong>多态的分类</strong></h3>

<p>已经简单的认识了多态了,那么我们来看一下多态的分类。</p>

<p>多态一般分为两种:<strong>重写式多态和重载式多态</strong>。重写和重载这两个知识点前面的文章已经详细将结果了,这里就不多说了。</p>

<ul>
<li><p>重载式多态,也叫编译时多态。也就是说这种多态再编译时已经确定好了。重载大家都知道,方法名相同而参数列表不同的一组方法就是重载。在调用这种重载的方法时,通过传入不同的参数最后得到不同的结果。</p>

<blockquote>
  <p>但是这里是有歧义的,有的人觉得不应该把重载也算作多态。因为很多人对多态的理解是:<strong>程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,这种情况叫做多态。</strong> 这个定义中描述的就是我们的第二种多态—重写式多态。并且,重载式多态并不是面向对象编程特有的,而多态却是面向对象三大特性之一(如果我说的不对,记得告诉我。。)。</p>
 
  <p>我觉得大家也没有必要在定义上去深究这些,我的理解是:<strong>同一个行为具有多个不同表现形式或形态的能力</strong>就是多态,所以我认为重载也是一种多态,如果你不同意这种观点,我也接受。</p>
</blockquote></li>
<li><p>重写式多态,也叫运行时多态。这种多态通过动态绑定(dynamic binding)技术来实现,是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。也就是说,只有程序运行起来,你才知道调用的是哪个子类的方法。 <br>
这种多态通过函数的重写以及向上转型来实现,我们上面代码中的例子就是一个完整的重写式多态。我们接下来讲的所有多态都是重写式多态,因为它才是面向对象编程中真正的多态。</p>

<blockquote>
  <p>动态绑定技术涉及到jvm,暂时不讲(因为我也不懂,哈哈哈哈),感兴趣的可以自己去研究一下,我暂时还没有时间去研究jvm。。</p>
</blockquote></li>
</ul>

<h3 id="多态的条件"><a name="t3"></a><strong>多态的条件</strong></h3>

<blockquote>
  <p>前面说过,我们接下来说的多态,都是运行时多态。</p>
</blockquote>

<ul>
<li><strong>继承</strong>。在多态中必须存在有继承关系的子类和父类。</li>
<li><strong>重写</strong>。子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。</li>
<li><strong>向上转型</strong>。在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。</li>
</ul>

<blockquote>
  <p>继承也可以替换为实现接口。</p>
</blockquote>

<p>继承和重写之前都说过了,接下来我们来看一下转型是什么。</p>

 

<h2 id="向上转型与向下转型"><a name="t4"></a>向上转型与向下转型</h2>

 

<h3 id="向上转型"><a name="t5"></a><strong>向上转型</strong></h3>

<p>子类引用的对象转换为父类类型称为向上转型。通俗地说就是是将子类对象转为父类对象。此处父类对象可以是接口。</p>

 

<h4 id="案例驱动"><strong>案例驱动</strong></h4>

<p>看一个大家都知道的例子:</p>

 

<pre class="prettyprint" name="code"><code class="language-java hljs  has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span> {</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">eat</span>(){
        System.out.println(<span class="hljs-string">"animal eatting..."</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Cat</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span>{</span>

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">eat</span>(){

        System.out.println(<span class="hljs-string">"我吃鱼"</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span>{</span>

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">eat</span>(){

        System.out.println(<span class="hljs-string">"我吃骨头"</span>);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>(){
        System.out.println(<span class="hljs-string">"我会跑"</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> {</span>

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span>(String[] args) {

        Animal animal = <span class="hljs-keyword">new</span> Cat(); <span class="hljs-comment">//向上转型</span>
        animal.eat();

        animal = <span class="hljs-keyword">new</span> Dog();
        animal.eat();
    }

}

<span class="hljs-comment">//结果:</span>
<span class="hljs-comment">//我吃鱼</span>
<span class="hljs-comment">//我吃骨头</span>
</code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li><li style="color: rgb(153, 153, 153);">6</li><li style="color: rgb(153, 153, 153);">7</li><li style="color: rgb(153, 153, 153);">8</li><li style="color: rgb(153, 153, 153);">9</li><li style="color: rgb(153, 153, 153);">10</li><li style="color: rgb(153, 153, 153);">11</li><li style="color: rgb(153, 153, 153);">12</li><li style="color: rgb(153, 153, 153);">13</li><li style="color: rgb(153, 153, 153);">14</li><li style="color: rgb(153, 153, 153);">15</li><li style="color: rgb(153, 153, 153);">16</li><li style="color: rgb(153, 153, 153);">17</li><li style="color: rgb(153, 153, 153);">18</li><li style="color: rgb(153, 153, 153);">19</li><li style="color: rgb(153, 153, 153);">20</li><li style="color: rgb(153, 153, 153);">21</li><li style="color: rgb(153, 153, 153);">22</li><li style="color: rgb(153, 153, 153);">23</li><li style="color: rgb(153, 153, 153);">24</li><li style="color: rgb(153, 153, 153);">25</li><li style="color: rgb(153, 153, 153);">26</li><li style="color: rgb(153, 153, 153);">27</li><li style="color: rgb(153, 153, 153);">28</li><li style="color: rgb(153, 153, 153);">29</li><li style="color: rgb(153, 153, 153);">30</li><li style="color: rgb(153, 153, 153);">31</li><li style="color: rgb(153, 153, 153);">32</li><li style="color: rgb(153, 153, 153);">33</li><li style="color: rgb(153, 153, 153);">34</li><li style="color: rgb(153, 153, 153);">35</li><li style="color: rgb(153, 153, 153);">36</li><li style="color: rgb(153, 153, 153);">37</li><li style="color: rgb(153, 153, 153);">38</li><li style="color: rgb(153, 153, 153);">39</li><li style="color: rgb(153, 153, 153);">40</li><li style="color: rgb(153, 153, 153);">41</li><li style="color: rgb(153, 153, 153);">42</li><li style="color: rgb(153, 153, 153);">43</li></ul></pre>

<p>这就是向上转型,Animal animal = new Cat();将子类对象Cat转化为父类对象Animal。这个时候animal这个引用调用的方法是子类方法。</p>

<blockquote>
  <p>关于方法调用的顺序,我们后面会详细讲解。</p>
</blockquote>

 

<h4 id="转型过程中需要注意的问题"><strong>转型过程中需要注意的问题</strong></h4>

<ul>
<li>向上转型时,子类单独定义的方法会丢失。比如上面Dog类中定义的run方法,当animal引用指向Dog类实例时是访问不到run方法的,<code>animal.run()</code>会报错。</li>
<li>子类引用不能指向父类对象。<code>Cat c = (Cat)new Animal()</code>这样是不行的。</li>
</ul>

 

<h4 id="向上转型的好处"><strong>向上转型的好处</strong></h4>

<ul>
<li>减少重复代码,使代码变得简洁。</li>
<li>提高系统扩展性。</li>
</ul>

<p>举个例子:比如我现在有很多种类的动物,要喂它们吃东西。如果不用向上转型,那我需要这样写:</p>

 

<pre class="prettyprint" name="code"><code class="language-java hljs  has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">eat</span>(Cat c){
    c.eat();
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">eat</span>(Dog d){
    d.eat();
}
<span class="hljs-comment">//......</span>

eat(<span class="hljs-keyword">new</span> Cat());
eat(<span class="hljs-keyword">new</span> Cat());
eat(<span class="hljs-keyword">new</span> Dog());
<span class="hljs-comment">//......</span></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li><li style="color: rgb(153, 153, 153);">6</li><li style="color: rgb(153, 153, 153);">7</li><li style="color: rgb(153, 153, 153);">8</li><li style="color: rgb(153, 153, 153);">9</li><li style="color: rgb(153, 153, 153);">10</li><li style="color: rgb(153, 153, 153);">11</li><li style="color: rgb(153, 153, 153);">12</li><li style="color: rgb(153, 153, 153);">13</li></ul></pre>

<p>一种动物写一个方法,如果我有一万种动物,我就要写一万个方法,写完大概猴年马月都过了好几个了吧。好吧,你很厉害,你耐着性子写完了,以为可以放松一会了,突然又来了一种新的动物,你是不是又要单独为它写一个eat方法?开心了么?</p>

<p>那如果我使用向上转型呢?我只需要这样写:</p>

 

<pre class="prettyprint" name="code"><code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">eat</span>(Animal a){
    a.eat();
}

eat(<span class="hljs-keyword">new</span> Cat());
eat(<span class="hljs-keyword">new</span> Cat());
eat(<span class="hljs-keyword">new</span> Dog());
<span class="hljs-comment">//.....</span></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li><li style="color: rgb(153, 153, 153);">6</li><li style="color: rgb(153, 153, 153);">7</li><li style="color: rgb(153, 153, 153);">8</li></ul></pre>

<p>恩,搞定了。代码是不是简洁了许多?而且这个时候,如果我又有一种新的动物加进来,我只需要实现它自己的类,让他继承Animal就可以了,而不需要为它单独写一个eat方法。是不是提高了扩展性?</p>

 

<h3 id="向下转型"><a name="t6"></a><strong>向下转型</strong></h3>

<p>与向上转型相对应的就是向下转型了。向下转型是把父类对象转为子类对象。(请注意!这里是有坑的。)</p>

 

<h4 id="案例驱动-1"><strong>案例驱动</strong></h4>

<p>先看一个例子:</p>

 

<pre class="prettyprint" name="code"><code class="language-java hljs  has-numbering"><span class="hljs-comment">//还是上面的animal和cat dog</span>
Animal a = <span class="hljs-keyword">new</span> Cat();
Cat c = ((Cat) a);
c.eat();
<span class="hljs-comment">//输出  我吃鱼</span>
Dog d = ((Dog) a);
d.eat();
<span class="hljs-comment">// 报错 : java.lang.ClassCastException:com.chengfan.animal.Cat cannot be cast to com.chengfan.animal.Dog</span>
Animal a1 = <span class="hljs-keyword">new</span> Animal();
Cat c1 = ((Cat) a1);
c1.eat();
<span class="hljs-comment">// 报错 : java.lang.ClassCastException:com.chengfan.animal.Animal cannot be cast to com.chengfan.animal.Cat</span></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li><li style="color: rgb(153, 153, 153);">6</li><li style="color: rgb(153, 153, 153);">7</li><li style="color: rgb(153, 153, 153);">8</li><li style="color: rgb(153, 153, 153);">9</li><li style="color: rgb(153, 153, 153);">10</li><li style="color: rgb(153, 153, 153);">11</li><li style="color: rgb(153, 153, 153);">12</li></ul></pre>

<p>为什么第一段代码不报错呢?相比你也知道了,因为a本身就是Cat对象,所以它理所当然的可以向下转型为Cat,也理所当然的不能转为Dog,你见过一条狗突然就变成一只猫这种操蛋现象?</p>

<p>而a1为Animal对象,它也不能被向下转型为任何子类对象。比如你去考古,发现了一个新生物,知道它是一种动物,但是你不能直接说,啊,它是猫,或者说它是狗。</p>

 

<h4 id="向下转型注意事项"><strong>向下转型注意事项</strong></h4>

<ul>
<li>向下转型的前提是父类对象指向的是子类对象(也就是说,在向下转型之前,它得先向上转型)</li>
<li><p>向下转型只能转型为本类对象(猫是不能变成狗的)。</p>

<blockquote>
  <p>大概你会说,我特么有病啊,我先向上转型再向下转型??</p>
</blockquote>

<p>我们回到上面的问题:喂动物吃饭,吃了饭做点什么呢?不同的动物肯定做不同的事,怎么做呢?</p></li>
</ul>

<pre class="prettyprint" name="code"><code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">eat</span>(Animal a){
    <span class="hljs-keyword">if</span>(a <span class="hljs-keyword">instanceof</span> Dog){ 
        Dog d = (Dog)a;
        d.eat();
        d.run();<span class="hljs-comment">//狗有一个跑的方法      </span>
    }
    <span class="hljs-keyword">if</span>(a <span class="hljs-keyword">instanceof</span> Cat){ 
        Cat c = (Cat)a;
        c.eat();
        System.out.println(<span class="hljs-string">"我也想跑,但是不会"</span>); <span class="hljs-comment">//猫会抱怨    </span>
    }
    a.eat();<span class="hljs-comment">//其他动物只会吃</span>
}

eat(<span class="hljs-keyword">new</span> Cat());
eat(<span class="hljs-keyword">new</span> Cat());
eat(<span class="hljs-keyword">new</span> Dog());
<span class="hljs-comment">//.....</span></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li><li style="color: rgb(153, 153, 153);">6</li><li style="color: rgb(153, 153, 153);">7</li><li style="color: rgb(153, 153, 153);">8</li><li style="color: rgb(153, 153, 153);">9</li><li style="color: rgb(153, 153, 153);">10</li><li style="color: rgb(153, 153, 153);">11</li><li style="color: rgb(153, 153, 153);">12</li><li style="color: rgb(153, 153, 153);">13</li><li style="color: rgb(153, 153, 153);">14</li><li style="color: rgb(153, 153, 153);">15</li><li style="color: rgb(153, 153, 153);">16</li><li style="color: rgb(153, 153, 153);">17</li><li style="color: rgb(153, 153, 153);">18</li></ul></pre>

<p>现在,你懂了么?这就是向下转型的简单应用,可能举得例子不恰当,但是也可以说明一些问题。</p>

<blockquote>
  <p>敲黑板,划重点!看到那个<strong>instanceof</strong>了么?</p>
</blockquote>

 

<h2 id="经典案例分析多态"><a name="t7"></a>经典案例分析多态</h2>

<p>基本的多态和转型我们都会了,最后加点餐。看一个经典案例:</p>

 

<pre class="prettyprint" name="code"><code class="language-java hljs  has-numbering">class A {
    <span class="hljs-keyword">public</span> String <span class="hljs-title">show</span>(D obj) {
        <span class="hljs-keyword">return</span> (<span class="hljs-string">"A and D"</span>);
    }

    <span class="hljs-keyword">public</span> String <span class="hljs-title">show</span>(A obj) {
        <span class="hljs-keyword">return</span> (<span class="hljs-string">"A and A"</span>);
    }

}

class B extends A{
    <span class="hljs-keyword">public</span> String <span class="hljs-title">show</span>(B obj){
        <span class="hljs-keyword">return</span> (<span class="hljs-string">"B and B"</span>);
    }

    <span class="hljs-keyword">public</span> String <span class="hljs-title">show</span>(A obj){
        <span class="hljs-keyword">return</span> (<span class="hljs-string">"B and A"</span>);
    }
}

class C extends B{

}

class D extends B{

}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo</span> {</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span>(String[] args) {
        A a1 = <span class="hljs-keyword">new</span> A();
        A a2 = <span class="hljs-keyword">new</span> B();
        B b = <span class="hljs-keyword">new</span> B();
        C c = <span class="hljs-keyword">new</span> C();
        D d = <span class="hljs-keyword">new</span> D();

        System.out.println(<span class="hljs-string">"1--"</span> + a1.show(b));
        System.out.println(<span class="hljs-string">"2--"</span> + a1.show(c));
        System.out.println(<span class="hljs-string">"3--"</span> + a1.show(d));
        System.out.println(<span class="hljs-string">"4--"</span> + a2.show(b));
        System.out.println(<span class="hljs-string">"5--"</span> + a2.show(c));
        System.out.println(<span class="hljs-string">"6--"</span> + a2.show(d));
        System.out.println(<span class="hljs-string">"7--"</span> + b.show(b));
        System.out.println(<span class="hljs-string">"8--"</span> + b.show(c));
        System.out.println(<span class="hljs-string">"9--"</span> + b.show(d));
    }
}
<span class="hljs-comment">//结果:</span>
<span class="hljs-comment">//1--A and A</span>
<span class="hljs-comment">//2--A and A</span>
<span class="hljs-comment">//3--A and D</span>
<span class="hljs-comment">//4--B and A</span>
<span class="hljs-comment">//5--B and A</span>
<span class="hljs-comment">//6--A and D</span>
<span class="hljs-comment">//7--B and B</span>
<span class="hljs-comment">//8--B and B</span>
<span class="hljs-comment">//9--A and D</span>

<span class="hljs-comment">//能看懂这个结果么?先自分析一下。</span></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li><li style="color: rgb(153, 153, 153);">6</li><li style="color: rgb(153, 153, 153);">7</li><li style="color: rgb(153, 153, 153);">8</li><li style="color: rgb(153, 153, 153);">9</li><li style="color: rgb(153, 153, 153);">10</li><li style="color: rgb(153, 153, 153);">11</li><li style="color: rgb(153, 153, 153);">12</li><li style="color: rgb(153, 153, 153);">13</li><li style="color: rgb(153, 153, 153);">14</li><li style="color: rgb(153, 153, 153);">15</li><li style="color: rgb(153, 153, 153);">16</li><li style="color: rgb(153, 153, 153);">17</li><li style="color: rgb(153, 153, 153);">18</li><li style="color: rgb(153, 153, 153);">19</li><li style="color: rgb(153, 153, 153);">20</li><li style="color: rgb(153, 153, 153);">21</li><li style="color: rgb(153, 153, 153);">22</li><li style="color: rgb(153, 153, 153);">23</li><li style="color: rgb(153, 153, 153);">24</li><li style="color: rgb(153, 153, 153);">25</li><li style="color: rgb(153, 153, 153);">26</li><li style="color: rgb(153, 153, 153);">27</li><li style="color: rgb(153, 153, 153);">28</li><li style="color: rgb(153, 153, 153);">29</li><li style="color: rgb(153, 153, 153);">30</li><li style="color: rgb(153, 153, 153);">31</li><li style="color: rgb(153, 153, 153);">32</li><li style="color: rgb(153, 153, 153);">33</li><li style="color: rgb(153, 153, 153);">34</li><li style="color: rgb(153, 153, 153);">35</li><li style="color: rgb(153, 153, 153);">36</li><li style="color: rgb(153, 153, 153);">37</li><li style="color: rgb(153, 153, 153);">38</li><li style="color: rgb(153, 153, 153);">39</li><li style="color: rgb(153, 153, 153);">40</li><li style="color: rgb(153, 153, 153);">41</li><li style="color: rgb(153, 153, 153);">42</li><li style="color: rgb(153, 153, 153);">43</li><li style="color: rgb(153, 153, 153);">44</li><li style="color: rgb(153, 153, 153);">45</li><li style="color: rgb(153, 153, 153);">46</li><li style="color: rgb(153, 153, 153);">47</li><li style="color: rgb(153, 153, 153);">48</li><li style="color: rgb(153, 153, 153);">49</li><li style="color: rgb(153, 153, 153);">50</li><li style="color: rgb(153, 153, 153);">51</li><li style="color: rgb(153, 153, 153);">52</li><li style="color: rgb(153, 153, 153);">53</li><li style="color: rgb(153, 153, 153);">54</li><li style="color: rgb(153, 153, 153);">55</li><li style="color: rgb(153, 153, 153);">56</li><li style="color: rgb(153, 153, 153);">57</li><li style="color: rgb(153, 153, 153);">58</li><li style="color: rgb(153, 153, 153);">59</li><li style="color: rgb(153, 153, 153);">60</li></ul></pre>

<p>前三个,强行分析,还能看得懂。但是第四个,大概你就傻了吧。为什么不是b and b呢?</p>

<p>这里就要学点新东西了。</p>

<blockquote>
  <p>当父类对象引用变量引用子类对象时,被引用对象的类型决定了调用谁的成员方法,引用变量类型决定可调用的方法。如果子类中没有覆盖该方法,那么会去父类中寻找。</p>
</blockquote>

<p>可能读起来比较拗口,我们先来看一个简单的例子:</p>

 

<pre class="prettyprint" name="code"><code class="hljs axapta has-numbering"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">X</span> {</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> show(Y y){
        System.out.println(<span class="hljs-string">"x and y"</span>);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> show(){
        System.out.println(<span class="hljs-string">"only x"</span>);
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Y</span> <span class="hljs-inheritance"><span class="hljs-keyword">extends</span></span> <span class="hljs-title">X</span> {</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> show(Y y){
        System.out.println(<span class="hljs-string">"y and y"</span>);
    }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> show(<span class="hljs-keyword">int</span> i){

    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">main</span>{</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> main(String[] args) {
        X x = <span class="hljs-keyword">new</span> Y();
        x.show(<span class="hljs-keyword">new</span> Y());
        x.show();
    }
}
<span class="hljs-comment">//结果</span>
<span class="hljs-comment">//y and y</span>
<span class="hljs-comment">//only x</span></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li><li style="color: rgb(153, 153, 153);">6</li><li style="color: rgb(153, 153, 153);">7</li><li style="color: rgb(153, 153, 153);">8</li><li style="color: rgb(153, 153, 153);">9</li><li style="color: rgb(153, 153, 153);">10</li><li style="color: rgb(153, 153, 153);">11</li><li style="color: rgb(153, 153, 153);">12</li><li style="color: rgb(153, 153, 153);">13</li><li style="color: rgb(153, 153, 153);">14</li><li style="color: rgb(153, 153, 153);">15</li><li style="color: rgb(153, 153, 153);">16</li><li style="color: rgb(153, 153, 153);">17</li><li style="color: rgb(153, 153, 153);">18</li><li style="color: rgb(153, 153, 153);">19</li><li style="color: rgb(153, 153, 153);">20</li><li style="color: rgb(153, 153, 153);">21</li><li style="color: rgb(153, 153, 153);">22</li><li style="color: rgb(153, 153, 153);">23</li><li style="color: rgb(153, 153, 153);">24</li><li style="color: rgb(153, 153, 153);">25</li><li style="color: rgb(153, 153, 153);">26</li><li style="color: rgb(153, 153, 153);">27</li><li style="color: rgb(153, 153, 153);">28</li><li style="color: rgb(153, 153, 153);">29</li></ul></pre>

<p>Y继承了X,覆盖了X中的show(Y y)方法,但是没有覆盖show()方法。</p>

<p>这个时候,引用类型为X的x指向的对象为Y,这个时候,调用的方法由Y决定,会先从Y中寻找。执行<code>x.show(new Y());</code>,该方法在Y中定义了,所以执行的是Y里面的方法;</p>

<p>但是执行<code>x.show();</code>的时候,有的人会说,Y中没有这个方法啊?它好像是去父类中找该方法了,因为调用了X中的方法。</p>

<p>事实上,Y类中是有show()方法的,这个方法继承自X,只不过没有覆盖该方法,所以没有在Y中明确写出来而已,看起来像是调用了X中的方法,实际上调用的还是Y中的。</p>

<blockquote>
  <p>这个时候再看上面那句难理解的话就不难理解了吧。X是引用变量类型,它决定哪些方法可以调用;show()和show(Y y)可以调用,而show(int i)不可以调用。Y是被引用对象的类型,它决定了调用谁的方法:调用y的方法。</p>
</blockquote>

<p>上面的是一个简单的知识,它还不足以让我们理解那个复杂的例子。我们再来看这样一个知识:</p>

<blockquote>
  <p>继承链中对象方法的调用的优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。</p>
</blockquote>

<p>如果你能理解这个调用关系,那么多态你就掌握了。我们回到那个复杂的例子:</p>

<p>abcd的关系是这样的:C/D —&gt; B —&gt; A</p>

<p>我们先来分析4 : <code>a2.show(b)</code></p>

<blockquote>
  <ul>
  <li>首先,a2是类型为A的引用类型,它指向类型为B的对象。A确定可调用的方法:show(D obj)和show(A obj)。</li>
  <li><code>a2.show(b)</code> ==&gt; <code>this.show(b)</code>,这里this指的是B。</li>
  <li>然后.在B类中找show(B obj),找到了,可惜没用,因为show(B obj)方法不在可调用范围内,<code>this.show(O)</code>失败,进入下一级别:<code>super.show(O)</code>,super指的是A。</li>
  <li>在A 中寻找show(B obj),失败,因为没用定义这个方法。进入第三级别:<code>this.show((super)O)</code>,this指的是B。</li>
  <li>在B中找show((A)O),找到了:show(A obj),选择调用该方法。</li>
  <li>输出:B and A</li>
  </ul>
</blockquote>

<p>如果你能看懂这个过程,并且能分析出其他的情况,那你就真的掌握了。</p>

<p>我们再来看一下9:<code>b.show(d)</code></p>

<blockquote>
  <ul>
  <li>首先,b为类型为B的引用对象,指向类型为B的对象。没有涉及向上转型,只会调用本类中的方法。</li>
  <li>在B中寻找show(D obj),方法。现在你不会说没找到了吧?找到了,直接调用该方法。</li>
  <li>输出 A and D。</li>
  </ul>
</blockquote>

 

<h2 id="总结"><a name="t8"></a>总结</h2>

<p>本篇文章的内容大体上就是这些了。我们来总结一下。</p>

<ol>
<li>多态,简而言之就是同一个行为具有多个不同表现形式或形态的能力。</li>
<li>多态的分类:运行时多态和编译时多态。</li>
<li>运行时多态的前提:继承(实现),重写,向上转型</li>
<li>向上转型与向下转型。</li>
<li>继承链中对象方法的调用的优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。</li>
</ol>

<hr>

<p>事实上,当你使用向上转型的时候,你就使用了多态。关于多态还有一些其他的知识点,比如几个关键字:static、final等,我们后面会一一讲解。下一篇《重新认识java(六) —-java中的另类:static关键字》不定期更新。</p>

<blockquote>
  <p>如果文章内容有什么问题,或者哪里出错,请及时与我联系。不保证文章内容的完全正确性。如果你有更好的简洁或者更好的理解方式,欢迎一起交流。</p>
 
  <p>原文地址:<a href="http://blog.csdn.net/qq_31655965/article/details/54746235" rel="nofollow" target="_blank">http://blog.csdn.net/qq_31655965/article/details/54746235</a> <br>
  欢迎转载~转载请注明出处! <br>
  看完了随手点个赞呗~</p>
</blockquote>            </div>
      <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-7f770a53f2.css" rel="stylesheet">
                </div>

智慧旅游解决方案利用云计算、物联网和移动互联网技术,通过便携终端设备,实现对旅游资源、经济、活动和旅游者信息的智能感知和发布。这种技术的应用旨在提升游客在旅游各个环节的体验,使他们能够轻松获取信息、规划行程、预订票务和安排食宿。智慧旅游平台为旅游管理部门、企业和游客提供服务,包括政策发布、行政管理、景区安全、游客流量统计分析、投诉反馈等。此外,平台还提供广告促销、库存信息、景点介绍、电子门票、社交互动等功能。 智慧旅游的建设规划得到了国家政策的支持,如《国家中长期科技发展规划纲要》和国务院的《关于加快发展旅游业的意见》,这些政策强调了旅游信息服务平台的建设和信息化服务的重要性。随着技术的成熟和政策环境的优化,智慧旅游的时机已经到来。 智慧旅游平台采用SaaS、PaaS和IaaS等云服务模式,提供简化的软件开发、测试和部署环境,实现资源的按需配置和快速部署。这些服务模式支持旅游企业、消费者和管理部门开发高性能、高可扩展的应用服务。平台还整合了旅游信息资源,提供了丰富的旅游产品创意平台和统一的旅游综合信息库。 智慧旅游融合应用面向游客和景区景点主管机构,提供无线城市门户、智能导游、智能门票及优惠券、景区综合安防、车辆及停车场管理等服务。这些应用通过物联网和云计算技术,实现了旅游服务的智能化、个性化和协同化,提高了旅游服务的自由度和信息共享的动态性。 智慧旅游的发展标志着旅游信息化建设的智能化和应用多样化趋势,多种技术和应用交叉渗透至旅游行业的各个方面,预示着全面的智慧旅游时代已经到来。智慧旅游不仅提升了游客的旅游体验,也为旅游管理和服务提供了高效的技术支持。
智慧旅游解决方案利用云计算、物联网和移动互联网技术,通过便携终端设备,实现对旅游资源、经济、活动和旅游者信息的智能感知和发布。这种技术的应用旨在提升游客在旅游各个环节的体验,使他们能够轻松获取信息、规划行程、预订票务和安排食宿。智慧旅游平台为旅游管理部门、企业和游客提供服务,包括政策发布、行政管理、景区安全、游客流量统计分析、投诉反馈等。此外,平台还提供广告促销、库存信息、景点介绍、电子门票、社交互动等功能。 智慧旅游的建设规划得到了国家政策的支持,如《国家中长期科技发展规划纲要》和国务院的《关于加快发展旅游业的意见》,这些政策强调了旅游信息服务平台的建设和信息化服务的重要性。随着技术的成熟和政策环境的优化,智慧旅游的时机已经到来。 智慧旅游平台采用SaaS、PaaS和IaaS等云服务模式,提供简化的软件开发、测试和部署环境,实现资源的按需配置和快速部署。这些服务模式支持旅游企业、消费者和管理部门开发高性能、高可扩展的应用服务。平台还整合了旅游信息资源,提供了丰富的旅游产品创意平台和统一的旅游综合信息库。 智慧旅游融合应用面向游客和景区景点主管机构,提供无线城市门户、智能导游、智能门票及优惠券、景区综合安防、车辆及停车场管理等服务。这些应用通过物联网和云计算技术,实现了旅游服务的智能化、个性化和协同化,提高了旅游服务的自由度和信息共享的动态性。 智慧旅游的发展标志着旅游信息化建设的智能化和应用多样化趋势,多种技术和应用交叉渗透至旅游行业的各个方面,预示着全面的智慧旅游时代已经到来。智慧旅游不仅提升了游客的旅游体验,也为旅游管理和服务提供了高效的技术支持。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值