目录
主要内容
- 面向过程和面向对象
- 类和对象
- 成员变量和成员方法
- 局部变量
- 构造方法及其重载
- 方法调用
- this
学习目标
节数 |
知识点 |
要求 |
第一节(类和对象) |
面向过程和面向对象 |
理解 |
类和对象 |
理解 |
|
第二节(类和对象) |
成员变量 |
掌握 |
成员方法 |
掌握 |
|
局部变量 |
掌握 |
|
第三节(构造方法) |
构造方法及其重载 |
掌握 |
对象数组 |
了解 |
|
第四节(方法调用) |
方法调用-基本数据类型形参 |
掌握 |
方法调用-引用数据类型形参 |
掌握 |
|
this关键字 |
理解 |
第一节 类和对象
1.1. 面向过程和面向对象
面向过程和面向对象都是对软件分析、设计和开发的一种思想,它指导着人们以不同的方式去分析、设计和开发软件。
早期先有面向过程思想,随着软件规模的扩大,问题复杂性的提高,面向过程的弊端越来越明显的显示出来,出现了面向对象思想并成为目前主流的方式。两者都贯穿于软件分析、设计和开发各个阶段,对应面向对象就分别称为面向对象分析(OOA)、面向对象设计(OOD)和面向对象编程(OOP)。C语言是一种典型的面向过程语言,Java是一种典型的面向对象语言。
示例1:开车和造车
面向过程思想思考问题时,我们首先思考“怎么按步骤实现?”并将步骤对应成方法,一步一步,最终完成。 这个适合简单任务,不需要过多协作的情况下。比如,如何开车?我们很容易就列出实现步骤:
面向过程适合简单、不需要协作的事务,重点关注如何执行。
但是当我们思考比较复杂的设计任务时,比如“如何造车?”,就会发现列出1234这样的步骤,是不可能的。那是因为,造车太复杂,需要很多协作才能完成。此时面向对象思想就应运而生了。
面向对象(Oriented-Object)思想更契合人的思维模式。我们首先思考的是“怎么设计这个事物?” 比如思考造车,我们就会先思考“车怎么设计?”,而不是“怎么按步骤造车的问题”。这就是思维方式的转变。
比如,我们用面向对象思想思考“如何设计车”:
天然的,我们就会从“车由什么组成”开始思考。发现,车由如下对象组成:
为了便于协作,我们找轮胎厂完成制造轮胎的步骤,发动机厂完成制造发动机的步骤;这样,发现大家可以同时进行车的制造,最终进行组装,大大提高了效率。但是,具体到轮胎厂的一个流水线操作,仍然是有步骤的,还是离不开执行者、离不开面向过程思维!
因此,面向对象可以帮助我们从宏观上把握、从整体上分析整个系统。 但是,具体到实现部分的微观操作(就是一个个方法),仍然需要面向过程的思路去处理。
我们千万不要把面向过程和面向对象对立起来。他们是相辅相成的。面向对象离不开面向过程!
示例2:蛋炒饭和盖浇饭
简单来说:用面向过程的方法写出来的程序是一份蛋炒饭,而用面向对象写出来的程序是一份盖浇饭。所谓盖浇饭,就是在米饭上面浇上一份盖菜,你喜欢什么菜,你就浇上什么菜。我觉得这个比喻还是比较贴切的。
蛋炒饭肯定是把米饭和鸡蛋混在一起炒匀。盖浇饭呢,则是把米饭和盖菜分别做好,你如果要一份红烧肉盖饭呢,就给你浇一份红烧肉;如果要一份青椒土豆盖浇饭,就给浇一份青椒土豆丝。
蛋炒饭的好处是入味均匀,吃起来香。如果恰巧你不爱吃鸡蛋,只爱吃青菜的话,那么唯一的办法就是全部倒掉,重新做一份青菜炒饭了。盖浇饭就没这么多麻烦,你只需要把上面的盖菜拨掉,更换一份盖菜就可以了。盖浇饭的缺点是入味不均,可能没有蛋炒饭那么香。
到底是蛋炒饭好还是盖浇饭好呢?其实这类问题都很难回答,非要比个上下高低的话,就必须设定一个场景,否则只能说是各有所长。那么从饭馆角度来讲的话,做盖浇饭显然比蛋炒饭更有优势,他可以组合出来任意多的组合,而且不会浪费。
盖浇饭的好处就是“菜”“饭”分离,从而提高了制作盖浇饭的灵活性。饭不满意就换饭,菜不满意换菜。用软件工程的专业术语就是“可维护性”比较好,“饭” 和“菜”的耦合度比较低。蛋炒饭将“蛋”“饭”搅和在一起,想换“蛋”“饭”中任何一种都很困难,耦合度很高,以至于“可维护性”比较差。软件工程追求的目标之一就是可维护性。面向对象的好处之一就是显著的改善了软件系统的可维护性。
·面向对象和面向过程思想的总结
- 都是解决问题的思维方式,都是代码组织的方式。
- 面向过程是一种“执行者思维”,解决简单问题可以使用面向过程。
- 面向对象是一种“设计者思维”,解决复杂、需要协作的问题可以使用面向对象。
- 面向对象离不开面向过程:
- 宏观上:通过面向对象进行整体设计
- 微观上:执行和处理数据,仍然是面向过程。。
面向过程 |
面向对象 |
|
区别 |
事物比较简单,可以用线性的思维去解决 |
事物比较复杂,使用简单的线性思维无法解决 |
共同点 |
面向过程和面向对象都是解决实际问题的一种思维方式 |
|
二者相辅相成,并不是对立的。 解决复杂问题,通过面向对象方式便于我们从宏观上把握事物之间复杂的关系、方便我们分析整个系统;具体到微观操作,仍然使用面向过程方式来处理 |
1.2. 理解类和对象
我们人认识世界,其实就是面向对象的(此对象可不是男女谈对象的彼对象呀) 。比如现在让大家认识一下“天使”这个新事物,天使大家没见过吧,怎么样认识呢?最好的办法就是,给你们面前摆4个天使,带翅膀的美女,让大家看,看完以后,即使我不说,大家下一次是不是就都认识天使了。
但是,看完10个天使后,我们总要总结一下,什么样的东东才算天使?天使是无数的,总有没见过的!所以必须总结抽象,便于认识未知事物!总结的过程就是抽象的过程。小时候,我们学自然数时怎么定义的?像1,2,3,4…这样的数就叫做自然数。 通过抽象,我们发现天使有这样一下特征:
- 带翅膀(带翅膀不一定是天使,还可能是鸟人)
- 女孩(天使掉下来脸着地,也是天使!)
- 善良
- 头上有光环
那么通过这4个具体的天使,我们进行抽象,抽象出了天使的特征,我们也可以归纳一个天使类。 通过这个过程,类就是对象的抽象。
类可以看做是一个模版,或者图纸,系统根据类的定义来造出对象。我们要造一个汽车,怎么样造?类就是这个图纸,规定了汽车的详细信息,然后根据图纸将汽车造出来。
类:我们叫做class。 对象:我们叫做Object,instance(实例)。以后我们说某个类的对象,某个类的实例。是一样的意思。
示例1:英雄联盟、王者荣耀中的类和对象
英雄就是类,具体的英雄,盖伦、提莫是对象。
示例2:月饼模具和月饼
月饼模具是类,使用月饼模具制作的一个个月饼就是对象
总结
- 类可以看成一类对象的模板,对象可以看成该类的一个具体实例。
- 类是用于描述同一类型的对象的一个抽象概念,类中定义了这一类对象所应具有的共同的属性、方法。
本节作业
- 理解面向过程和面向对象的异同
- 理解类和对象的关系
第二节 类和对象
2.1. 定义类和创建对象
做了关于对象的很多介绍,终于进入代码编写阶段。本节中重点介绍类和对象的基本定义,属性和方法的基本使用方式。
2.1.1. 属性(field 成员变量)
属性用于定义该类或该类对象包含的数据或者说静态特征。属性作用范围是整个类体。在定义成员变量时可以对其初始化,如果不对其初始化,Java使用默认的值对其初始化。
数据类型 |
默认值 |
整型 |
0 |
浮点型 |
0.0 |
字符型 |
'\u0000' |
布尔型 |
false |
所有引用类型 |
null |
属性定义格式:
[修饰符] 属性类型 属性名 = [默认值] ;
2.1.2. 方法
方法用于定义该类或该类实例的行为特征和功能实现。方法是类和对象行为特征的抽象。方法很类似于面向过程中的函数。面向过程中,函数是最基本单位,整个程序由一个个函数调用组成。面向对象中,整个程序的基本单位是类,方法是从属于类和对象的。
方法定义格式:
[修饰符] 方法返回值类型 方法名(形参列表) {
// n条语句
}
void代表没有返回值;方法的作用:重用代码,封装功能,便于修改
【示例1】定义类,模拟人的行为:吃饭工作和休息
- 面向对象分析OOA
从张三、李四、王五中提取出共同内容,提取一个类,人Person,包含共同的内容
静态的特征:姓名、年龄、性别、住址
动态的行为:eat、rest、work
- 面向对象设计OOD Design
类:Person
对象:zhangsan、lisi
让对象完成功能
- 面向对象编程OOP Programming
public class Person { //静态特征:成员变量 属性 field String name; //姓名 int age;//年龄 //动态的行为: 成员方法 method public void eat(){ System.out.println("----人是铁饭是钢,一顿不吃饿得慌!!!-----"); } public void work(){ System.out.println(name+"-------在劳动------"); } public void rest(String site){ System.out.println(name+"在"+site+"休息"); } }
【示例2】模拟实现具体人的特征和行为
public class Test { public static void main(String[] args) { //int n=5; int n; n = 5; System.out.println(n); Scanner input = new Scanner(System.in); //创建一个Person类的对象:张三并进行动态行为 //Person person1 = new Person(); Person person1; //方法中定义的变量,局部变量,没有默认值 person1 = new Person(); person1.name="zhangsan"; person1.age = 23; person1.eat(); person1.work(); person1.rest("宿舍"); //创建一个Person类的对象:李四并进行动态行为 Person person2 = new Person(); person2.name="lisi"; person2.age=24; person2.work(); person2.rest("工地"); person2.eat(); } }
总结1:如何创建对象 Scanner input = new Scanner(System.in); Person person1 = new Person(); new 后面是构造方法,具体含义稍后讲解
总结2:如何操作属性:对象名.属性名 person1.name="zhangsan"; person1.age = 23;
总结3:如何调用方法: 对象名.方法名(实参列表) person1.eat(); person1.work(); person1.rest("宿舍");
总结4:内存分配图
2.2. 局部变量
类中定义的变量是成员变量,而方法中定义的变量,包括方法的参数,代码块中定义的变量被称为局部变量。两个的区别主要表现在以下几方面:
成员变量 |
局部变量 |
|
代码中位置不同 |
类中定义的变量 |
方法或代码块中定义的变量 |
内存中位置不同 |
堆内存 |
栈内存 |
是否有默认值 |
有 |
没有 |
代码作用范围(空间) |
当前类的方法 |
当前一个方法或代码块 |
作用时间不同 |
当前对象从创建到销毁 |
定义变量到所属方法或代码块执行完毕 |
【示例3】使用计算器完成加法、减法运算
public class Calculator { //成员变量 private String brand;//品牌 private double size;//尺寸 //成员方法 public int add(int num1,int num2){ int result; result = num1+num2; return result; } public int sub(int num1,int num2){ return num1-num2; } public void show(){ System.out.println("我购买了一个计算器"+brand+","+size); } public static void main(String[] args) { //购买运算器 Calculator calc = new Calculator(); calc.brand = "联想"; calc.size = 6.5; calc.show(); //使用运算器进行运算 int num1 = 10; int num2 = 20; int result = calc.add(num1,num2); System.out.println(result); result = calc.sub(num1,num2); System.out.println(result); } }
代码执行的内存分配图如下:
本节作业
- 定义Person类并创建多个Person对象,模拟人的行为
- 定义一个计算器类并模拟其行为
第三节 构造方法及其重载
3.1. 构造方法
对于一个类来说,一般有三种常见的成员:属性field、方法method、构造器constructor。这三种成员都可以定义零个或多个。
构造方法(constructor)也叫构造器,用于对象的初始化。构造器是一个创建对象时被自动调用的特殊方法,目的是对象的初始化。构造器的名称应与类的名称一致。Java通过new关键字来调用构造器,从而返回该类的实例,是一种特殊的方法。
声明格式:
[修饰符] 类名(形参列表){
//n条语句
}
构造器4个要点:
- 构造器的方法名必须和类名一致!
- 构造器通过new关键字调用!!
- 构造器虽然有返回值,但是不能定义返回值类型(返回值的类型肯定是本类),不能在构造器里使用return返回某个值。
- 如果我们没有定义构造器,则编译器会自动定义一个无参的构造方法。如果已定义则编译器不会自动添加!
构造方法也是方法,只不过有特殊的作用而已。与普通方法一样,构造方法也可以重载。
【示例4】定义计算机类并模拟其操作
public class Computer { //成员变量 private String cpu="Intel";//cpu private String memory;//内存 private String mainBoard;//主板 private String keyBoard;//键盘 //构造方法 public Computer(){ System.out.println("--------Computer()--------"); cpu = "AMD"; } public Computer(String cpu,String memory, String mainBoard,String keyBoard){ this.cpu = cpu; this.memory = memory; this.mainBoard = mainBoard; this.keyBoard = keyBoard; } // public Computer(String cpu1,String memory1,String mainBoard1,String keyBoard1){ // cpu = cpu1; // memory = memory1; // mainBoard = mainBoard1; // keyBoard = keyBoard1; // } //成员方法 public void start(){ System.out.println("-------starting------"); } public void close(){ System.out.println("------- closing----------"); } public void show(){ System.out.println("cpu="+cpu+",memory="+memory+ ",mainBoard="+mainBoard+",keyBoard"+keyBoard); } public static void main(String[] args) { //购买一台电脑 Computer computer2 = new Computer(); // computer.cpu="酷睿"; omputer.memory="三星"; // computer.mainBoard="华硕"; computer.keyBoard="罗技"; Computer computer = new Computer("酷睿","三星","华硕","罗技"); //让电脑运行 computer.start(); computer.show(); computer.close(); } }
新手雷区
对象的创建完全是由构造方法实现的吗?
不完全是。构造方法是创建Java对象重要途径,通过new关键字调用构造器时,构造器也确实返回了该类对象,但这个对象并不是完全由构造器负责创建的。创建一个对象分为如下四步:
1. 分配对象空间,并将对象成员变量初始化为0或空
2. 执行属性值的显示初始化
3. 执行构造方法
4. 返回对象的地址给相关的变量
新手雷区
如果方法构造中形参名与属性名相同时,需要使用this关键字区分属性与形参。
this.id 表示属性id;id表示形参id
3.2. 对象数组
已经学过数组了,但是数组元素都是基本数据类型或者String类型。学习了类和对象之后,可以定义数组的元素类型是更加复杂的引用引用数据类型,每个元素可以是一个具体的对象,称为对象数组。
【示例5】使用对象数组存储多台计算机信息
public class TestArray { public static void main(String[] args) { //定义一个数组,存储4个分数,并遍历 int [] arr; arr = new int[4]; arr[0] = 90; arr[1] = 80; arr[2] = 100; arr[3] = 54; for(int score : arr){ System.out.println(score); } System.out.println("======================"); //定义一个数组,存储4台计算机,并遍历 //Computer [] arr2; //arr2 = new Computer[4]; Computer [] arr2 = new Computer[4]; arr2[0] = new Computer("酷睿","三星","华硕","罗技"); arr2[1] = new Computer("Intel","金士顿","技嘉","双飞燕"); arr2[2] = new Computer("AMD","三星","华硕","双飞燕"); arr2[3] = new Computer("酷睿","金士顿","技嘉","罗技"); for (Computer computer:arr2){ // System.out.println(computer.toString()); computer.show(); } } }
内存分配图入下图所示。
本节作业
- 定义一个“点”(Point)类用来表示二维空间中的点(有二个坐标)。要求如下:
- 可以生成具有特定坐标的点对象。
- 提供可以设置二个坐标的方法。
- 提供可以计算该“点”距另外点距离的方法。
- 使用对象数组存储多个对象并输出内容
第四节 方法调用
方法调是Java开发中的基本操作。理解方法调用的内存分配过程,实参形参的传递过程非常必要。方法参数分为基本数据类型和引用数据类型两种,传递参数有着实质的区别。
4.1. 基本数据类型的方法调用
【示例6】基本数据类型的方法调用
public class TestPrimaryArgs { public static void main(String[] args) { //定义两个变量 int num1 = 10; int num2 = 20; //输出交换前两个变量的值 System.out.println("交换前:num1="+num1+",num2="+num2); //交换两个变量的值 swap(num1,num2); //输出交换后两个变量的值 System.out.println("交换后:num1="+num1+",num2="+num2); } public static void swap(int num1,int num2){ int temp; temp = num1; num1 = num2; num2 = temp; System.out.println("交换后1:num1="+num1+",num2="+num2); } }
4.2. 引用数据类型的方法调用
【示例7】引用数据类型的方法调用
public class Point { int x; int y; } public class TestRefArgs { public static void main(String[] args) { //定义两个变量 Point p = new Point(); p.x = 10; p.y = 20; //输出交换前两个变量的值 System.out.println("交换前:p.x="+p.x+",p.y="+p.y); //交换两个变量的值 swap(p); //输出交换后两个变量的值 System.out.println("交换后:p.x="+p.x+",p.y="+p.y); } public static void swap(Point p){ p = new Point(); int temp; temp = p.x; p.x = p.y; p.y = temp; } }
内存分配过程如图所示。
新手雷区
基本数据类型的参数是值传递,引用数据类型的参数传递是引用(地址),本质上也是值传递。
4.3. this
4.3.1. 对象创建的过程和this的本质
构造方法是创建Java对象的重要途径,通过new关键字调用构造器时,构造器也确实返回该类的对象,但这个对象并不是完全由构造器负责创建。创建一个对象分为如下四步:
1. 分配对象空间,并将对象成员变量初始化为0或空
2. 执行属性值的显示初始化
3. 执行构造方法
4. 返回对象的地址给相关的变量
this的本质就是“创建好的对象的地址”! 由于在构造方法调用前,对象已经创建。因此,在构造方法中也可以使用this代表“当前对象” 。
4.3.2. this最常的用法:
- 调用成员变量:如果成员变量和局部变量同名,this必须书写,用来区分两者;如果没有同名的局部变量,this可以不写
- 调用成员方法:这种情况下,this可以省略
- 调用构造方法:使用this关键字调用重载的构造方法,避免相同的初始化代码。但只能在构造方法中用,并且必须位于构造方法的第一句。
- this不能用于static方法中。
【示例8】this关键字的使用
public class Student { //成员变量 private int sno;//学号 private String name;//姓名 private String sex;//性别 private double score;//分数 //构造方法 public Student(){ } public Student(int sno,String name,String sex ){ this.sno = sno; this.name = name; this.sex = sex; } public Student(int sno,String name,String sex ,double score){ this(sno,name,sex); //new Student(sno,name,sex); // this.sno = sno; // this.name = name; // this.sex = sex; this.score = score; } //成员方法 public void study(){ this.shout(); shout(); //System.out.println("好好学习,天天向上。add oil!!!"); System.out.println("在教室努力的学习中,代码量一行行提升了....."); } public void shout(){ System.out.println("好好学习,天天向上。add oil!!!"); } public void show(){ System.out.println(sno +" "+this.name+" "+sex+" "+this.score); } public static void main(String[] args) { Student stu = new Student(7,"田七","男",77); stu.study(); stu.shout(); stu.show(); //study(); Student stu2 = new Student(); } }
本节作业
- 练习基本数据类型的参数传递
- 练习引用数据类型的参数传递
- this关键字的作用和用法
- 练习this关键字的使用