----------------------ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
一.什么是面向对象?
1.面向对象的定义
面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。早期的计算机编程是基于面向过程的方法,例如实现算术运算1+1+2 = 4,通过设计一个算法就可以解决当时的问题。随着计算机技术的不断提高,计算机被用于解决越来越复杂的问题。一切事物皆对象,通过面向对象的方式,将现实世界的事物抽象成对象,现实世界中的关系抽象成类、继承,帮助人们实现对现实世界的抽象与数字建模。通过面向对象的方法,更利于用人理解的方式对复杂系统进行分析、设计与编程。同时,面向对象能有效提高编程的效率,通过封装技术,消息机制可以像搭积木的一样快速开发出一个全新的系统。面向对象是指一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的集合。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。
起初,“面向对象”是专指在程序设计中采用封装、继承、多态等设计方法。现在面向对象的思想已经涉及到软件开发的各个方面。如,面向对象的分析(OOA,Object Oriented Analysis),面向对象的设计(OOD,Object Oriented Design)、以及我们经常说的面向对象的编程实现(OOP,Object Oriented Programming)。
面向对象的分析根据抽象关键的问题域来分解系统。面向对象的设计是一种提供符号设计系统的面向对象的实现过程,它用非常接近实际领域术语的方法把系统构造成“现实世界”的对象。面向对象程序设计可以看作一种在程序中包含各种独立而又互相调用的对象的思想,这与传统的思想刚好相反:传统的程序设计主张将程序看作一系列函数的集合,或者直接就是一系列对电脑下达的指令。面向对象程序设计中的每一个对象都应该能够接受数据、处理数据并将数据传达给其它对象,因此它们都可以被看作一个小型的“机器”,即对象。
2.面向对象三大特点(封装、继承、多态)
1)封装性
面向对象编程核心思想之一就是将数据和对数据的操作封装在一起。通过抽象,即从具体的实例中抽取共同的性质形成一般的概念,比如类的概念。在实际生活中,我们每时每刻都与“对象”在打交道,如日常用的钢笔、骑的自行车、乘的公共汽车等。而经常见到的卡车、公共汽车、轿车等都会涉及以下几个重要的物理量:可乘载 的人数、运行速度、发动机的功率 、耗油量、自重、轮子数目等。另外,还有几个重要的功能:加速、减速、制动、转弯等。也可以把这些功能称为它们具有的方法,而物理量是它们的状态描述,仅仅用物理量或功能不能很好地描述它们。在现实生活中,用这些共有的属性和功能给出一个概念:机动车类。也就是说,人们经常谈到的机动车类就是从具体的实例中抽取共同的属性和功能形成的一个概念,那么一个具体的轿车就是机动车类的一个实例,即对象。一个对象将自己的数据和对这些数据的操作合理有效地封装在一起,例如,每辆轿车调用”加速功能“改变的都是自己的运行速度。
2)继承性
继承性是子类自动共享父类数据结构和方法的机制,这是类之间的一种关系。在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义 的内容作为自己的内容,并加入若干新的内容。继承体现了一种先进的编程模式。。了类可以继承父类的属性和功能,即子类继承了父类所具有的数据和数据上的操作,同时又可以增添子 类独有的数据和数据上的操作。比如,“人类”自然继承了“哺乳类”的属性和功能,同时又增添了人类独有的属性和功能采用继承性,提供了类的规范的等级结构。通过类的继承关系, 使公共的特性能够共享,提高了软件的重用性。
3)多态性(多形性)
多态是面向对象编程的又一重要特征。有两种意义的多态,一种是操作名称的多态,即有多个操作具有相同的名字,但这 些操作所接收的消息类型必须不同。例如,让一个人执行“ 求面积”操作时,他可能会问你求什么面积?所谓操作名称的多态是指 可以向操作传递不同消息,以便让对象根据相应的消息来产生~定的行为。另一种多态是和继承有关的多态,是 指同一个操作被不同类型对象调用时可能产生不同的行为。例如,狗和猫都具有哺乳类的功能:“喊叫”。当狗操作“喊叫”时产生的声音是“汪汪 ……,,,而当猫操作“喊叫”时产生的声音 是“喵喵……”。
多态性允许每个对象以适合自身的方式去响应共同的消息。
3.面向对象思想的特点
1)它是一种更符合人们思考习惯的思想
2)它是复杂的内容简单化
3)它使我们从执行者变成了指挥者
二.类
1.类的概念
类是组成Java程序的基本要素。类封装J,一类对象的状态和方法。类是用来定义对象的模板。
类的实现包括两部分:类声明和类体。基本格式为:
class 类名 {
类体的内容
}
其中: class是关键字,用来定义类。"class类名”是类的声明部分,类名必须是合法的Java标识符。两个大括号以及之间的内容是类体。
2.类的声明
以下是两个类声明的例子。
class People {
···
}
class植物 {
···
}
class People和class 植物称为类声明,People和“植物”是类名。习惯上类名的第一个字母大写,但这不是必需的。类的名字不能是Java中的关键字,要符合标识符规定,即名字可以由字母、下划线、数字或美元符号组成,并且第一个字符不能是数字。但给类命名时,最好遵守下列习惯:
(1)如果类名使用拉丁字母,那么名字的首写字母使用大写字母,如Hello、Time、People等。
(2)类名最好容易识别,当类名由几个“单词”复合而成时,每个单词的首写字母使用大写,如BeijingTime、AmericanGame、HeIIoChina等。
3.类体
编写类的目的是为了描述一类事物共有的属性和功能,描述过程由类体来实现。类声明之后的一对大括号“{"、“}”以及它们之间的内容称为类体,大括号之间的内容称为类体的内容。
类体的内容由两部分构成:一部分是变量的定义,用来刻画属性:另一部分是方法的定义,用来刻画功能。
代码示例
- public class ObjectDemo1 {
- /**
- * 定义一个植物类,包含颜色,叶子数量两个方法,并在主函数调用
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Plant p = new Plant(); //创建一个植物类对象p
- p.colorDisplay("red"); //调用植物类的颜色方法
- p.numberDisplay(6); //调用植物类的数量方法
- }
- }
- class Plant {
- String color; //定义颜色变量
- int number; //定义叶子数量变量
- public void colorDisplay(String color) {
- System.out.println("my color is" + color); //输出要传递的变量并打印
- }
- public void numberDisplay(int number) {
- System.out.println("my number is" + number); //输出要传递的变量并打印
- }
- }
三.成员变量和局部变量
类体分为两部分。变量定义部分所定义的变量被称为类的成员变量,在方法体中定义的变量和方法的参数被称为局部变量。
1)成员变量和局部变量的类型可以是Java中的任何…种数据类型,包括基本类型:整型、浮点型、字符型;引用类型:数组类型、对象。成员变量和局部变量的名字必须符合标识符规定,遵守习惯:名字如果使用拉丁字母,首写字母使用小写;如果由多个单词组成,从第2个单词开始的其他单词的首写字母使用大写。
2)成员变量在整个类内都有效,局部变量只在定义它的方法内有效。
代码示例
- public class ObjectDemo2 {
- /**
- * 展示成员变量和局部变量的区别
- * @黑马ZWF
- */
- }
- class Sun {
- int distance; //定义成员变量distance
- int find() {
- int a = 12; //定义局部变量a
- distance = a; //这样是合法的,因为distance是成员变量,在整个类中都有用
- return distance;
- }
- void g() {
- int y;
- y = a; //这样定义是错误的,因为a没有在g中定义
- }
- }
3)如果局部变量的名字与成员变量的名字相同,则成员变量被隐藏,即这个成员变量在这个方法内暂时失效。
代码示例
- public class ObjectDemo3 {
- /**展示成员变量和局部变量的区别
- * @黑马ZWF
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Sam s = new Sam();
- s.d(); //输出结果是3,因为方法d中定义了x,则Sam类中的x = 98 暂时失效
- }
- }
- class Sam {
- int x = 98, y; //定义成员变量x,y。其中x = 98 ,y没有赋值
- void d() {
- int x = 3; //定义局部变量x,其中x = 3
- y = x;
- System.out.println(y);
- }
- }
4)如果局部变量的名字与成员变量的名字相同,则成员变量被隐藏。这时如果想在该方法内使用成员变量,必须使用关键字this。
代码示例
- class Triangle {
- float sideA,sideB,sideC,lengthSum;
- void setSide(float sideA, float sideB, float sideC) {
- this.sideA = sideA; //这个sideA才表示成员变量sideA,下同
- this.sideB = sideB;
- this.sideC = sideC;
- }
- }
四.方法
1.概念
一个类的类体由两部分组成:变量的定义和方法的定义。方法的定义包括两部分:方法声明和方法体。
一般格式为:
方法声明部分{
方法体的内容
}
2.方法的声明
最基本的方法声明包括方法名和方法的类型,如:
float area() {
…
}
方法的类型可以是任意的Java数据类型,当一个方法不需要返回数据时,方法的类型必须是voido很多的方法声明中都给出方法的参数,参数是用逗号隔开的一些变量声明。方法的参数可以是任意的Java数据类型。
方法的名字必须符合标识符规定。在给方法起名字时应遵守良好的习惯:名字如果使用拉丁字母,首写字母使用小写。如果由多个单词组成,从第2个单词开始的其他单词的首写字母使用大写。例如:
float getrrrangleArea();
void setCircleRadius (double radius);
3.方法体
方法声明之后的一对大括号“{”、“}”以及之间的内容称为方法的方法体。方法体的内容应包括局部变量的定义和合法的Java语句。例如上例中的void setSide(float sideA, float sideB, float sideC) {}就是一个方法,()里的内容代表要传递的参数。
4.方法的重载
方法重载是多态性的一种,例如,让一个人执行“求面积”操作时,他pJ能会问你求什么面积?所谓功能多态性是指可以向功能传递不同的消息,以便让对象根据相应的消息来产生相应的行为。对象的功能通过类中的方法来体现,那么功能的多态性就是方法的重载。方法重载的意思是:一个类中可以有多个方法具有相同的名字,但这些方法的参数必须不同,即或者是参数的个数不同,或者是参数的类型不同。
代码示例
- public class ObjectDemo4 {
- /**用三个名字相同参数不同的方法实现方法的重载
- * @黑马ZWF
- */
- float getArea(float r) { //求园的面积
- return 3.14f * r * r;
- }
- double getArea(float x, int y) { //求长方形的面积
- return x * y;
- }
- float getArea (int x, float y) { //求长方形的面积,长和宽的精度与上个方法不同
- return x * y;
- }
- double getArea (float x, float y, float z) { //求长方体的面积
- return (x * y + y * x + x * z) * 2.0;
- }
- }
5.构造方法
构造方法是一种特殊方法,用于对类的成员变量进行初始化。它有以下几个特点:
(1)构造方法名与类名相同.
(2)构造方法不返回任何值,也没有返回类型.
(3)每个类可以有零个或多个构造方法.
(4)构造方法在创建对象时自动执行,一般不能显式地直接调用.
(5)构造方法可以重载。
代码示例
- public class ObjectDemo5 {
- /**使用构造方法,分别调用含参和无参的构造方法
- * @黑马ZWF
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Human h1 = new Human(); //调用无参的构造方法
- Human h2 = new Human("李四",14); //调用含参的构造方法
- }
- }
- class Human {
- String name;
- int age;
- Human () {
- name = "张三";
- age = 12;
- System.out.println("我的名字叫" + name + " 今年" + age + "岁了");
- }
- Human(String name, int age) {
- System.out.println("我的名字叫" + name + " 今年" + age + "岁了");
- }
- }
五.对象
1.定义
类是创建对象的模板。当使用一个类创建了一个对象时,也就说给出了这个类的一个实例。
2.创建对象
创建一个对象包括对象的声明和为对象分配内存两个步骤。
1)对象的声明
一般格式为:
类的名字 对象名字;
如:
People zhangPing;
这里People是一个类的名字.zhangPing是声明的对象的名字.
2)为声明的对象分配内存
使用new运算符和类的构造方法为声明的对象分配内存,如果类中没有构造方法,系统会调用默认的构造方法(默认的构造方法是无参数的,构造方法的名字必须和类名相同)。
如:
zhangPing = new People();
代码示例:
- ublic class ObjectDemo1 {
- /**创建一个对象
- * @黑马ZWF
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- XiyoujiRenwu zhubajie; //声明对象
- zhubajie=new XiyoujiRenwu(); //为对象分配内存,使用new运算符和默认的构造方法
- }
- }
- class XiyoujiRenwu {
- float height,weight;
- String head, ear, hand, foot, mouth;
- void speak (String s) {
- System.out.println(s);
- }
- }
下面使用例子来说明对象的内存模型。
1)声明对象时的内存模型
当用XiyoujiRenwu类声明一个变量zhubajie,即对象zhubajie时,如上个代码示例中:
XiyoujiRenwu zhubajie;
声明对象变量zhubajie后,zhubajie的内存中还没有任何数据,这时的zhubajie称为一个空对象。空对象不能使用,因为它还没有得到任何“实体”,必须再进行为对象分配内存
的步骤,即为对象分配实体。
2)对象分配内存后的内存模型
当系统见到
zhubajie—new XiyoujiRenwu();时,就会做两件事。
①为height、weight. head、ear、mouth、hand、foot各个变量分配内存,即XiyoujiRenwu类的成员变量被分配内存空间,然后执行构造方法中的语句。如果成员变量在声明时没有
指定初值,所使用的构造方法也没有对成员变量进行初始化操作,那么,对于整型的成员变量,默认初值是O;对于浮点型,默认初值是O.O;对于boolean型,默认初值是false;对于引用型,默认初值是null。
②给出一个信息,确保这些变量是属于对象zhubajie的,即这些内存单元将由zhubajie操作管理。为了做到这一点,new运算符在为变量height、weight. head、ear、mouth、hand、foot分配内存后,将返回一个引用给对象变量zhubajie。也就是返回一个“号码”(该号码包含着代表这些成员变量内存位置的首地址等重要的有关信息)给zhubajie,不妨就认为这个引用就是zhubajie在内存里的名字,而且这个名字(引用)是Java系统确保分配给hcight、weight、head、ear、mouth、hand、foot的内存单元将由zhubajie操作管理。称height、weight、hcad、ear、mouth、hand、foot分配的内存单元是属于对象zhubajie的实体,即这些变量是属于zhubajie的。所谓为对象分配内存就是指为它分配变量,并获得一个引用,以确保这些变量由它来“操作管理”。
对象的声明和分配内存两个步骤也可以用一个等价的步骤完成,如:
XiyoujiRenwu zhubajie = new XiyoujiRenwu();
(3)创建多个不同的对象
一个类通过使用new运算符可以创建多个不同的对象,这些对象将被分配不同的内存空间,因此,改变其中一个对象的状态不会影响其他对象的状态。例如,可以在上述例子中创建两个对象:zhubajie和sunwukong。
zhubajie = new XiyoujiRenwu();
sunwukong = new XiyoujiRenwu();
当创建对象zhubajie时,XiyoujiRenwu类中的成员变量height、weight、head、ear、mouth、hand、foot被分配内存空间,并返回一个引用给zhubajie;当再创建一个对象sunwukong时,XiyoujiRenwu类中的成员变量height、weight、head、ear、mouth、hand、foot再一次被分配内存空间,并返回一个引用给sunwukong。sunwukong的变量所占据的内存空间和zhubajie的变量所占据的内存空间是互不相同的位置。
六.对象的使用
对象不仅可以改变自己变量的状态,而且还拥有了使用创建它的那个类中的方法的能力,对象通过使用这些方法可以产生一定的行为。通过使用运算符“.”,对象可以实现对自己的变量访问和方法的调用。例如本文第一个代码示例中XiyoujiRenwu中有speak方法,我们就可以通过"zhubajie.speak();"来调用
1.对象操作自己的变量(对象的属性)
对象创建之后,就有了自己的变量,即对象的实体。通过使用运算符“.”,对象可以实现对自己的变量的访问。
2.对象调用类中的方法(对象的功能)
对象创建之后,可以使用运算符“.”调用创建它的类中的方法,从而产生一定的行为功能。
上一篇博客中对类的介绍提到,类中的方法可以操作成员变量。当对象调用方法时,方法中出现的成员变量就是指该对象的成员变量。
当对象调用类中的一个方法时,方法中的局部变量被分配内存空间,方法执行完毕,局部变量即刻释放内存。局部变量声明时如果没有初始化,就没有默认值,因此在使用局部变量之前,要事先为其赋值。我将通过一个程序具体实现对象的使用。
代码示例
- public class ObjectDemo2 {
- /**创建一个XiyoujiRenwu类,创建一个zhubajie对象,然后赋值并输出,调用XiyoujiRenwu的方法
- * @黑马ZWF
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- XiyoujiRenwu zhubajie; //声明对象
- zhubajie = new XiyoujiRenwu(); //为对象分配内存,使用new运算符和默认的构造方法
- zhubajie.ear = "又肥又大"; //为XiyoujiRenwu的ear成员变量赋初值
- zhubajie.head = "是一个猪头"; //为XiyoujiRenwu的head成员变量赋初值
- zhubajie.mouth = "有一张猪嘴"; //为XiyoujiRenwu的mouth成员变量赋初值
- zhubajie.height = 1.6f; //为XiyoujiRenwu的height成员变量赋初值
- zhubajie.weight = 500; //为XiyoujiRenwu的weight成员变量赋初值
- zhubajie.speak("大家好!我是猪八戒"); //调用XiyoujiRenwu的speak方法
- System.out.println("我" + zhubajie.mouth ); //输出之前赋的值
- System.out.println("我" + zhubajie.head);
- System.out.println("我的耳朵" + zhubajie.ear);
- System.out.println("我的身高只有" + zhubajie.height + "米");
- System.out.println("但我却有" + zhubajie.weight + "公斤重");
- }
- }
- class XiyoujiRenwu {
- float height; //定义变量
- int weight;
- String head, ear, hand, foot, mouth;
- void speak (String s) { //定义speak方法
- System.out.println(s);
- }
- }
输出结果如下图
七.对象的引用和实体
当用类创建一个对象时,类中的成员变量被分配内存空间,这些内存空间称为该对象的实体,而对象中存放着引用,以确保实体由该对象操作使用。
因此,如果一个类创建的两个对象具有相同的引用,那么就具有完全相同的实体。没有实体的对象称为空对象,空对象不能使用,即不能让~个空对象去调用方法产生行为。假如程序中使用了空对象,程序在运行时会出现异常:NuIIPointerException o由于对象是动态地分配实体,所以Java昀编译器对空对象不做检查。因此,在编写程序时要避免使用空对象。
代码示例
- public class ObjectDemo2 {
- /**举例具体讲述对象的引用和实体
- * @黑马ZWF
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Point p1 = new Point(10, 10); //为对象分配内存,使用new和类中的构造方法
- Point p2 = new Point(23, 35);
- }
- }
- class Point {
- int x, y;
- Point(int a, int b) {
- y = a;
- x = b;
- }
- }
pl=p2.
把p2的引用(p2在内存中的名字)赋给了pl,因此pl和p2奉质上是一样的了。虽然在源文件中pl、p2是两个名字,但在系统看来它们的名字是一个:OxDDo系统将取消原来分配给pl的内存.即释放分配给pl的变量。这时如果输出pl.x的结果将是6,而不是12,即pl、p2有相同的实体。
八.对象的参数传值
当方法被调用时,如果力.法有参数,参数必须要实例化,即参数变量必须有具体的值。在Java中,方法的所有参数都是“传值”的,也就是说,方法中参数变量的值是调用者定的值的副本。例如,如果向方法的int型参数x传递一个int值,那么参数x得到的值是传递值的副本。方法如果改变参数的值,不会影响向参数“传值”的变量的值。
1.基本数据类型参数的传值
对于基本数据类型的参数,向该参数传递的值的级别不可以高于该参数的级别,比如,不可以向int型参数传递一个float值,但可以向double型参数传递一个float值。
2.引用类型参数的传值
Java的引用型数据包括对象、数组以及接口。当参数是引用类型时,“传值”传递的变量的引用而不是变量所引用的实体。
如果改变参数变量所引用的实体,就会导致原变量的实体发生同样的变化,因为,两个同类型的引用型变量如果具有同样的引用,就会用同样的实体。但是,改变参数的引用不会影响向其传值的变量的引用
代码示例
- public class ObjectDemo4 {
- /**创建一个“圆锥”类对象,将一个圆的对象的引用传递给圆锥对象的底圆
- * @黑马ZWF
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Circle circle = new Circle(10); //创建一个圆对象并赋初值10
- ConicCircle coniccircle = new ConicCircle(circle, 20); //创建一个圆锥对象并赋初值20
- System.out.println("圆锥底圆半径" + coniccircle.getDownCircleRadius()); //输出结果是:圆锥底圆半径10.0
- System.out.println("圆锥的体积" + coniccircle.cauculateVolume()); //输出结果是:圆锥的体积2093.3333333333335
- coniccircle.modifyDownCircleRadius(100); //调用方法修改半径
- System.out.println("圆锥底圆半径" + coniccircle.getDownCircleRadius()); //输出结果是:圆锥底圆半径100.0
- System.out.println("圆锥的体积" + coniccircle.cauculateVolume()); //输出结果是:圆锥的体积209333.33333333334
- }
- }
- class Circle { //定义一个圆类
- double radius; //定义半径
- Circle(double r) {
- radius = r;
- }
- double calculateRadius() { //定义计算面积方法
- return 3.14 * radius * radius; //计算圆面积的公示
- }
- void modifyRadius(double NewRadius) { //定义修改半径方法
- radius = NewRadius;
- }
- double getRadius() { //定义获取半径方法
- return radius;
- }
- }
- class ConicCircle { //定义圆锥类
- Circle downCircle; //声明圆对象底圆
- double heigh;
- ConicCircle(Circle circle, double h) { //构造方法定义变量
- this.downCircle = circle;
- this.heigh = h;
- }
- double cauculateVolume() { //定义计算体积的方法
- double volume;
- volume = downCircle.calculateRadius() * heigh / 3.0; //计算圆锥的体积公示,其中传递了圆的底圆面积
- return volume;
- }
- void modifyDownCircleRadius(double r) { //定义修改半径方法
- downCircle.modifyRadius(r);
- }
- double getDownCircleRadius(){ //定义返回底圆半径方法
- return downCircle.getRadius();
- }
- }
- public class ObjectDemo5 {
- /**使用构造方法,分别调用含参和无参的构造方法
- * @黑马ZWF
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Human h1 = new Human(); //调用无参的构造方法
- Human h2 = new Human("李四",14); //调用含参的构造方法
- }
- }
- class Human {
- String name;
- int age;
- Human () {
- name = "张三";
- age = 12;
- System.out.println("我的名字叫" + name + " 今年" + age + "岁了");
- }
- Human(String name, int age) {
- System.out.println("我的名字叫" + name + " 今年" + age + "岁了");
- }
- }