zoukankan      html  css  js  c++  java
  • 面向对象,封装,构造方法,this关键字,main,继承,接口,多态阶段性小结

    一、局部变量和成员变量

    成员变量:  定义在类中变量

    局部变量:  定义在方法中变量

    1成员变量与局部变量的区别:

    1. 应用范围  
      1. 成员变量在整个类内都有效    
      2. 局部变量只在其声明的方法内有效
    2. 生命周期  
      1. 成员变量: 它属于对象,它随着对象的创建而创建,随着对象的消失而消失 
      2. 局部变量: 使用完马上释放空间。
      3. 存储位置  成员变量属于对象,它存储在堆内,堆内的实体,当没有引用指向其时,才垃圾回收清理 局部变量存在栈内存中,当不在使用时,马上就会被释放。
      4. 初始值

    成员变量它存储在堆中,如果没有赋初值,它有默认值。

    1. 整数byte、short、int、long =0;
    2. char='uoooo';
    3. boolean =flase;
    4. String =null;
    5. 类类型 =null;
    6. 数组 =null;

        局部变量,如果要想使用必须手动初始化.

    1. 方法中,参数列表中,语句中。
    2. 必须给初始化值,没有初始值,不能使用
    3. 在栈内存中

    2内存分析:

    二、匿名对象

    1匿名对象:没有名字的实体,也就是该实体没有对应的变量名引用。

    1.1匿名对象的用途

    1,当对象对方法进行一次调用的时候,可以使用匿名对象对代码进行简化。

       为什么只对方法,而不调用属性呢?因为匿名对象调用属性没意义。

       如果对象要多成员进行多次调用,必须给对象起个名字。不能在使用匿名     对象。

    2,匿名对象可以实际参数进行传递。

        1.2:匿名对象的简单演示

    1new Car().run();

    1.3:内存结构图

    1new Car().num=5;

    2new Car().clor="blue";

    两个new 是两个不同的对象,在堆内存中有不同的空间,相互不相互干扰。

    1.4:匿名对象的使用

    1:当只使用一次时可以使用匿名对象。执行完毕到;该对象就变成了垃圾。

    new Car().run();

      2:执行方法时,可以将匿名对象作为实际参数,传递进去。

    三、封装

    1模拟问题没有封装会怎样

    1. 描述Employee类。定义姓名,工号,性别的成员变量,和工作的方法。成员使用public修饰。
    2. 创建Employee对象,对象.成员的方式进行赋值。最后该对象调用工作方法。
    3. 总结:如果不使用封装,很容易赋值错误,并且任何人都可以更改,造成信息的    不安全。
    4. 问题解决使用封装

    2封装的实现

    1:设置类的属性private(关键字),不能使用对象名.属性名的方式直接访问对象的属性。

         问题:

    1:为什么之前可以通过对象名.属性名的方式访问?

    2public 成员修饰符,公共的谁都可以访问。

    3private 成员修饰符,私有的,只有自己可以访问。

    2:修改Employee类 性别的修饰符修改为private

    1:编译不通过

    2private修饰的成员在自己所在的类中可以使用,在类外边不可以使用。

    3Employee类的gender的修饰符修改为private后,无法再类外调用,那么如何给gender设置值?

    1:对外提供公开的用于设置对象属性的public方法

    1:设置set

    2:获取get

    2:在set方法中加入逻辑判断,过滤掉非法数据。

    3:将所有的成员变量封装加上private,提供getset方法

    3封装的好处

    1:隐藏了类的具体实现

    2:操作简单

    3:提高对象数据的安全性

    四、构造方法

    1  问题的提出

    1.我们人出生的时候,有些人一出生之后再起名字的,但是有些人一旦出生就已经起好名字的。那么我们在java里面怎么在对象一旦创建就赋值呢?

    2 构造方法的作用

    构造方法作用:对对象进行初始化.

    3  构造函数与普通的函数的区别

    1. 一般函数是用于定义对象应该具备的功能。而构造函数定义的是,对象在调用功能之前,在建立时,应该具备的一些内容。也就是对象的初始化内容。
    2. 构造函数是在对象建立时由jvm调用, 给对象初始化。一般函数是对象建立后,当对象调用该功能时才会执行。
    3. 普通函数可以使用对象多次调用,构造函数就在创建对象时调用。
    4. 构造函数的函数名要与类名一样,而普通的函数只要符合标识符的命名规则即可。
    5. 构造函数没有返回值类型。

    4构造函数注意的细节

    1. 当类中没有定义构造函数时,系统会指定给该类加上一个空参数的构造函数。这个是类中默认的构造函数。当类中如果自定义了构造函数,这时默认的构造函数就没有了。

    备注:可以通过javap命令验证。

    2.在一个类中可以定义多个构造函数,以进行不同的初始化。多个构造函数存在于类中,是以重载的形式体现的。因为构造函数的名称都相同。

    五、构造代码块

    1作用

    构造代码块作用:给所有的对象进行统一的初始化。

    1:作用

    1:给对象进行初始化。对象一建立就运行并且优先于构造函数。

    2:与构造函数区别

    1:构造代码块和构造函数的区别,构造代码块是给所有对象进行统一初始化, 构造函数给对应的对象初始化。

        2:构造代码块的作用:它的作用就是将所有构造方法中公共的信息进行抽取

    例如孩子一出生统一哭

    六、this关键字

    1 this 的概述

    this关键字代表是对象的引用。也就是this在指向一个对象,所指向的对象就是调用该函数的对象引用。

    2 this关键字的作用

    1.一个类中存在同名的成员变量与局部变量的时候,可以通过this关键字指定访问

    成员变量的数据。

    2.this关键字还可以在构造函数中调用另外一个构造函数初始化对象。

    3 this关键字调用构造函数要注意的事项:

       1.this关键字调用其他的构造函数时,必须是在第一个语句。

       2.this关键字调用构造函数时不能出现相互调用,因为是一个死循环。

       3.如果在方法的内部访问一个变量时,该变量只存在于成员变量中, 局部变量没有,这时候java编译器会为该变量的前面添加一个this关键字。

    七、static关键字

    1.static关键字作用

    1:为了实现对象之间重复属性的数据共享

    2.static的使用

       Static 主要用于修饰类的成员

    1:成员变量

                1:非静态成员变量:需要创建对象来访问

        2:静态成员变量:使用类名直接调用,也可以通过对象访问

    2:成员方法

          静态成员方法可以使用类名直接调用

    3.static需要注意的事项

        1:静态函数中不能访问非静态成员变量,只能访问静态变量。

    2:静态方法不可以定义this,super关键字.

    3:因为静态优先于对象存在.静态方法中更不可以出现this

    4:非静态函数:非静态函数中可以访问静态成员变量

    5:静态函数中不能使用非静态变量非静态函数可以访问静态变量

    原因:为什么静态函数中不能访问非静态成员

        因为static修饰的成员在共享区中。优先于对象存在

        验证

        使用静态代码块验证

        静态代码块

        static{

        静态代码块执行语句;

          }

           静态代码块特点

    随着类的加载而加载。只执行一次,优先于主函数。用于给类进行初始化。

    4.static特点

    1 随着类的加载而加载,静态会随着类的加载而加载,随着类的消失而消失。说明它的生命周期很长。

           2 优先于对象存在。-->静态是先存在,对象是后存在。

          3 被所有实例(对象)所共享。

           4 可以直接被类名调用

    5.静态变量(类变量)和实例变量的区别:

         1存放位置

             1:类变量随着类的加载而加载存在于方法区中.

              2:实例变量随着对象的建立而存在于堆内存中.

         2生命周期

              1:类变量生命周期最长,随着类的消失而消失.

              2:实例变量生命周期随着对象的消失而消失.

    6.静态优缺点

    1: 优点:静态对象的共享数据进行单独空间的存储,节省空间 例如Person 都有国籍。该数据可以共享可以被类名调

    2:缺点:生命周期过长访问出现局限性。(静态只能访问静态)

    7. 什么时候定义静态变量

    1:静态变量(类变量)当对象中出现共享数据

      例如:学生的学校名称。学校名称可以共享

            对象的数据要定义为非静态的存放在对内存中(学生的姓名,学生的年龄)

    8.什么时候定义静态函数

    如果功能内部没有访问到非静态数据(对象的特有数据。那么该功能就可以定义为静态)

    9.静态的应用

    自定义数组工具类

    10.static修饰方法(静态的成员方法)
    访问方式:
            方式一:可以使用对象进行访问。
            对象.静态的函数名();

    方式二:可以使用类名进行访问。

    类名.静态函数名字。

    推荐使用是类名直接访问静态的成员。

    11.静态的成员变量与非静态的成员变量的区别:

    1. 作用上的区别:

    1. 静态的成员变量的作用共享一个 数据给所有的对象使用。

    2. 非 静态的成员变量的作用是描述一类事物的公共属性。

    2. 数量与存储位置上的区别:

    1. 静态成员变量是存储方法 区内存中,而且只会存在一份数据。

    2. 非静态的成员变量是存储在堆内存中,有n个对象就有n份数据。

    3. 生命周期的区别:

    1. 静态的成员变量数据是随着类的加载而存在,随着类文件的消失而消失。

    2.非静态的成员数据是随着对象的创建而存在,随着 对象被垃圾回收器回收而消失。

    12.静态函数要注意的事项:

    1. 静态函数是可以调用类名或者对象进行调用的,而非静态函数只能使用对象进行调用。

    2. 静态的函数可以直接访问静态的成员,但是不能直接访问非静态的成员。

    原因:静态函数是可以使用类名直接调用的,这时候可能还没有存在对象,

    而非静态的 成员数据是随着对象 的存在而存在的。

    3. 非静态的函数是可以直接访问静态与非静态的成员。

    原因:非静态函数只能由对象调用,当对象存在的时候,静态数据老早就已经存在了,而非静态数据也随着对象的创建而存在了。

    4. 静态函数不能出现this或者super关键字。

    原因:因为静态的函数是可以使用类名调用的,一旦使用类名调用这时候不存在对象,而this关键字是代表了一个函数 的调用者对象,这时候产生了冲突。

    5.静态的数据的生命周期:静态的成员变量数据是优先于对象存在的。

    13.static什么时候修饰一个函数?

    如果一个函数没有直接访问到非静态的成员时,那么就可以使用static修饰了。 一般用于工具类型的方法。

    14.静态函数为什么不能不能访问非静态的成员?

    静态函数只要存在有对象,那么也可以访问非 静态的数据。只是不能直接访问而已。

    15.静态的成员变量与非静态的成员变量的区别:

         1作用上的区别:

              1 .静态的成员变量的作用共享一个数据给所有的对象使用。

              2.非静态的成员变量的作用是描述一类事物的公共属性。

          2数量与存储位置上的区别:

               1.静态成员变量是存储方法区内存中,而且只会存在一份数据。

               2.非静态的成员变量存储在堆内存中,有n个对象就有n份数据。

           3.生命周期的区别:

                1.静态的成员变量数据是随着类的加载而存在,随着类文件的消失而消失。

                2.非静态的成员数据是随着对象的创建而存在,随着对象被垃圾回收器回收而消失。

    main方法详解

    1主函数是静态的

    public static void main(String[] args){

          

    }

    2主函数是什么:主函数是一个特殊的函数,作为程序的入口,可以被jvm识别。

    3主函数的定义:

           public :代表该函数的访问权限是最大的。

           static :代表主函数随着类的加载,就已经存在了。

           void:  主函数没有具体的返回值

           main : 不是关键字,是一个特殊的单词可以被jvm识别。

           (String[] args) 函数的参数,参数类型是一个数组,该数组中的元素是字符串。字符串类型的数组。

           主函数的格式是固定的:jvm能够识别

           jvm在调用函数是,传入的是new String[0];

    九、继承

    1.问题的提出

    1:如果没有继承,出现类和类的关系无法描述

    2:如果没有继承,类和类之间有关系会出现类和类的描述代码的重复。

    2.继承特点

    1:描述类和类之间的关系

    2:降低类和类之间的重复代码

    3:降低对象和对象之间的代码重复使用静态变量

    4:降低类和类之间的代码重复使用就继承

    3.extends关键字

    继承使用extends关键字实现

    1:类名的设定,被继承的类称之为父类(基类),继承的类称之为子类

    2:子类并不能继承父类中所有的成员

    1:父类定义完整的成员 静态成员,非静态,构造方法。静态变量和静态方

    法都可以通过子类名.父类静态成员的形式调用成功

    2:所有的私有成员不能继承,private修饰的成员。

    3:构造函数不能被继承

    3:如何使用继承

    1:不要为了使用继承而继承。工人和学生都有共性的成员,不要为了节省代

    码,让工人继承学生。

    十、super关键字

        Super关键字对于有继承关系的类,子类可以通过这个关键字调用父类中的方法。

    1super关键字作用

    1:主要存在于子类方法中,用于指向子类对象中父类对象。

    2:访问父类的属性

    3:访问父类的函数

    4:访问父类的构造函数

    2super注意

    1thissuper很像,this指向的是当前对象的调用,super指向的是当前调用对象的父类。Demo类被加载,执行main方法,Son.class加载,发现有父类Father类,于是Father类也加载进内存。类加载完毕,创建对象,父类的构造方法会被调用(默认自动无参),然后执行子类相应构造创建了一个子类对象,该子类对象还包含了一个父类对象。该父类对象在子类对象内部。this super只能在有对象的前提下使用,不能在静态上下文使用。

    2:子类的构造函数默认第一行会默认调用父类无参的构造函数,隐式语句

    super();

    1:父类无参构造函数不存在,编译报错。

       

    Son(int y) {

    //super();隐式语句

    this.y = y + x;

    System.out.println("这是子类的有参构造");

    }

    3:子类显式调用父类构造函数

    在子类构造函数第一行通过super关键字调用父类任何构造函数。如果显式调用父类构造函数,编译器自动添加的调用父类无参数的构造就消失。构造函数间的调用只能放在第一行,只能调用一次。super() this()不能同时存在构造函数第一行。

    Son(int y) {

    super(y);// 子类显式调用父类构造函数

    this.y = y + x;

    System.out.println("这是子类的有参构造");

    }

    Son(int y) {

    this();  //不能同时存在构造函数第一行  

    super(y);

    this.y = y + x;

    System.out.println("这是子类的有参构造");

    }

    4super思考

    如果开发者自定义了一个类,没有显示的进行类的继承,那么该类中成员函数是否可以使用super关健健字?

    可以使用,继承了Object类,Object类是所有类的父类。

    class Demo7 {

    public  void print(){

    System.out.println(super.toString());

    }

    public static void main(String[] args){

    new Demo7().print();

    System.out.println();

          }

    }

    十一、instanceof 关键字

    1:快速演示instanceof

    Person p=new Person();

    System.out.println( p instanceof Person);

    2instanceof是什么?

    1:属于比较运算符:

      2instanceof关键字:该关键字用来判断一个对象是否是指定类的对象。

      3:用法:

           对象  instanceof ;   

       该表达式是一个比较运算符,返回的结果是boolea类型  true|false

    注意:使用instanceof关键字做判断时,两个类之间必须有关系。

    十一、final关键字

    1:定义静态方法求圆的面积

    2:定义静态方法求圆的周长

    3:发现方法中有重复的代码,就是PI,圆周率。

    1:如果需要提高计算精度,就需要修改每个方法中圆周率。

    4:描述一个变量

    1:方法都是静态的,静态只能访问静态,所以变量也定义为静态的。

    public static double PI=3.14;

    1:如果定义为public后,新的问题,类名.PI=300; 改变了PI的值。

    2:修改为private,修改为private后进行了封装,需要getset公共访问方法。

    3:现有的知识不能解决这样的问题了。可以使用final

    5:使用final

    1final关键字主要用于修饰类、类成员、方法、以及方法的形参。

    2final修饰成员属性:

    1:说明该成员属性是常量,不能被修改。

    public static final double PI=3.14;

    1public :访问权限最大

    2static :内存中只有一份

    3final  :是一个常量

    4:常量名大写

    5:必须初赋值。

    2:使用类名.成员。修改该成员的值,报错。--常量不能被修改

    1:基本数据类型,final使值不变

    2:对象引用,final使其引用恒定不变,无法让其指向一个新的对象,但是对象自身却可以被修改。

    3:该关键字一般和static关键字结合使用

    1:常量可以优先加载,不必等到创建对象的时候再初始化。

    4finalstatic可以互换位置

    5:常量一般被修饰为final

    3fianl修饰类:

    1:该类是最终类,不能被继承。

    1:将父类加final修饰,子类继承,就会报错。

    2:查看api文档发现String类是final的。Integer类也是final

    1:为了防止代码功能被重写

    2:该类没有必要进行扩展

    4final修饰方法:

    1:该方法是最终方法,不能被重写

    2:当一个类被继承,那么所有的非私有函数都将被继承,如果函数不想被子类继承并重写可以将该函数final修饰

    3:当一个类中的函数都被修饰为final时,可以将类定义为final的。

    十二、抽象类

    当描述一个类的时候,如果不能确定功能函数如何定义,那么该类就可以定义为抽象类,功能函数应该描述为抽象函数。

    1.抽象类的特点

    1:有抽象函数的类,该类一定是抽象类。

    2:抽象类中不一定要有抽象函数。

    3:抽象类不能使用new创建对象,因为如果使用new创建对象时,需要使用该对象的功能,要使用抽象类的方法,但是抽象类没有方法体。

    4:抽象类主要为了提高代码的复用性,让子类继承来使用。

    5:编译器强制子类实现抽象类父类的未实现的方法。

    1:可以不实现,前提是子类的也要声明为抽象的。

    2抽象的优点

    1:提高代码复用性,强制子类实现父类中没有实现的功能。

    2:提高代码的扩展性,便于后期的代码维护

    3.小问题

    1.抽象类不能创建对象,那么抽象类中是否有构造函数?

    抽象类中一定有构造函数。主要为了初始化抽象类中的属性。通常由子类实现。

    9finalabstract是否可以同时修饰一个类?  

    一定不能同时修饰。

    4抽象类需要注意的细节

    1.抽象类可以没有抽象方法(java.awt.*的类就是这样子操作的)。

    2.抽象类可以继承普通类与抽象类。

    3.抽象类不能直接使用类名创建实例,但是有构造方法,构造方法是让子类进行初始化。

    4.抽象类一定有构造方法。

    5abstract与其他修饰符的关系:

    5.1final与abstract不能共存:

    final:它的作用  修饰类代表不可以继承  修饰方法不可重写

    abstract修饰类就是用来被继承的,修饰方法就是用来被重写的。

    5.2static static修饰的方法可以用类名调用,

     对于abstract修饰的方法没有具体的方法实现,所有不能直接调用,

    也就是说不可以与static共存。

    5.3private

    private修饰的只能在本类中使用,

    abstract方法是用来被子类进行重写的,有矛盾

    所有不能共存.

    十三、接口

    1、接口的作用

    由于一个类只能有一个直接的父类,所以接口可以拓展类的功能。

    接口(interface)usb接口,主要是使用来拓展笔记本的功能,那么在java中的接口主要是使用来拓展定义类的功能,可以弥补java中单继承的缺点。

    1 拓展功能。

    2定义约束规范。

    3程序的解耦。

    2、接口的定义格式

    接口的定义格式: 

    interface 接口名{

    属性

    抽象方法

    }

    接口的体验

    interface Inter

    {

    int num = 6;  可以定义属性与方法。

    void show();

    }

    3、接口的特点

    1类实现接口可以通过implements实现,实现接口的时候必须把接口中的所有方法实现,一个类可以实现多个接口。

    2接口中定义的所有的属性默认是public static final的,即静态常量既然是常量,那么定义的时候必须赋值。

    3接口中定义的方法不能有方法体。接口中定义的方法默认添加public abstract

    4有抽象函数的不一定是抽象类,也可以是接口类。

    5由于接口中的方法默认都是抽象的,所以不能被实例化。

    6对于接口而言,可以使用子类来实现接口中未被实现的功能函数。

    7如果实现类中要访问接口中的成员,不能使用super关键字。因为两者之间没有显示的继承关系,况且接口中的成员成员属性是静态的。可以使用接口名直接访问。

    8接口没有构造方法。

    9接口中的所有属性 默认的修饰符是  public static final

    10接口中的所有方法 默认的修饰符是  public abstract

    11 接口是一个特殊的类,接口的成员变量的默认的修饰符为:public static final 那么也就是说,接口中的成员变量都是常量。

    12 接口中的方法都是抽象的方法,默认的修饰符为:public abstract

    13 接口不能创建对象。

    4、接口与类,接口之间的关系:实现关系

    1. 大家之前都知道类与类之间的关系继承,那么接口与类之间又是怎样子的关系呢?接口与类之间是实现关系。非抽象类实现接口时,必须把接口里面的所有方法实现。类实现接口用关键字implments,类与接口之间是可以多实现的(即一个类可以实现多个接口)

    2. 接口与接口之间的关系式继承

    5、类与接口需要注意的事项:

    1. 非抽象类实现一个接口时,必须要把接口中所有方法全部实现。

    2. 抽象类实现一个接口时,可以实现也可以不实现接口中的 方法。

    3. 一个类可以实现多个接口 。

    十四、多态

    多态就是一个对象具备多种形态。即,父类的引用类型变量指向了子类的对象或者是接口的引用类型变量指向了接口实现类的对象,所以,多态的前提是必须存在继承或者实现关系。

    多态的另一种定义:指允许不通类型的对象对同一消息做出响应。即同一消息可以根据发送对象的不通而采取多种不同的行为方式,(发送消息就是函数调用)

    1多态的三个必要条件

    一、要有继承;

    二、要有重写;

    三、父类引用指向子类对象。

    Java中多态性的实现

    2多态概述

    1. 面向对象的三大特性:封装、继承、多态。从一定角度来看,封装和继承几乎都是为多态而准备的。这是我们最后一个概念,也是最重要的知识点。
    2. 多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
    3. 实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。
    4. 多态的作用:消除类型之间的耦合关系
    5. 现实中,关于多态的例子不胜枚举。比方说按下 F1 键这个动作,如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;如果当前在 Word 下弹出的就是 Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。

    下面是多态存在的三个必要条件,要求大家做梦时都能背出来!

    多态存在的三个必要条件
    一、要有继承;
    二、要有重写;
    三、父类引用指向子类对象。

    3多态的好处

    1.可替换性substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
    2.可扩充性extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
    3.接口性interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如图8.3 所示。图中超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如CircleSphere为了实现多态,完善或者覆盖这两个接口方法。
    4.灵活性flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
    5.简化性simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
    Java中多态的实现方式:接口实现,继承父类进行方法重写,同一个类中进行方法重载。

     

    4多态需要注意的细节

    1.  多态情况下,子父类存在同名的成员变量时,访问的是父类的成员变量。

    2.  多态情况下,子父类存在同名的非静态的成员函数时,访问的是子类的成员函数。

    3.  多态情况下,子父类存在同名的静态的成员函数时,访问的是父类的成员函数。

    4.  多态情况下,不能访问子类特有的成员。

    总结:多态情况下,子父类存在同名的成员时,访问的都是父类的成员,除了在同名非静态函数时才是访问子类的。

    编译看左边,运行不一定看右边。

    编译看左边:java编译器在编译的时候,会检查引用类型变量所属的类是否具备指定的成员,如果不具备马上编译报错。

  • 相关阅读:
    Oracle expdp 多表导出处理
    字符串
    Java设计模式
    多线程
    Java面向对象练习
    Java面向对象基础
    Java基础算法
    Java常识
    DOS基础命令(1)
    Java基础练习
  • 原文地址:https://www.cnblogs.com/xiangnianchulian/p/7265671.html
Copyright © 2011-2022 走看看