<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Sunspl

    Hello,everyone,i am sun. 天道酬勤,笨鳥先飛.
    隨筆 - 47, 文章 - 0, 評論 - 24, 引用 - 0
    數據加載中……

    [oop] 面向對象由淺入深(轉)

    oop:使用Java開始面向對象的編程
    你正在從傳統(tǒng)的過程化的編程轉向面向對象的開發(fā)模式嗎?還是想要進入膨脹的Java世界呢?你不會感到孤單的.成千上萬的開發(fā)者和你處在相同的情形之下.在這系列文章中,我們將使用Java語言帶領你一步一步的學習面向對象的開發(fā)過程.

    OOP: 理解類和對象
    上一次在"使用Java開始面向對象的編程"這篇文章中,我們學習了一個編程語言要真正成為面向對象的,它應該支持信息隱藏/封裝,多態(tài),繼承和動態(tài)綁定.另外,我們知道了Java完全支持這些功能,而且知道了因為Java是一種解釋性的語言并運行在虛擬機的內部,所以由Java寫成的任何程序都可以在任何支持 Java虛擬機(JVM)的操作系統(tǒng)上運行.我們還明白了對象是代表現(xiàn)實生活中事物的軟件-編程模型以及對象是由它們的狀態(tài)和行為定義的.最后,我們知道了Java中除了原始數據對象以外一切都是對象.

    OOP: 繼承以及多態(tài)
    在"OOP簡介:理解類和對象"這篇文章中,我們討論了繼承和多態(tài)性的好處.我們還粗略的學習了如何擴展基類定義子類,繼承基類中合適的行為和屬性而重載那些并不適合的行為和屬性.這種方式能夠削減代碼宏余以及錯誤的堆積.

    OOP: 限制對象屬性的訪問
    這篇文章中,我們繼續(xù)討論了繼承和多態(tài)性的好處.我們還學習了其它的東西: 雖然Java只支持從一個父類繼承,但它使用接口的方式支持多重繼承. 接口實現(xiàn)了多態(tài),使得我們能夠給與對象不同特性以滿足不同的需要. 你可以使用多態(tài)機制讓完成相似功能的不同的方法擁有相同的名字但是擁有不同的參數列表.動態(tài)/運行時的綁定機制允許一個對象在運行時被強制轉化成你所需要的對象類型,前提是這個對象實現(xiàn)了必需的接口或者括展了特定的父類.

    oop: 神奇的初始化
    java在初始化的時候也有很多講究,因為java中出現(xiàn)了類,所以在初始化的時候就有可能使用到創(chuàng)建新對象,所以,對于初始化的順序要求的比較嚴格,請看下面一個程序,是thinking in java中的一個程序,被我稍加改編,這樣可以更好的說明幾個初始化的要點

    posted on 2006-09-06 11:38 JavaSuns 閱讀(430) 評論(5)  編輯  收藏

    評論

    # re: [oop] 面向對象由淺入深  回復  更多評論   

    一種語言是面向對象的究竟意味著什么呢?如果一種編程語言是真正的面向對象的語言,它必須支持以下的特點:

    封裝--隱藏實現(xiàn)細節(jié)
    多態(tài)--將同一個消息發(fā)送給不同的對象并使各個對象以預定的方式對消息做出響應的能力
    繼承--拓展現(xiàn)存的類來生成專有類繼承原來類的狀態(tài)和行為的能力
    動態(tài)綁定--在編程時不必知道對象的具體類型就能向它們發(fā)送消息的能力

    讓我們考察一下Java是如何支持這些功能的以及它又如何提供了附加的功能來使得從過程化的程序設計到面向對象的開發(fā)的轉變過程相對容易.


    Java中面向對象的特點
    Java是由Sun Microsystems公司在九十年代中期發(fā)布的面向對象(OOP)的編程語言.你可以從Sun公司的網站上下載最新的Java開發(fā)包(JDK).Java是一種解釋性的語言,這意味著其源程序首先被編譯成中間代碼的形式,然后在每次運行之前都要經過虛擬機的解釋,它是徹頭徹尾的面向對象的編程語言.

    Java對程式員隱藏了許多傳統(tǒng)的面向對象編程語言--比方說C++和Object Pascal--的復雜性和讓人容易混淆的地方.例如,Java中沒有了指針,Java會為程序員自動的清除引用類型,而且所有變量將被自動初始化成適當的缺省值.除了原始數據類型以外,Java中的所有東西都是對象,必要的時候,甚至可以為原始數據類型也提供封裝機制.


    對象簡介
    對象是代表現(xiàn)實生活中的實物的軟件編程實體,比如說銀行帳號,計算機用戶,用戶介面上的按鈕,窗口菜單等等.對象是由它們的狀態(tài)和行為定義的.例如,一個銀行帳號擁有一種狀態(tài),諸如當前的收支狀況,賬戶的所有人,允許的最小交易額,等等,而它的行為則包括提取,存入,收支平衡等.

    一個對象的狀態(tài)是由只有對象自己知道的變量定義的.Java把這些變量稱為數據域或者成員變量.數據域對對象來說是私有的除非顯式的使用關鍵字來定義它們的作用域,使它們對其它類可見.我們將在以后討論變量作用域的問題.

    一個對象的行為是由它上面的操作定義的.在Java中,這些操作被叫做方法.方法可以改變一個對象的狀態(tài),創(chuàng)建新對象,實現(xiàn)實用的功能等.



    類是一個實體,它定義了一個對象的運行方式以及在對象被創(chuàng)建或者說實例化的時候所包含的數據.類的作用就象一個模板,一個或者多個對象可以依照它來創(chuàng)建.下面是使用Java面向對象的概念申明HelloWorld應用程序的例子:

    public class HelloWorld
    {
    private String helloMsg = "Hello World!";
    public static void main(String[] args)
    {
    HelloWorld hw = new HelloWorld();
    }

    public HelloWorld()
    {
    // 顯示我們的"Hello World"消息
    System.out.println(helloMsg);
    }
    }

    上面的例子定義了一個模板,真實的HelloWorld對象可以從這個模板創(chuàng)建.你還會注意到從public static void main(String[] args)這一行開始的一段奇怪的代碼.這一段代碼定義的是一個特殊的方法main,它其實就是我們這個HelloWorld程序的入口點,上面的程序是一個典型的演示所有的Java應用程序如何定義它們的入口點.注意到即使是這個main入口點也被封裝在類里面.對于這個例子,我們就是將它封裝在HelloWorld類里.上面的程序展示了如何定義一個類,HelloWorld,以及其中的一個數據域,helloMsg和兩個方法main和HelloWorld.HelloWorld方法是一種特殊的方法,這種方法被稱做構造函數.我們將在后面的文章里討論常規(guī)方法,構造函數和靜態(tài)成員函數的細節(jié)和區(qū)別.

    在Java中,所有與一個特殊的類有關的源代碼都寫在一個與類同名的擁有后綴名.java的文件里.Java編譯器讀取源文件并將它們翻譯成平臺無關的,二進制格式的代碼,成為字節(jié)代碼,然后將這些代碼分類保存在與類同名的但是后綴為.class的文件里.你最終會為每一個類得到一個class文件.


    編譯并運行我們的例子程序
    一旦你已經從Sun的Web站點上下載了JDK并在你的機器上安裝了它,你就可以開始編譯并運行Java程序了.要編譯并運行我們的例子程序,將HelloWorld類的代碼粘貼到你最喜歡的文檔編輯器里,將文件保存為HelloWorld.java,然后,在命令提示符下,將當前路徑改變到包含了這個文件的路徑里.現(xiàn)在你就可以在命令行提示符下鍵入下面的命令來編譯程序了:

    Windows:
    <你的JDK所在目錄>\bin\javac HelloWorld.java

    UNIX or Linux:
    <你的JDK所在目錄>/bin/javac HelloWorld.java

    這個命令將在同一個目錄里產生一個新的文件,叫做HelloWorld.class.要運行這個程序,請在命令提示符下鍵入下面的命令:

    Windows:
    <你的JDK所在目錄>\bin\java HelloWorld

    UNIX or Linux:
    <你的JDK所在目錄>/bin/java HelloWorld

    你應該可以看到屏幕上顯示Hello World!

    總結
    我們已經接觸到了使用Java程序設計語言進行面向對象的編程的一些皮毛知識.下次,我們將剖析我們的例子程序,給它添加更多的功能,并討論更多的有關對象,類和其它面向對象編程的基本概念以及用Java如何實現(xiàn)它們.
    2006-09-06 11:38 | JavaSuns

    # re: [oop] 面向對象由淺入深  回復  更多評論   

    對象詳論
    使用對象的一個關鍵是當你在瀏覽系統(tǒng)分析文檔或者設計文檔的時候如何來確定它們.因為對象一般代表人,地方或者事物,所以一個確定對象的基本的方法就是找出句子中所使用的名詞.這里有一個簡單的例子.在句子"一個顧客可以擁有多于一個的銀行帳號",我們就確定了兩個對象,客戶和帳號.在句子"小貓喵喵叫"中,我們能夠確定一個對象,貓.

    類詳論
    前面,我們學習了一個類是定義了對象如何動作以及當對象創(chuàng)建或者說實例化的時候應該包含些什么的實體.在對動物的討論中,我們可以說,"狗兒汪汪叫,貓喵喵叫,鴨子嘎嘎叫."確定句子中的對象我們就得到了狗,貓和鴨子.至于汪汪叫,喵喵叫,嘎嘎叫,那都是我們對象發(fā)出的行為動作.

    要實現(xiàn)這些對象,我們需要創(chuàng)建三個對象分別叫Dog,Cat和Duck.要實現(xiàn)它們的行為,我們可以為每一個這些對象創(chuàng)建代表每個對象發(fā)出的聲音的方法,而且我們把這個方法叫做speak或者,如果我們發(fā)揮想象力的話還可以把這個方法叫做sayHello.

    在程序的上下文中為了演示這些概念,讓我們修改上篇文章中的HelloWorld程序,添加這三個新對象并給它們中的每一個添加sayHello方法,如下所示:

    public class HelloWorld
    {
    public static void main(String[] args)
    {
    Dog animal1 = new Dog();
    Cat animal2 = new Cat();
    Duck animal3 = new Duck();
    animal1.sayHello();
    animal2.sayHello();
    animal3.sayHello();
    }
    }

    class Dog
    {
    public void sayHello()
    {
    System.out.println("Bark");
    }
    }

    class Cat
    {
    public void sayHello()
    {
    System.out.println("Meow");
    }
    }

    class Duck
    {
    public void sayHello()
    {
    System.out.println("Quack");
    }
    }

    在編譯并運行了這個程序以后,輸出應該如下:
    Bark
    Meow
    Quack

    看看我們的程序,我們馬上就注意到了一些事情:每個對象代表了一種動物,而每個對象實現(xiàn)了一個相同的方法,sayHello.假設我們想要給對象更多的功能以及用來代表對象所指的動物的方法和屬性.比方說,我們可以添加一個方法來確定一個動物是不是哺乳類的,或者我們添加一個方法來確定一個動物是不是肉食性的.我們可以通過給每一個對象添加這兩種方法來實現(xiàn)或者我們也能夠使用OOP的兩個最強大的功能:繼承和多態(tài).

    因為所有的對象都代表一個對象,所以我們將創(chuàng)建一個被稱為"基類"或是"超類"的類,它的名字是Animal.我們然后可以讓我們的對象從Animal類繼承相同的特點并強制每個對象只實現(xiàn)與Animal類不同的功能.

    Java用extends關鍵字指明一個類從另一個繼承.讓我們利用繼承和多態(tài)的概念獲得代碼重用的好處來重建我們的程序并使得每個對象只實現(xiàn)與基類Animal不同的功能:

    public class HelloWorld
    {
    public static void main(String[] args)
    {
    Dog animal1 = new Dog();
    Cat animal2 = new Cat();
    Duck animal3 = new Duck();
    System.out.println("A dog says " +animal1.getHello()
    +", is carnivorous: " +animal1.isCarnivorous()
    +", is a mammal: " +animal1.isAMammal());

    System.out.println("A cat says " +animal2.getHello()
    +", is carnivorous: " +animal2.isCarnivorous()
    +", is a mammal: " +animal2.isAMammal());

    System.out.println("A duck says " +animal3.getHello()
    +", is carnivorous: " +animal3.isCarnivorous()
    +", is a mammal: " +animal3.isAMammal());
    }
    }

    abstract class Animal
    {
    public boolean isAMammal()
    {
    return(true);
    }

    public boolean isCarnivorous()
    {
    return(true);
    }

    abstract public String getHello();
    }

    class Dog extends Animal
    {
    public String getHello()
    {
    return("Bark");
    }
    }

    class Cat extends Animal
    {
    public String getHello()
    {
    return("Meow");
    }
    }

    class Duck extends Animal
    {
    public boolean isAMammal()
    {
    return(false);
    }

    public boolean isCarnivorous()
    {
    return(false);
    }

    public String getHello()
    {
    return("Quack");
    }
    }

    在編譯并運行我們的程序以后,輸出應該如下:
    A dog says Bark, is carnivorous: true, is a mammal: true
    A cat says Meow, is carnivorous: true, is a mammal: true
    A duck says Quack, is carnivorous: false, is a mammal: false

    看看我們的例子,你將發(fā)現(xiàn)我們定義了一個叫做Animal的新類,它定義了三個方法:isAMammal, isCarnivorous, 和 getHello.你一概還注意到了,我們在每個現(xiàn)存的類申明的前面都添加了extends Animal這個語句.這個語句告訴編譯器這些對象是Animal類的子類.

    因為方法isAMammal 和 isCarnivorous 都返回 true,所以Dog和Cat類用不著重新實現(xiàn)--即"重載"這兩個方法.但是鴨子既不是哺乳動物又不是肉食性的,所以Duck類需要重載這兩種方法來返回正確的值.我們所有的對象都以自己獨特的方式說"hello",所以它們都需要重載getHello方法.因為每種動物說"hello"的方式都不同,所以我們在基類中將getHello方法申明為抽象的,而且我們沒有給這個方法一個函數體.這就迫使Animal的每一個子類重載getHello方法并根據每一個特定動物的需要來定義它.

    因為我們將getHello方法申明為虛擬的,我們就不能直接實例化Animal對象.因此,我們需要將Animal類也申明為抽象的.我們通過在Animal類定義的開始行添加abstract關鍵字來實現(xiàn)這一點.子類重載它們基類的方法的能力就是多態(tài).多態(tài)使得子類能夠使用基類的方法或是在這些方法不足的時候重載它們.這就實現(xiàn)了代碼重用,加快了代碼的實現(xiàn)過程,而且它還隔離和程序中的bug,使得程序的維護更容易.

    總結
    在本文中,我們學習了如何確定潛在的對象.我們還學習了如何使用繼承和多態(tài)來加快我們的代碼實現(xiàn)過程并隔離錯誤,這使得代碼的維護過程更加容易.下一次,我們將展開討論多態(tài)和繼承的概念并開始我們對動態(tài)綁定的討論.
    2006-09-06 11:39 | JavaSuns

    # re: [oop] 面向對象由淺入深  回復  更多評論   

    深入繼承性
    一些面向對象的語言提供叫做"多重繼承"的特點,當一個對象需要從多于一個的基類繼承行為和屬性的時候這是有價值的.多重繼承在有些情況下是復雜的.例如,假設我們需要定義一個基類,Animal,然后是Animal的兩個子類,LandAnimal 和 WaterAnimal.現(xiàn)在我們想要定義一個類來代表青蛙.青蛙是兩棲動物,所以我們自然會想到定義Frog類從LandAnimal和WaterAnimal類繼承.這使得Frog類能夠同時從LandAnimal 和WaterAnimal類繼承所需的行為和屬性.

    初看起來這是相當簡單的;但是,讓我們?yōu)锳nimal添加一個叫做LivingEnvironment的屬性,并用方法getLivingEnvironment來返回它.我們假設LandAnimal 和 WaterAnimal類都重載了這個方法來實現(xiàn)特殊的功能.LandAnimal將返回Land作為它的LivingEnvironment屬性的值,而WaterAnimal將返回Water作為它的LivingEnvironment屬性的值.現(xiàn)在,當我們將Frog類作為LandAnimal 和 WaterAnimal 子類實現(xiàn)的時候,想要得到Frog的LivingEnvironment屬性值,這時將遇到一個麻煩:Frog類的getLivingEnvironment方法是返回Land值呢還是Water值?答案取決于編譯器如何處理多重繼承.

    我在前面的文章里就已經說過,Java不支持多重繼承.但它確實允許一個對象通過使用叫做"接口"的功能擁有多個特性.下面的例子顯示了定義LandAnimal的接口的可能的定義代碼:
    public interface LandAnimal
    {
    public int getNumberOfLegs();
    public boolean hasATail();
    }

    一個使用接口的類在類定義語句的開始添加implements+接口名.例如,在Java中,我們會以下面的方式定義Frog類:


    public class Frog extends Animal implements LandAnimal, WaterAnimal

    接口并沒有什么實際的功能;相反,它的作用是聯(lián)系使用者和實現(xiàn)了這個接口的對象.接口保證了對象實現(xiàn)接口定義的方法.而且,一個實現(xiàn)接口的對象能夠在運行時被強制轉換成接口類型.例如,使用上面的Frog定義,并且假設LandAnimal類定義了一個叫做getNumberOfLegs的方法而WaterAnimal定義了一個叫做hasGills的方法,那么一個Frog類的實例可以在運行時被強制轉換成LandAnimal或WaterAnimal對象:


    Frog aFrog = new Frog();
    int legCount = ((LandAnimal)aFrog).getNumberOfLegs();
    Boolean gillFlag = ((WaterAnimal)aFrog).hasGills();


    注意Forg為什么能夠被強制轉換成一個LandAnimal對象即使實際的LandAnimal對象并沒有被創(chuàng)建.這使得我們能夠在運行時以其帶有的任何"身份"調用一個對象,這就是所謂的"動態(tài)綁定"或"運行時綁定".
    2006-09-06 11:40 | JavaSuns

    # re: [oop] 面向對象由淺入深  回復  更多評論   

    雖然Java只支持從一個父類繼承,但它使用接口的方式支持多重繼承.
    接口實現(xiàn)了多態(tài),使得我們能夠給與對象不同特性以滿足不同的需要.
    你可以使用多態(tài)機制讓完成相似功能的不同的方法擁有相同的名字但是擁有不同的參數列表.
    動態(tài)/運行時的綁定機制允許一個對象在運行時被強制轉化成你所需要的對象類型,前提是這個對象實現(xiàn)了必需的接口或者括展了特定的父類.

    下面我們將討論通過限制對對象屬性和方法的訪問來強制實現(xiàn)對多重接口實現(xiàn)和父類拓展的正確使用的目的和實用性.


    黑箱方法:封裝
    一個基本的面向對象的概念就是封裝--將表示一個對象狀態(tài)的數據與其它對象隔離開來.這一點是通過一個通常叫做作用域的概念來實現(xiàn)的.作用域指的是編程語言的一種能力,這種能力被用來實現(xiàn)一些限制對類或者結構體成員變量的訪問的規(guī)則.大多數面向對象的語言支持作用域機制,這些機制通常是通過諸如public, protected, 和 private之類的特殊關鍵字來實現(xiàn)的.

    Java提供了四種不同的作用范圍:public, package, protected, 和 private.任何類,方法或者成員變量都能通過使用public, protected, 和 private關鍵字來顯式的加以保護.任何類,方法,或者成員變量如果沒有使用上面的關鍵字都將被隱式的給與package的作用范圍.所有這些就構成了Java中命名空間的概念.


    命名空間和軟件包
    一個命名空間可以被看成是在一個給定的上下文中一組相關的名字或是標識符.命名空間避免了擁有相同名字或標識符的實體存在于同一個上下文里.這里隱含的意思是只要實體是存在于不同的命名空間中,那么擁有相同名字或者標識符的實體就能夠呆在一塊兒.Java使用軟件包的概念來實現(xiàn)命名空間和作用范圍控制.

    軟件包是一個在統(tǒng)一的名字下的類和接口的集合.每一個類或者接口都必須存在于用package關鍵字構成的軟件包申明語句定義的命名空間中.例如,下面的申明語句:

    package com.mycompany.apps.HelloWorld;

    它申明了一個存在于com.mycompany.apps軟件包中的名叫HelloWorld的類或者接口.軟件包申明總是放在包含了類或者接口定義的文件的頂部.

    在java開發(fā)界,目前對軟件包的命名有一個建議,就是使用公司或組織的域名(以相反的順序),作為你的軟件包的第一部分.因為域名是全球唯一的,所以使用你的域名來命名你的軟件包也能使你軟件包的名字全球唯一.

    如果一個Java類或者接口沒有包含一個軟件包申明,那么它就屬于"unamed package,"也就是沒有名字的軟件包.無名的軟件包應該只用來測試程序或是代碼原型等等.

    2006-09-06 11:41 | JavaSuns

    # re: [oop] 面向對象由淺入深  回復  更多評論   

    class Cup

    {

    Cup(int marker)

    {

    System.out.println("Cup(" + marker + ")");

    }

    void f(int marker)

    {

    System.out.println("f(" + marker + ")");

    }

    }



    class Cups

    {

    static Cup c1=new Cup(1);

    Cup c3=new Cup(3);

    static Cup c2= new Cup(2);

    Cups()

    {

    System.out.println("Cups()");

    }

    Cup c4=new Cup(4);

    }



    public class ExplicitStatic

    {

    Cups c=new Cups();

    {

    System.out.println("Hello");

    }

    public static void main(String[] args)

    {

    System.out.println("Inside main()");

    Cups.c1.f(99);

    ExplicitStatic x=new ExplicitStatic();

    }

    static Cups x = new Cups();

    }

    大家可以手動執(zhí)行一下這個程序,考慮一下結果是什么,然后參照下面的答案對照一下,看看是否正確:



    Cup(1)

    Cup(2)

    Cup(3)

    Cup(4)

    Cups()

    Inside main()

    f(99)

    Cup(3)

    Cup(4)

    Cups()

    Hello

    我總結了四個初始化的要點,如下:

    1、 如果有static,即靜態(tài)成員定義,首先初始化static的變量,如,在類Cups中c3在c2前面,可是在輸出的結果中,你可以發(fā)現(xiàn),c2是在c3前執(zhí)行的,這就是因為,所有的static都在第一時間被初始化。

    2、 Static只初始化一次,在第二次創(chuàng)建類的對象的時候,就不會去執(zhí)行static的語句,如,在第二次執(zhí)行new Cups()的時候,就只輸出了Cup(3)和Cup(4),顯然,static的兩個創(chuàng)建對象的語句沒有做。

    3、 變量的初始化在方法前。如,在Cups類中,方法Cups()在語句Cup c4=new Cup(4)之前,可是輸出結果的時候,打印的Cups()卻在Cup(4)之后。

    4、 在含有main的類中執(zhí)行順序是先做static,然后就是main,而不是像其它類一樣,除了static就按順序做下來。如,在main函數中,如果去掉語句ExplicitStatic x=new ExplicitStatic(),則Cups c=new Cups()和System.out.println("hello")都不會執(zhí)行。另外,留個小問題,如果去掉了System.out.println("hello")外的括號會怎么樣呢?

    2006-09-06 11:41 | JavaSuns

    只有注冊用戶登錄后才能發(fā)表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲精品自拍视频| 亚洲专区在线视频| 国产精品亚洲专区一区| 国产成人精品免费直播| 瑟瑟网站免费网站入口| 国内精品99亚洲免费高清| 久久精品免费大片国产大片 | 内射无码专区久久亚洲| 日日摸日日碰夜夜爽亚洲| 国产无遮挡吃胸膜奶免费看 | 亚洲视频免费一区| 久久受www免费人成_看片中文| 亚洲国产精品久久丫| 全免费A级毛片免费看网站| 另类图片亚洲校园小说区| 亚洲一区无码精品色| 免费一级毛片无毒不卡| 亚洲视频小说图片| 免费鲁丝片一级在线观看| 免费夜色污私人影院网站电影| 亚洲精品无码久久千人斩| 91精品免费不卡在线观看| 亚洲最大中文字幕无码网站 | 国产亚洲精品一品区99热| 99精品一区二区免费视频| 亚洲天堂男人影院| 亚洲成A人片在线观看中文| 免费人成网站在线观看不卡| 亚洲精品亚洲人成在线播放| 亚洲AⅤ无码一区二区三区在线 | 久久亚洲最大成人网4438| 国产伦精品一区二区三区免费迷 | 99re6热视频精品免费观看| 中文字幕在线观看亚洲视频| 亚洲日韩在线第一页| 2021在线永久免费视频| 精品一区二区三区免费毛片| 亚洲AV无码一区二区二三区软件 | 国产91免费视频| 国产亚洲精品免费| 亚洲国产二区三区久久|