面向对象第五天

---------------------- android培训java培训、期待与您交流! ----------------------

  (一)  概述

面对对象概念:

面向对象是相对面向过程而言,面向对象和面向过程都是一种思想,面向过程强调的是功能行为,面向对象是将功能封装进对象,强调具备了功能的对象。面向对象是基于面向过程的。

面对对象特点:
将复杂的事情简单化 ,将程序员从执行者转换成了指挥者.

完成需求时
1.先要去找具有所需的功能的对象来用。
2.如果该对象不存在,那么创建一个具有所需功能的对象。
3.这样简化开发并提高复用。


  (二)  举例

比如某天接到个项目要开发,我雇了几个人帮我开发,我就成了指挥者,被雇的人就成了对象.又比如餐厅点菜,服务员是对象.

面对对象的开发特点:

开发的过程:其实就是不断的创建对象,使用对象,指挥对象做事情.以后开发首先考虑的就是对象,没有对象就创建对象.
设计的过程:其实就是在管理和维护对象之间的关系。


   (三)  类与对象的关系

面向对象的三个特征:

封装,继承,多态.

类是对现实事物抽象的描述,对象是事物的具体个体.描述事物就是在描述事物的属性和行为.

举例:

1.

//需求:描述汽车(颜色,轮胎数).

//属性对应类中的变量,行为类中的函数(方法).定义类其实就是在定义类中属性和行为,属性和行为称为类中的成员,即成员变量和成员函数.

class Car

{

    //描述颜色

    string color="红色";

    //描述轮胎数

    int num =4;

    //运行行为

    void run()

    {

        System.out.println(color+".."+mun);

    }

}

2.

class CarDemo

{

    public ststic void main(String[] args)

    {

        //生产汽车,在java中通过new操作符来完成.

        //其实就是在堆内存中产生一个实体,这个实体就是一个对象.

        Car c=new Car () ; //c是一个类类型变量,这个类型指向它所产生的实体.

        //需求:将已有的车颜色改为蓝色,需要指挥该对象做事情,在java中的指挥方式是:对象. 对象成员

        c.color="blue";//改变c这辆车的颜色.

        c.run();//运行c这辆车.

        Car c1=new Car();//再新建一辆车,还是红色,四个轮胎数.

        c1.run();//运行c1这辆车.

    }

}

注意:堆内存中的变量都有一个默认初始化值,字符串类型的默认初始化值是null,数值类型是0.

3.对象在内存中的情况举例:

Car c=new Car();//在栈内存中创建一个c,堆内存中创建一个Car实体,c指向这个Car.这叫多个引用指向同一个对象.

c.num=5;//堆内存中的num属性改为5.

Car c1=c;//栈内存中再创建一个c1,把c指向的地址值赋给c1.也就是说c和c1共同指向同一个堆内存中实体.

c1.color="green";//所以改动c1,也就改动了c.

c.run();//结果是绿色,5个轮胎数.

总结:对象中封装了属性和行为,想要操作对象,要明确操作那个对象和对象的哪个属性.


   (四)成员变量和局部变量

定义类的时候没有写主函数,主函数是用来确保函数独立运行,如果类只是用来描述,则不需要写主函数.

成员变量:
1.定义在类中,作用于整个类中.
2.随着对象的建立而建立,存在于对象所在的堆内存中。
3.有默认初始化值。
 
局部变量:
1.只定义在局部范围内,作用于函数中或语句中,如:以前定义在函数中的变量.
2.存在于栈内存中。
3.作用的范围结束,变量空间会自动释放。
4.没有默认初始化值。只有定义了初始化值才能参与运算.


小结:什么时候需要定义成员变量呢?当类里面有多个函数需要共用同一变量的时候,就把这个变量定义为成员变量.


  (五)匿名对象的应用

举例:

class Demo

{

    public ststic void main(String[] args)

    {

       Car c=new Car();

       c.num=5;

     }

}

在修改对象属性值的时候可以省略对象名,写成:

class CarDemo

{

    public ststic void main(String[] args)

    {      

        new Car().num=5;//在堆内存中产生一个新对象,把num属性改为5,注意用匿名对象的时候栈内存中是不会产生东西的.

        new Car().color="blue";//在堆内存再产生一个新对象,把color改为blue,注意是重新产生的对象.

        new Car().run();//再产生一个新对象,运行,结果是red和4,因为是新产生的对象,属性值没变.

     }

}

注意匿名对象调用方法才有意义,调用属性没有意义.所以前面两句改变属性的命令是垃圾.

匿名对象的使用方式:

1.当对象的方法只调用一次的时候,可以用匿名对象,简化形式.但如果要对多个成员调用,就必须给对象起个名字.

2.可以将对象作为实际参数进行传递.

举例:

//需求:汽车修配厂,对汽车进行改装,将来的车改成黑色,三轮.

class Car

{

    string color="红色";

    int num =4;

    void run()

    {

        System.out.println(color+".."+mun);

    }   

}

    main()

    {

        Car c=new Car();//在堆内存中新建一个对象,在栈内存中命名为c指向这个对象.

        show(c);//这里的c是上面命名的那个c,把c赋给了函数show.所以num变为3color变为blcak.

    }

    public static void show(Car c)//在栈内存中定义一个show的函数.

    {

        c.num=3;

        c.color="black";

        c.run();

    }

如果用匿名对象,上面的main函数可以写成:

main

{

    show(new Car());//在堆内存中新建了一个对象,其属性的初始化值是red和4,然后在栈内存中定义了一个show函数,并把show函数中的c指向new Car().

}

注意:上面当main执行完之后,show函数会自动释放,此时new Car没有show的指向,堆内存中的new Car就成了垃圾.


  (六)封装的概述

封装:Encapsulation,隐藏对象的属性和实现细节,仅对外提供公共访问方式。

封装的好处:
1.将变化隔离。
2.便于使用。
3.提高重用性。
4.提高安全性。

封装原则:
1.将不需要对外提供的内容都隐藏起来。
2.把属性都隐藏,提供公共方法对其访问。


  (七)封装Private

class Person
{
    private int age;//private私有,权限修饰符,用于修饰类中的成员(成员变量,成员函数).私有只在本类中有效.

    public void setAge(int a)//在实际开发中属性可能会私有化,这时对于这些属性,所采用的方法无非就是设置和获取,也就是set和get.

    {

         if(a>0&&a<130)

         {

              age=a;

              speak();

          }

         else

                System.out.println("non");

    }

    public int getAge()

    {

            return age;

     }

    void speak()
    {
        System.out.println("age="+age);
    }
}
class PersonDemo
{
    public static void main(String[] args)
    {
        Person p=new Person();
        p.setAge=(20);
        p.speak();
    }
}

注意:封装不等于私有,私有仅仅是封装的一种表现形式.之所以停供访问方式,因为可以在方式中加入逻辑,判断等语句对被访问数据进行操作,提高代码健壮性.隐藏的最低权限是Private.set的返回值类型一般都是void,因为只是设置,不需要返回值.get一般没有参数,只是获取.


  (八)构造函数

特点:

1.  函数名与类名相同
2.  不用定义返回值类型
3.  不可以写return 语句

举例:

class Person
{
    Person()//这个就是构造函数,函数名和类名相同,没有返回值类型.
    {
        System.out.println("person run");
    }
}
class PersonDemo
{
    public static void main(String[] args)
    {
        Person p=new Person();//对象只要建立,就可以调用与之对应的构造函数,不需要再写p.Person();
        new Person();//匿名对象
    }
}

作用:

用于给指定对象进行初始化.比如某些一出现就具备某些行为的事物.

注意:

当类中没有定义构造函数时,那么系统会默认给该类加一个不含参数的构造函数.Person(){},因为构造函数是对象的基本,没有构造函数就没有对象,但当自定义了构造函数之后,默认的就消失了.


小细节:构造函数可以重载

例如:

class Person
{
    private String name;//String就是字符串类型.
    private int age;
    Person()//初始化三个不同类型的人,有的有名字和年龄,有的没有.
    {
        System.out.println("A:name="+name+",age="+age);
    }
    Person(String n)//构造函数支持重载,函数名相同,参数不同.
    {
        name=n;
        System.out.println("B:name="+name+",age="+age);
    }
    Person(String n,int a)
    {
        name=n;
        age=a;
        System.out.println("C:name="+name+",age="+age);
    }
}
class PersonDemo
{
    public static void main(String[] args)
    {
        Person p1=new Person();
        Person p2=new Person("lisi");
        Person p3=new Person("wangwu",10);
    }
}

注意:考察对系统有默认的初始化构造函数理解,比如:

假如把上面的

Person()
    {
        System.out.println("A:name="+name+",age="+age);
    }

注释掉,

再问下面主函数的结果,会报错说找不到初始化值,因为注释掉以后,类中还有其他已经定义了的构造函数,系统就不会自己创建默认的初始化构造函数,所以Person p1=new Person()这个对象就没有对应的构造函数,也就是没有对应的初始化值.


小细节:构造函数是可以被私有化的,私有化可以修饰成员变量和成员函数,构造函数也是成员函数,但是当构造函数被私有之后,外部的程序,比如在其他类里面创建对象进行调用的时候,这个被私有化的构造函数就不能创建对应的对象.

例如:

class Person
{
    private Person(String x){}
}
class PersonDemo
{
    public static void main(String[] args)
    {
        Person name=new Person("张三");
    }    
}

报错的原因是Person(String x)已经私有化了,下面的name对象不能访问这个被私有化的构造函数.


构造函数和一般函数的区别:

1.和一般函数写法不同

2.构造函数在对象一建立就运行,是给对象初始化.

3.一般方法是对象调用才执行,是给对象添加对象具备的功能.

4.一个对象建立,构造函数只运行一次.而一般方法可以被该对象调用多次.


setget(设置和获取)的举例:

class Person
{
    private String name;//定义成员变量name的原因是下面多个构造函数都会用到,私有化因为不会被对象直接调用.
    private int age;
    Person()
    {
        System.out.println("A:name="+name+","+"age="+age);//输出某个对象的name和age值.
        cry();
    }
    Person(String n)
    {
        name=n;//对象建立之后,对象中的值传给n,n赋值给name.
        System.out.println("B:name="+name+","+"age="+age);
        cry();
    }
    Person(String n,int a)
    {
        name=n;
        age=a;
        System.out.println("C:name="+name+","+"age="+age);
        cry();
    }
    public String getName()//获取某个对象的name值.
    {
        return name;
    }
    public int getAge()//获取对象的age值
    {
        return age;
    }
    public void setNameAge(String n,int a)//没有具体的返回值,没有return,所以返回值类型是void.
    {        
        name=n;//更改某个对象的name值,而不用对象直接访问name这个成员变量,为了name的安全性,上面的输出name同理.
        age=a;
    }
    public void cry()
    {
        System.out.println("cry...");
    }
}
class PersonDemo
{
    public static void main(String[] args)
    {
        Person p1=new Person();
        p1.cry();//这就是一般函数的好处,在初始化中只哭了一次,如果还想哭,则可以再继续调用一般函数,可以多次调用.
        Person p2=new Person("张三");
        Person p3=new Person("李四",20);
        p1.setNameAge("王五",10);//把p1改名为王五,年龄改为10
        System.out.println("A:name="+p1.getName()+","+"age="+p1.getAge());//打印验证p1的name和age是否改过来了
    }
}


注意:对于构造函数在对象建立的时候只运行一次的理解:

Person p1=new Person();如果我还想让Person()这个构造函数再运行一次,不能在下面直接加Person p1=new Person(),这样是又创建了一个名为p1的对象,而应该把这个构造函数里面的参数在单独写一个一般函数,比如上面的cry(),这样,对象就可以多次调用了.构造函数是给对象一开始就赋予某些特性,而一般函数是对象的其他特性,方便对象多次调用.



小结:什么时候定义构造函数:

当分析事物时,该事物存在具备一些特性或者行为,那么将这些特性定义在构造函数中.如果事物有一开始就具有特殊的属性,比如人有年龄名字等属性,这些属性就定义为成员变量,写在构造函数中.并私有化防止对象直接访问,但加不加静态得看是否需要类直接调用,或者有没有其他静态方法来调用.


  (九)构造代码块

举例:

class Person
{
    private String name;
    private int age;
    Person()
    {
        System.out.println("A:name="+name+","+"age="+age);
    }
    {
        cry();//这个就是构造代码块,没有名字,只有中括号和里面的语句.
    }
    Person(String n)
    {
        name=n;
        System.out.println("B:name="+name+","+"age="+age);
    }
    Person(String n,int a)
    {
        name=n;
        age=a;
        System.out.println("C:name="+name+","+"age="+age);
    }
    public void cry()
    {
        System.out.println("cry...");
    }
}
class PersonDemo
{
    public static void main(String[] args)
    {
        Person p1=new Person();
        p1.cry();
        Person p2=new Person("张三");
        Person p3=new Person("李四",20);
    }
}

结果为:

cry...
A:name=null,age=0
cry...
cry...
B:name=张三,age=0
cry...
C:name=李四,age=20


小结:构造函数代码块和构造函数的区别,以及构造代码块的特点:

构造函数代码块是给所有对象统一进行初始化,并且优先于构造函数执行,所以结果里面每一个对象的前面都有一个cry...,

构造函数是给对应的对象进行初始化.构造函数代码块用于定义每个对象的共性初始化值,所以上面代码的cry()是属于每个对象都要执行的行为,所以就写在构造函数代码块里面了.但是要注意构造函数代码块是优先于构造函数执行的,这些代码块执行完后会出现在每个构造函数的前面,注意代码块执行完后出现的位置.

 

  (十)this关键字

当局部变量和成员变量名字相同时,对象会调用局部变量,而不会找成员变量.

举例:

class Person
{
    private String name;
    private int age;
    Person(){}//注意这里这个空参数的是不能省略的,道理就是之前讲的如果自定义了构造函数,系统不会默认指定空参数的构造函数.
    Person(String n)
    {
        name=n;
    }
    Person(String n,int a)
    {
        name=n;
        age=a;
    }
    public void speak()
    {
        System.out.println("name:"+name+","+"age:"+age);
    }
}
class PersonDemo
{
    public static void main(String[] args)
    {
        Person p1=new Person();
        Person p2=new Person("张三");
        p1.speak();
        p2.speak();
    }
}

假如把

Person(String n)
    {
        name=n;
    }

里面的n改成name,改的原因是为了直观,提高阅读性,好清楚到底对象要往这个构造函数里面传一个什么值.

Person(String name)
    {
        name=name;
    }

此时的结果会显示
name:null,age:0

name不是对象传了个"张三"进去,怎么会显示null,原因就是,这里的成员变量和局部变量同名了,到底对象传的值要传给哪个name呢,哪个name是成员变量,哪个是局部变量,系统默认假如在函数里面的两个变量同名,那这两个都是局部变量,也就是说两个name都是一样,假如不同名,才会去成员变量中找.

要解决这个同名的问题,需要在成员变量的前面加一个关键字this声明,那么就应该这样写:

Person(String name)
    {
        this.name=name;
    }

小结:this代表其所在函数所属对象的引用.换句话说,this就代表正在调用这个函数的对象名.

举例:

class Person
{
    private String name;
    private int age;
    Person(String name)
    {
        this.name=name;//谁的对象在调用这个函数,this就代表那个对象的引用,比如p1是new Person("张三");这个对象的引用,如果p1在调用这个函数,那么this就代表p1.

    }
    public void speak()
    {
        System.out.println("name:"+name+","+"age:"+age);
    }
}
class PersonDemo
{
    public static void main(String[] args)
    {
        Person p1=new Person("张三");
        Person p2=new Person("李四");
        p1.speak();
        p2.speak();
    }
}

结果是

name:张三,age:0
name:李四,age:0

分析原因:p1把"张三"传给了Person(String name)里面没加this的那个name,这个name再赋值给了加了this的name,此时p1的name属性就有了值为"张三",所以p1在speak()的时候就是张三,age没传值进去,初始化是0,然后p2传了"李四"给局部变量name,再赋值给成员变量name,p2的name属性就是"李四",所以说this就代表所在函数所属对象的引用.当然在描述的时候给speak ()里面的name和age加上this声明更好,就写成 System.out.println("name:"+this.name+","+"age:"+this.age);同样在调用其他方法的时候,为了更加明确,也可以加上this,但是最好省略,因为没必要加,但是变量同名,就必须加了,不然计算机不能分辨哪个是哪个,比如

public void speak()

{

    System.out.println("name:"+this.name+","+"age:"+this.age);

    this.show();//this加了更加明确,但最好省略

}

public void show()

{

    System.out.println(this.name);

}


注意:不管是对象还是其他什么,只要是在调用函数的时候,括号里面参数一定要和被调用函数定义的参数一致,如果是空参数,那么主动调用的那个括号里面也是空的,如果被调用的函数定义了参数类型,那么主动调用的那个括号里面也必须符合这个类型.在对象调用类里面函数的时候要尤其注意.


  (十一)this关键字的应用

/*
需求:给人定义一个用于比较年龄是否相同的功能.也就是是否是同龄人.
*/
class Person
{
    private int age;
    Person(int age)
    {
        this.age=age;
    }
    public boolean compare(Person p)//Person类型.
    {
        return this.age==p.age;//this代表p1,p代表p2.
    }
}
class PersonDemo
{
    public static void main(String[] args)
    {
        Person p1=new Person(20);
        Person p2=new Person(25);
        System.out.println(p1.compare(p2));
    }

}

小结:当定义类中功能时,该函数内部要用到调用该函数的对象时,这时用this来表示这个对象.比如下面compare这个函数要调用p1和p2这两个对象,一个就用this来声明,一个就用p这个变量来声明,但凡本类功能内部使用到了本类对象,都用this 表示.


  (十二)this关键字在构造函数间调用

举例:

class Person
{
    private int age;
    private String name;
    Person(int age)
    {
        this.age=age;
    }
    Person(String name,int age)
    {
        this.age=age;
        this.name=name;
    }
    public int getAge()
    {
        return age;
    }
}
class PersonDemo
{
    public static void main(String[] args)
    {
        Person p1=new Person("李四",20);
        System.out.println(p1.getAge());
    }
}

上面的两个构造函数中都有this.age=age这个操作,重复了,所以可以在下面的构造函数里面调用上面写好的this.age=age,

class Person
{
    private int age;
    private String name;
    Person(int age)
    {
        this.age=age;
    }
    Person(String name,int age)
    {
        this(age);//这里的this指p1这个对象.
        this.name=name;
    }
}

class PersonDemo
{
    public static void main(String[] args)
    {
        Person p1=new Person("李四",20);
        System.out.println(p1.getAge());
    }
}

传递分析:Person p1=new Person("李四",20);里面的20先传给age,再给age,再给age,再给age,再给age,这才传到p1的age属性里面.需要注意的就是这个this语句必须写在第一行,另外括号里面必须和要引用的哪个构造函数里面的参数要类型一致.比如这个age和这个age类型一致,也就是之前说到的调用函数要保证参数类型一致.

比如:

Person()
    {
        this("李四");
    }
    Person(String name)
    {
        this();
    }

this() 再调用Person(),this("李四")又在调用Person(String name),这是个死循环.


小结:this语句用于构造函数间函数互相调用,是不能用于一般函数的,只能用于构造函数之间的调用.this语句只能定义在构造函数的第一行.因为如果初始化函数里面还有初始化,那就要先执行里面的那个初始化.java的this关键字只能用于方法的方法体内,当对象创建以后,jvm就会给这个对象分配一个引用自身的指针,这个指针就是this,也就是说this指针是在创建对象之后产生的.所以this只能在类的非静态方法中使用,静态方法和静态代码块中绝对不能出现this.并且this只和特定对象关联,不和类关联,同一个类不同对象有不同的this.


---------------------- android培训java培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net/heima

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值