黑马程序员_04_面向对象

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ---------------------- 
1.理解面向对象:
面向对象是相对面向过程而言;
面向对象和面向过程都是一种思想;
面向过程强调的是功能行为;
面向对象是将功能封装进对象,强调具备了功能的对象;
面向对象是基于面向过程的。
以冰箱为例:
面向过程:打开冰箱,存储进冰箱,关闭冰箱。
面向对象:冰箱.打开,冰箱.存储,冰箱.关闭。

2.面向对象的特点:
是一种符合人们思考习惯的思想;
可以将负责的事情简单化;
将程序员从执行者转换成了指挥者;
完成需求时:先去找具有所需的功能的对象来用。如果该对象不存在,那么创建一个具有所需功能的对象。这样可以简化开发并提高复用性。

面向对象的三个特征:封装,继承,多态。以后开发其实就是找对象使用,没有对象就新建一个对象。找对象,建立对象,使用对象,维护对象的关系。

3.类和对象的关系

类的定义:

类(Class)实际上是对某种类型的对象定义变量和方法的原型。它表示对现实生活中一类具有共同特征的事物的抽象。

使用计算机语言就是不断的描述现实生活中的事物。Java中描述事物通过类的形式出现,类是具体事物的抽象,概念上的定义。

类与对象的关系

类就是:对现实生活中事物的描述。——>如上面的图纸

对象:就是这类事物,实实在在存在个体。——>如上面的个体,汽车。

老师举例

现实生活中的对象:张三 李四。(其实万物皆对象)

想要描述:提取对象中共性内容。对具体的抽象。

描述时:这些对象的共性有:姓名,年龄,性别,学习java功能。

定义类,就是在定义属性和行为,就是在描述事物,属性和行为共同成为类中的成员属性:对应类中成员变量

行为:对应类中成员方法

代码演示

class Car//描述汽车这个类,代表汽车这个整体事物的抽象。

{

      //描述颜色

      Stringcolor = "红色";//汽车的属性,颜色为红色

      //描述轮胎数

      intnum = 4;//汽车的属性,每个汽车都有4个轮胎

 

      //运行行为。

      voidrun()//成员方法,描述类:汽车的某种行为

      {

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

      }   

}

成员变量:

1、        成员变量定义在类中,整个类都可以被访问。

2、        成员变量随着对象的建立而建立。存在于对象所存在的堆内存中。

3、        成员变量有默认初始化值。

局部变量:

1、        局部变量之定义在局部内,如函数内,语句内。

2、        局部变量存在于栈内存中。

3、        局部变量作用范围结束,变量的空间会自动释放。

4、        局部变量没有默认初始化值。

在java中创建类类型函数的格式是

类名.对象名 = new 类名(); 

示例:Car c = newCar();

使用对象及其成员是方法格式是:

对象.对象成员  (或对象方法)

示例:  c.color = "blue";     

      c.run();

Car c1 = new car();

C1是一个类类型变量,属于引用型变量,是一个类类型变量,类类型变量都指向对象

匿名对象

匿名对象是对对象的简化形式。

匿名对象的两种使用情况

1、        当对象方法仅使用一次的时候。

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

示例:System.out.println(newCar().num);

如果对一个对象进行多个成员调用,必须给这个对象起个名字。匿名对象是一种建立对象的简化形式,简化的有自身的局限性

New car().num=5;

New car().color=”blue”;

New car().run();

匿名函数调用成员变量没意义,每次使用都会在堆内存新建一个New car()对象。如果对一个对象进行多个成员调用,必须给这个对象起个名字。

 

 

代码演示

class Car

{

      Stringcolor = "红色";

int num = 4;// 成员变量定义在类中,整个类都可以被访问。

      voidrun()

      {

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

      }

     

}

class CarDemo

{

      publicstatic void main(String[] args)

      {

           Carc = new Car();//建立一个c的类类型变量,当c作为对象建立时,c的颜色和轮胎数有了默认初始化的值,这两个成员变量随着c对象的建立,在堆内存中一起建立。

           c.color= "blue";//将对象c中成员变量color变为blue。这是在堆内存中改变的。

           c.run();//运行c的run函数,这是输出的color是blue和4

           Carc1 = new Car();//建立c1类类型变量,栈内存中有个c1,但是堆内存有new Car(),已经初始的Car内部的成员变量,c1指向new Car()的地址。示例图2.

           c1.run();//输出的是red..4

            c.num = 5;

           Carc1=c;

           c1.color = green;

           c.run();//这个是出的是green和5,因为c的num是5,而c1指向了c的地址,c1的color改变成green的时候,也就是改变c的color,这样输出c.run()就是green和5。示例图3

           /*

new Car().num = 5;//对匿名对象的成员变量赋值,为5。

new Car().color = "blue";//对匿名函数的成员变量赋值,blue

            new Car().run();//运行匿名函数的成员函数,输出为红色和4.虽然有前面两条指令,但是匿名函数使用即为垃圾,第三条指令运行的仍然是堆内存中Car的初始成员变量值。不会因为上面两条指令而更改。上面两条指令会各自在堆内存中建立匿名函数。用完后会在某个时间段由java虚拟机自动垃圾回收器来管理。

//基本上可以总结为,匿名对象调用属性基本没有什么意义,调用方法有意义。

Car c = new Car();

c.run();

c.num = 4;

new Car().run();

如果对一个对象进行多个成员调用,必须给这个对象起个名字。

           */

//需求:汽车修配厂。对汽车进行改装,将来的车够改成黑车,三个轮胎。

           Carq = new Car();//建立q类类型变量,栈内存中有个q,但是堆内存有new Car(),已经初始的Car内部的成员变量,q指向new Car()的地址。

           show(q);//局部变量没有默认初始化值,当作用范围结束,局部变量在栈内存中的的空间会自动释放。

          //上面的两条指令用匿名函数表示即为 show(new Car());因为没有对象,new Car()所以只在堆内存中存在,当要调用show()函数时,show中的返回对象c指向了new Car()的内存地址。而且使用完以后show在栈内存中的空间随即被释放示例图4

}

      publicstatic void show(Car c)//建立一个局部函数,show,返回值为汽车类型,因为这个函数的作用就是对汽车进行改装,对象是车。所以show()后面括号内部的为Car c

//若这个c改为q,那么q与上面那条指令中的q是不是同一个呢?答案是不是,

//show(Car c),当q调用此函数时,c对象在堆内存中的地址赋予了q,不论字母是否相同,两者都是两个对象。见示例图5,(重点掌握)

      {

           c.num= 3;//这个局部变量存在于成员函数show中,存在于栈内存中

           c.color= "black";//存在于栈内存中

           c.run();//局部成员函数调用成员函数。

      }

}

 


思维扩展:

数据类型分为两种,基本数据类型和引用数据类型。

8种基本数据类型

byte char short int long float doubleBoolean

3种引用数据类型

类,数组,接口

栈内存与堆内存:

http://www.cnblogs.com/whgw/archive/2011/09/29/2194997.html

简单的可以理解为:

Java把内存分成两种,一种叫做栈内存,一种叫做堆内存

 

在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。栈内存的优点是寄存速度快、、栈数据可以共享、缺点是数据固定、不够灵活。

堆内存用于存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的引用变量,以后就可以在程序中使用栈内存中的引用变量来访问堆中的数组或者对象,引用变量相当于为数组或者对象起的一个别名,或者代号。

堆内存存放的有:String、基本数据类型、对象引用等

栈内存存放的有:基本类型的变量和对象的引用变量等

3.3 对象的封装

封装的定义:(Encapsulation)

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

好处:

1、        将变化隔离

2、        便于使用。

3、        提高重用性

4、        提高安全性

封装原则:

·将不需要对外提供的内容都隐藏起来。

·把属性都隐藏,提供公共方法对其访问。

Private关键字:

?是一个权限修饰符

?用于修饰成员(成员变量和成员函数)

?被私有的成员只在本类中有效

常用于:

?将成员变量私有化,对外提供对应的set,get方法对其进行访问,提高对数据的访问安全性。如set一个成员变量时,可以限制设置这个变量的条件

注意:封装不是私有,私有仅仅是封装的一种表现形式。不能用于修饰类。修饰类只有两种public和default(默认)(其他类型的关键字如static也可以修饰)

代码演示

class Person

{

      privateint age;//private修饰成员变量age,私有化age,只有Person类中的对象可以调用,类以外即使建立了对象也不能直接访问。

      publicvoid setAge(int a)//建立成员函数setAge用来在Person内部设置age值,使用public修饰,对外提供这个方法便于外界使用。上面两条指令符合封装原则2:把属性都隐藏,提供公共方法对其访问。

      //凡是set开头的函数,返回值一般都是void,因为设置函数,返回值不确定

      {    //之所以对外提供访问方式,就因为可以在访问方式中加入逻辑判断等语句。对访问的数据进行操作。提高代码健壮性。

           if(a>0&& a<130)//如果输入的年龄不是在正常范围,内部就进行判断,只对外部提供饭饭,这样封装可以将变化隔离,便于使用。并且提高代码健壮性。

           {

                 age= a;//内部直接调用了age,不需要外界调用,所以age私有化

                 speak();//内部之间调用了speak(),不需要外界调用,所以私有化speak()

           }

           else

                 System.out.println("feifaage");//输出feifa age

      }

 

      publicint getAge()//建立成员函数getAge用来在获取Person内部的age值,使用public修饰,对外提供这个方法便于外界使用。一般被私有的成员变量对应两个函数,set和get

      {

           returnage;//这个函数很重要,获取一个变量的值就用这个return!

      }

      privatevoid speak()//private修饰成员函数speak(),因为这个函数不会被外部调用,在if语句内部就调用了,所以用private修饰,符合封装原则1:将不需要对外提供的内容都隐藏起来。

      {

           System.out.println("age="+age);//输出年龄和变量值

      }

}

 

class PersonDemo

{

      publicstatic void  main(String[] args)

      {

           Personp = new Person();//建立对象p,指向new Person()函数

           p.setAge(40);//通过p使用setAge函数,将age值设置为40,并执行setAge函数,具体在内存中的流程参阅示例图6

           //p.speak();通过p执行Person内部的speak()函数,执行失败,因为speak()已经被private修饰,不能被外界所调用。

      }

}

 

示例图6

注意:setAge中的a不是对象,是一个局部的变量,setAge(40)执行时,a为40了,这样把堆内存中的new Person()中的age值改为了40,a指向的其实是new Person()中的age值。p是对象,他的地址指向new Person()。

3.4构造函数

特点:

1、        函数名与类名相同。

2、        不用定义返回值类型。(不是不用写void这句话,而是不用定义返回值。)

3、        不可以写return语句。(不需要返回值,就不需要return语句)

作用:

给对象进行初始化。                          

注意:                                                     

1.构造函数的特点                                             

2.对象一建立就会调用与之对应的构造函数。

3. 当一个类中没有定义构造函数时,那么系统会默认给该类加入一个空参数的构造函数。(方便该函数的初始化,为什么要初始化?)

4. 当在类中自定义了构造函数后,默认的构造函数就没有了。

5.就多个构造函数是以重载的形式存在的。(初始化方式不一样的时候,就构造不同的构造函数,方便初始化)

6.构造函数属于成员函数,也可以被私有化,但是私有化以后就不能创建对象了,因为对象不能进行初始化动作。

7构造函数之间只能用this语句调用

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

首先在写法上有不同,在运行上也有不同:

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

而一般方法是对象调用才执行,给是对象添加对象具备的功能。(对象调用才会使用一般方法)

其次是一个对象建立,构造函数只运行一次。

而一般方法可以被该对象调用多次。

什么时候定义构造函数?

当分析事物时,该事物存在具备一些特性或者行为,那么将这些内容定义在构造函数中。(如定义一个人,刚刚出生时有名字和年龄,这样初始化名字和年龄)

构造代码块:

作用:给对象进行初始化。

对象一建立就运行,而且优先于构造函数执行。

构造代码块和构造函数的区别:

构造代码块是给所有对象进行统一初始化,

而构造函数是给对应的对象初始化。

构造代码快中定义的是不同对象共有特性的初始化内容。

演示代码:

class Person//定义一个Person的类

{

      privateString name;//类的名字不想被外界使用,用private修饰私有化,只让内部使用

      privateint age;//同上。

{

           cry();//构造代码块,定义了所有对象的共性的初始化内容,就是都会执行cry()这个函数。每个对象建立,都会执行,优先于构造函数执行。

      }

      {

           //System.out.println("personcode run");

           cry();

      }

      Person()//构造函数,与类名相同,对象一建立就调用Person()内部的指令。如果没有构造函数,系统会默认自动构造一个空的构造函数

      {

      }

      Person(Stringn)//第二个构造函数,当有字符串的对象建立时,执行此构造函数进行初始化。

      {

           name= n;//被函数中定义了name,即有名字的对象建立时,执行此构造函数进行初始化。

           System.out.println("B:name="+name);

           //输出名字和年龄

           //cry();

          

      }

      /*

      publicvoid setName(String n)//非构造函数,有返回值void。用public修饰,方便外界调用

      {

           name  = n;

      }

      publicString getName()//一般函数,用public修饰,方便外界调用

      {

           returnname; //非构造函数,有返回语句return

      }

      */

      Person(Stringn,int a) //第三个构造函数,当有字符串和数值的对象建立时,执行此构造函数进行初始化。只有这三个构造函数的话,意思就是对象建立,要么为空,要么有名字,要么有名字年龄,不可能出现别的类型构造函数,如果有别的类型的函数对象建立,会提示错误。

      {

           name= n;

             age = a; //被函数中定义了name,age即有名字和年龄的对象建立时,执行此构造函数进行初始化。

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

           //cry();

      }

 

      publicvoid cry()//一般函数

      {         

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

      }

}

class PersonDemo2

{

      publicstatic void main(String[] args)

      {

           Personp1 = new Person();//p1对象建立,此时会调用Person(),p对象也被初始化。

           Personp2 = new Person("lisi");//p2对象建立,此时会调用Person(String n),p2对象也被初始化并且name值为lisi

           //p2.setName(wangrui);//构造函数例如上面的的指令,只能执行一次,而一般函数(譬如setName可以执行多次)

// p2.setName(zhangsan);//这样改名字的话,通过建立一个对象,执行setName就可以改名字了。

           //System.out.println(p2.getName());输出名字

           Personp3 = new Person("wnagu",10);// p3对象建立,此时会调用Person(String n),p2对象也被初始化并且name为wangwu,age为10。

           //注意,当面没有与之对应的构造函数时,会提示找不到函数的。

      }

}

3.5    This关键字

特点:this代表其所在函数所属对象的引用

换言之:this代表本类对象的引用。简单说:哪个对象在调用this所在的函数,this就代表哪个对象。

什么时候使用this关键字?

当在函数内需要用到调用该函数的对象时,就用this。

当定义类中功能时,该函数内部要用到调用该函数的对象时,这时用this来表示这个对象。但凡本类功能内部使用了了本类对象,都用this表示。

代码演示:

class Person

{

      privateString name;

      privateint age;

      Person(intage)//构造函数,局部变量age

      {

           this.age= age;// this代表本类对象的引用,就是Person的引用。

      }

      Person(Stringname)//第二个构造函数

      {

           this.name= name;//这个局部变量可以用别的命名,但是可读性不强,所以this.name,this可以解决这个问题。

      }

      Person(Stringname,int age)//第三个构造函数

      {

           this.name= name;

           this.age= age;

      }

 

      public void speak()

      {

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

//输出的时候其实前面都有this.的,只不过可以省略。这样输出的都是自己对象里面的name和age值,不会和成员变量混淆。

           this.show();//这个show也是调用的本类的show函数,前面有个this.

      }

      public void show()

      {

           System.out.println(this.name);

      }

 

      /*

      需求:给人定义一个用于比较年龄是否相同的功能。也就是是否是同龄人。

      */

    publicboolean compare(Person p)

      {

           returnthis.age==p.age;

           //返回布尔型的时候,最简单的语句就是return.

      }

}

 

class PersonDemo3

{

      publicstatic void main(String[] args)

      {

 

           Personp1 = new Person(20);。

           Personp2 = new Person(25);

           booleanb = p1.compare(p2);

           System.out.println(b);

           Personp = new Person("lisi");

          Personp1 = new Person("zhangsan");

          p.speak(); //输出lisi的name和age值

           p1.speak();//输出zhangsan的name和age值。

           p.speak();//输出lisi的name和age值。



      }

}


需求:给人定义一个用于比较年龄是否相同的功能。也就是是否是同龄人。

这个练习的思路一定要重点记忆!相比较一般都是用boolean布尔型。一般用a compare b,两个对象想比较比较合适。

人与人比较,所以publicboolean compare(Person p) 括号内部是个人对象的引用,即为Person类的引用。

 

this语句 :用于构造函数之间进行互相调用。

构造函数间只能用this语句,而且this语句只能定义在构造函数的第一行。因为初始化要先执行。

this语句 演示代码2

class Person

{

      privateString name;

      private intage; 

      {         

           System.out.println("coderun");

      }   

      Person()

      {

           //this("hah");这条语法错误,因为下面那个Person(String name)已经调用这个构造函数了,如果再用这条指令,会造成死循环

           System.out.println("personrun");

      }

      Person(Stringname)

      {

           this();这条语句就是this语句,必须放在构造函数的第一行,用来引用上一个构造函数Person()。放到第一行是因为必须初始化,而初始化的过程中如果有更初始化的过程(如此条this语句),则执行这个更初始化的过程。

           this.name=name;

      }

      Person(Stringname,int age)

      {

           this(name);//这条语句就是this语句,必须放在构造函数的第一行,用来引用上一个构造函数Person(String name)。

           this.name= name;

           this.age= age;       

      }

}

class  PersonDemo4

{

      public staticvoid main(String[] args)

      {

           //newPerson();

           Person p= new Person("lisi",30);

           Personp1 = new Person("lisi2",36);

      }

}

一般函数是不能调用构造函数的,因为这个this语句只能用在构造函数间~



------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值