第六讲 面向对象
课程大纲 | 课程内容 | 学习效果 | 掌握目标 |
面向对象 | 类和对象 | 掌握 | 熟练掌握面向对象的思想 熟练掌握类和对象的定义和使用方式 熟练掌握属性和方法的含义和使用 |
封装 | 掌握 | 熟练掌握封装的意义和方式 | |
构造方法 | 掌握 | 熟练掌握构造方法特点、定义方式和作用 | |
this关键字 | 了解 | 熟练掌握this关键字的含义和使用方式 |
一、类和对象
1、万物皆对象
问题:我们是怎么认识世界的?
人类不断地接触世界上各种各样的事物(动物、植物、建筑、山川、河流.....),然后通过这些事务的公共属性,归纳出这些事务的共同特征。所以,当我们见到猫的时候,不会叫老虎,见到树木的时候,不会叫花朵。我们在现实生活中,是通过具体的某种事物归纳总结它们的公共特性然后产生类(一类事物)。那么类就描述了该种事物的的共性。类相当于造事物的图纸,我们可以根据这个图纸去做出具体的实体对象。
问题:说一说教室里的对象?
对象:在现实生活中存在具体的一个事物。
类:实际就是对某种类型事物的共同属性与行为的抽取。
人类认识世界: 对象----à类。
在java中: 类 -----à对象。
2、面向对象概述
“面向对象”(英语:Object Oriented,简称OO)是一种以事物为中心的编程思想。
面向对象程序设计(英语:Object-oriented programming,缩写:OOP),是一种程序开发的方法。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。
面向对象是相对于面向过程而言的(C则是一个典型的面向过程的语言),站在面向对象的角度去看问题,你则是对象的动作的指挥者。如果站在面向过程的角度去看问题,你则是动作的执行者。
3、面向对象和面向过程的对比
“面向过程”强调的是功能行为,面向过程”是一种以过程为中心的编程思想。“面向过程”他们不支持丰富的“面向对象”特性(比如继承、多态),就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。面向过程在这一系列工作的执行中,强调的是工作的执行。
1:买电脑 面向过程 1:查资料 2:电脑城砍价 3:被黑 4:痛苦归来 面向对象 1:找对象(老师) 2:老师.砍价 3:老师.检测电脑 4:电脑成功购买 2:吃饭 面向过程 1:自己动手做 2:买菜 3:洗菜 4:煮饭炒菜 5:很难吃,浪费时间 面向对象 1:找专业对象(餐馆) 2:餐馆.点餐 3:餐馆.做饭 4:饭好吃,节约时间,精力 3:找对象 面向过程: 1:上网聊天 2:约见面 3:请吃饭 4:...... 5:发现不合适,分手,很痛苦!
面向对象: 1:求介绍,相亲,找现成的对象。(面向对象的思想先找有的对象,直 接拿来使用) 2:不满意,没有对象,自己造一个。(sun没有提供,自己造对象) |
4、对象
对象(object)代表现实世界中可以明确标识的一个实体。例如:一个学生、一张桌子、一间教室,一台电脑都可以看做是一个对象。每个对象都有自己独特的状态标识和行为
对象的属性(attribute,或者状态(state))。学生有姓名和学号,该学生特有的姓名和学号就是该学生(对象)的属性。
对象的行为(behavior),是由方法定义,调用对象的一个方法,其实就是给对象发消息,要求对象完成一个动作。可以定义学生对象具备学习的行为。学生对象可以调用学习的方法,执行学习的动作。
5、类
类是对对象所应当具有的特征的描述。
类是抽象的存在。
对象是具体的存在。
在Java中,对象对应着内存中的一片数据。
6、类与对象的关系:
类好比是图纸,对象好比是房子。
类存在的理由:可以通过这个图纸,创建多个房子。
类创建对象的的过程叫做:实例化。
7、Java开发的任务
使用已有的类创建对象。(jdk中提供的)
编写自已的类,使有自已的类创建对象。
调用对象的方法,属性,去解决问题。
8、类的定义与使用
(1)使用已有的类
Java API提供了一些现成的类供我们使用,我们可以使用这些现有类来创建实例(对 象),比如:
String
Object
包装类Integer、Long…
集合类等等
使用现有类创建对象
类名 对象引用变量名 = new 类名 (); 例如:
String s1 = new String(“Hello,World”);
Object o = new Object();
(2)自定义类
除了使用现有API提供的类库,我们也可以自定义类。之前我们说过类是具有相同属性和相同操作的对象集合,属性就是成员变量,操作就是方法。
所以,类的定义主要有两方面组成:
成员变量(属性)
方法(行为)
格式
class 类名{ 成员变量(属性)定义; 方法定义; } |
约定俗称的命名规则:
类名的首字母大写
变量名和方法名的首字母小写
采用驼峰命名标识
(3)属性
类的定义主要由属性和方法组成。属性是指类(这类事物)拥有的特征。属性,通常是名词。
例如:定义一个学生类,拥有的属性有:学号,姓名,年龄,家庭住址...
那么如何确定一个类拥有哪些属性(特征)?其实,一个类(一类事物)拥有的属性有很多种。通常,我们在定义类的属性时,遵循的原则是,需要什么属性就定义什么属性。
定义属性的语法:
[访问控制符] 数据类型 属性名 [=值]
class Student{ int num; //学号 String name; //姓名 int age; // 年龄 String address; //家庭住址 ... } |
示例代码
public class Student { //属性(特征) ——名词 int id; //学号 String name; //姓名 String gender; //性别 int age; //年龄 } |
(4)方法
类的另一个成员,方法(动词)。方法,指一个类的行为(动词)。
方法的四个要素:
1、访问控制符(修饰符)
2、返回值类型——(方法调用结束之后,返回给调用者的信息) void(方法没有返回值)
3、方法名——调用的时候用来区分
4、参数列表——参数--方法运行时,需要的额外的信息.方法有返回值,在方法中就一定要有return
无参数,无返回值的方法:
在学生类(Student)中添加学习(study)方法,和玩游戏(playGame)方法
public void study(){ System.out.println(“努力学习”); } public void playGame(){ System.out.println(“开心玩游戏”); } |
无参数,有返回值的方法: 添加自我介绍的方法 introduce
public String introduce(){ return “我叫”+name; } |
问题: 为什么要用带参数的方法?
public class ZhaZhiJi{ public String zhazhi (String fruit ) { String juice = fruit + "汁"; return juice; } } |
向学生类中添加做整数加法题的方法:
public int add(int x,int y){ int result = x+y; return result; } |
示例代码
public class Student { //属性(特征) ——名词 int id; //学号 String name; //姓名 String gender; //性别 int age; //年龄 //方法(行为,能干什么)——动词 public void study(){ System.out.println("认真学习"); } public String introduce(){
return "我是:"+name; } public void eat(){ System.out.println("好好吃饭"); }
public int add(int a,int b){ int result = a+b; return result; } } |
(5)创建实例(对象)
类创建对象的过程叫做实例化。
Java中实例化对象和数组相同,也是使用new关键字。
语法:
类名 对象名 = new 类名();
Student stu = new Student(); 创建一个Student类的对象实例(可以简称为创建一个Student类的对象),对象的名字叫做stu(对象名,通常叫做对象引用)。
Student stu2 = new Student();// 又创建了一个Student对象,对象的引用叫做stu2
Student stu3 = stu;
内存分配图
单个对象:
|
多个对象:
|
(6)练习
案例1:定义一个汽车类,并生产出汽车,有颜色,轮胎个数, 有跑的功能。
分析:如何描述现实世界中的事物,描述该事物的属性和行为,汽车具有颜色和轮胎数的属性,具备跑的行为。
如何使用Java语言进行转换?
根据对应关系:
属性:类中的成员变量
行为:类中的成员方法
那么定义Java类就是定义一个类的成员。汽车类具备的成员是:颜色,轮胎数,运行方法。
Car类定义流程:
- 使用class 关键字 定义类,
-
-
- class空格 类名。类名就是标识符,命名规则,单词的首字母大写,多个单词的首字母大写。注意:不是规定,但是最好遵守。
- 类名后紧跟一对{}表示类的开始和结束。
-
-
- 汽车有轮胎数 int num;
-
-
- 不需要给num初始化值,因为汽车轮胎数不确定,有4,有6,有8。
-
-
- 有颜色 String color
-
-
- 为什么使用String 例如定义颜色"红色"是字符串类型。
- 也不需要初始化值。
-
-
- 跑的行为(方法) void run(){}
-
-
- 方法中执行输出语句。syso("跑啦。。。。");
-
-
示例代码
//汽车类 public class Car { // 属性——成员变量 int num; //轮胎个数 String color; // 颜色 // 方法——成员方法 public void run(){ System.out.println("跑啦..."); } } |
案例2:定义手机类
属性: 品牌、颜色、价格、尺寸
方法: 打电话、发短信
示例代码
//定义手机类 public class Mobile { // 属性(成员变量) String brand; //品牌 double price; //价格 String color; //颜色 int size; // 尺寸 //方法 public void call(String name){ //打电话方法 System.out.println("正在给"+name+"打电话......"); } public void sendMessage(String name){ //发信息方法 System.out.println("给"+name+"发信息<<<>>>"); } } |
(7)对象成员的调用
使用new关键字创建了对象后,就要调用对象成员(属性、方法)
使用点(.)来调用
示例代码
Mobile m1 = new Mobile(); m1.brand="华为"; m1.color="黑色"; m1.price=3000; m1.size=5;
m1.call("小毛"); m1.sendMessage("小邓"); |
(8)成员变量和局部变量
成员变量:定义在类中的变量。
局部变量:定义在方法中定义的变量和方法的参数。
成员变量与局部变量的区别
应用范围
成员变量在整个类内都有效
局部变量只在其声明的方法内有效
总结:变量的应用范围(作用域)就是定义这个变量的那对{}
生命周期
成员变量: 它属于对象,它随着对象的创建而创建,随着对象的消失而消失。被同一个类中的方法共享。可以不赋初值,有相应的默认值。
局部变量: 使用完马上释放空间。(定义它的那一对{}),另外,局部变量,定义完成后,必须赋初值。
在内存中的位置不同
成员变量:堆内存
局部变量:栈内存
示例代码
public class Car { String color="黑色"; //成员变量——直接在类下定义 public void drive(String name){ // String name是方法的参数——局部变量 int speed=80; // 在方法中定义变量——局部变量 System.out.println(name+"驾驶一辆"+color+"的车,以每小时"+speed+"公里的速度行驶..."); } } |
(9)面向对象练习
完成汽车修理功能。
汽车类(Car)和修理厂类(Factory)
Car的属性和方法:
属性:名字、颜色、轮胎数量
方法: 跑。方法要求: 如果汽车的轮子数量少于4个则显示汽车不能正常运行,如果是4个汽车则可以跑起来。
Factory的属性和方法。
属性:名字、地址
方法:修理汽车(修理汽车的轮胎数量)
编写汽车类、修理厂类和测试类。
示例代码
public class Car { String name; int num; String color; public void run(){ if(num==4){ System.out.println("跑啦......"); }else{ System.out.println("汽车不能正常运行,请修理"); } } }
public class CarFactory { String name; String address; public void repairCar(Car c){ c.num=4; //完成了修理工作 System.out.println("车修好了"); } }
public class Test { public static void main(String[] args) { Car car = new Car(); //创建汽车 car.name="Smart"; //设置属性 car.color="黑色"; car.num=3; CarFactory factory = new CarFactory(); //创建修理厂 factory.repairCar(car); car.run(); //调用方法 } } |
(10)匿名对象
匿名对象:没有名字的实体,也就是该实体没有对应的变量名引用。
匿名对象的用途
1、当对象对方法进行一次调用的时候,可以使用匿名对象对代码进行简化。
为什么只调用方法,而不调用属性呢?因为匿名对象调用属性没意义。
如果对象要多成员进行多次调用,必须给对象起个名字。不能再使用匿名对象。
2、匿名对象可以实际参数进行传递。
匿名对象的简单演示
new Car().num=5;
new Car().clor="blue";
两个new 是两个不同的对象,在堆内存中有不同的空间,相互不相互干扰。
匿名对象的使用
1、当只使用一次时可以使用匿名对象。执行完毕到;后该对象就变成了垃圾。
new Car().run();
2、执行方法时,可以将匿名对象作为实际参数,传递进去。
(11)形参和实参
形参:形式参数(声明方法时,方法中声明的参数)
实参:实际参数(调用方法时,实际传给方法的参数)
注意:形参的改变,不会影响实参
示例代码
public class Demo_参数问题 { public void fun1(int x){ // 这个方法的作用就是将传入的int型参数加上100 x = x+100; } public void fun2(Student stu){ stu.age=30; } }
public class Student { int id; String name; int age; }
public class Test_Demo_参数问题 { public static void main(String[] args) { Demo_参数问题 dd = new Demo_参数问题(); int a = 100; dd.fun1(a); System.out.println(a); // 100--- "形参的改变,不会影响实参"——传入时传入的是a的一个拷贝
Student s = new Student(); s.id=1; s.name="小毛"; s.age=20; //System.out.println(s+"<<<<"); dd.fun2(s); //System.out.println(s+">>>>"); System.out.println(s.id); System.out.println(s.name); System.out.println(s.age); // 20? 30? 形参的改变影响了实参?
// 两个错误:第一,形参并没有改变,形参是stu而不是stu的age 第二,查看的不是实参,实参是s而不是s的age } } |
二、封装
1、为什么要封装
我们日常使用的电脑主机,把cpu、内存、主板等等都封装到机箱里面去。假如没有机箱的话的出现什么问题?主机、主板全部都散落在一处,然后开机没有开机按钮,那么需要我们直接操作接跳线才能把电脑开启。这样子的话假如操作不慎的话,会让机器损坏危险,那么假如用机箱封装起来的话,那么就不需要这样子做了。体现了封装的---安全特性。
你拿电脑去加内存,可以直接给电脑给维修的人,等他加好内存了之后。你拿到的还是那个机箱,里面发生了怎样子的变化你并不知道。封装的第二个好处-将变化隔离。
在机箱里面提供一个开机按钮,而不需要你直接使用跳线开机的话,体现了封装的—便于使用的特性。
只要机箱提供了一个开机的功能,然后无论这个机箱拿到哪里去,都可以使用这个开机的功能.体现了封装的---提供重复性的特性。
不使用封装的问题:Person类,年龄赋值问题。
示例代码
public class Person {
int id; String name; int age; public void eat(){ System.out.println("吃饭...."); } } Person p2 = new Person(); p2.id=2; p2.name="小邓"; p2.age = -19; // 年龄赋予了非法值 |
2、如何封装
Java中,使用private关键字对属性进行封装。
封装后的属性将不能直接访问?那么如何访问?
每个被封装的属性,都应该提供相应的set和get方法(setter/getter)
案例:定义Person类,属性包括:学号,姓名,年龄。封装这些,属性,并提供相应的setter和getter。
示例代码
public class Person { private int id; private String name; private int age; public void setId(int x){ id = x; } public int getId(){ return id; }
public void setName(String str){ name = str; } public String getName(){ return name; } public void setAge(int x){ if(x<0){ System.out.println("你的赋值不合适,已经把年龄默认设置为18了"); age = 18; // 当非法赋值时,赋age为18 }else{ age = x; } } public int getAge(){ return age; } public void eat(){ System.out.println("吃饭...."); } } |
3、private的含义
private是一个权限修饰符,代表最小权限。
可以修饰成员变量和成员方法。
被private修饰后的成员变量和成员方法,只在本类中才能访问。
4、封装的好处
隐藏了类的具体实现
操作简单
提高对象数据的安全性
- 构造方法
1、构造方法概念
又称为构造器,C++称为构造函数,Java中称为构造方法或构造器。
构造方法是一个对象刚刚出生时,调用的第一个方法。(出生的洗礼)
它一般从事一些初始化的工作。
2、构造方法的特征
名字必与类名相同。
参数可有可无,可多可少。
没有返回值,也不是void。
new 的时候被自动调用。创建对象时自动调用。
示例代码
public class Student { private int id; private String name; private int age; private String address;
public Student(){ //System.out.println("Student对象创建了"); } } |
3、构造方法的作用
构造方法作用:对对象进行初始化
我们人出生的时候,有些人出生之后再起名字的,但是有些人一旦出生就已经起好名字了。那么我们在Java里面怎么在对象一旦创建就赋值呢?
案例: 定义Teacher类型,属性有id、名字和年龄,使用构造方法,完成初始化对象时,给名字和年龄赋值的工作。
示例代码
public class Teacher { private int id; private String name; private int age; public Teacher(){ // 构造方法 System.out.println("Teacher的对象出生了..."); id = 101; name = "张三丰"; age = 200;
} public void setId(int x){ id = x; } public int getId(){ return id; } public void setName(String str){ name = str; } public String getName(){ return name; } public void setAge(int x){ age = x; } public int getAge(){ return age; } } |
4、构造方法细节
1. 当类中没有定义构造方法时,系统会指定给该类加上一个空参数的构造方法。这个是类中默认的构造方法。当类中如果自定义了构造方法,这时默认的构造方法就没有了。
2.在一个类中可以定义多个构造方法,以进行不同的初始化。多个构造方法存在于类中,是以重载的形式体现的。因为构造方法的名称都相同。
5、初始化代码块
类似构造方法,也是用来初始化对象的成员变量的,是类里面可以定义的第四种成员。(前三种依次是成员变量、方法和构造方法)
格式
class 类名{ { 初始化块; } } |
构造方法已经能初始化对象了,为什么还要有初始化块啊?
初始化块初始化对象的时期优先于构造方法,所以当多个构造方法拥有同样的初始化语句时,可以把该语句统一提到初始化块中定义,以免相同的初始化语句分散到各个构造方法中引起代码重复、凌乱。
示例代码
class Student { { // 初始化代码块——在创建对象时,自动调用 -----在构造方法之前执行,所以可以将多个构造方法中相同的代码放入代码块中 //System.out.println("初始化代码块<<<<>>>>>"); System.out.println("Student对象创建了"); } public Student(){ //System.out.println("Student对象创建了"); } public Student(int a,int b){ //System.out.println("Student对象创建了"); } public Student(int a,String str1,int b,String str2){ //构造方法重载(overload) //System.out.println("Student对象创建了"); id = a; name = str1; age = b; address = str2; } } |
四、this关键字
1、问题引入
我们发现 setXxx 方法中的形参名字并不符合见名知意的规定,那么如果修改成与成员变量名一致,是否就见名知意了呢?代码如下:
public class Student { private String name; private int age;
public void setName(String name) { name = name; }
public void setAge(int age) { age = age; } } |
经过修改和测试,我们发现新的问题,成员变量赋值失败了。也就是说,在修改了setXxx() 的形参变量名后,方法并没有给成员变量赋值!这是由于形参变量名与成员变量名重名,导致成员变量名被隐藏,方法中的变量名,无法访问到成员变量,从而赋值失败。所以,我们只能使用this关键字,来解决这个重名问题。
2、this的含义
this代表所在类的当前对象的引用(地址值),即对象自己的引用。
记住 :方法被哪个对象调用,方法中的this就代表那个对象。即谁在调用,this就代表谁。
this,当前对象的默认引用。(调用这个方法的对象的引用)
3、this使用格式
this.成员变量名;
示例代码
public class User { private int id; private String name; private int age;
public void setId(int id){ // 成员变量和方法参数同名 this.id = id; //this.id 成员变量 id 方法参数 }
public int getId(){ return this.id; }
public void setName(String name){ this.name = name; }
public String getName(){ return name; }
public void setAge(int age){ this.age = age; }
public int getAge(){ return age; }
public void sayHello(){ System.out.println("hello........"); }
public void fun1(){ //sayHello(); this.sayHello(); } } |
4、调用构造方法
在一个类中,其中一个构造方法调用其他构造方法可以使用this关键字。
格式:
this() 或 this(参数)
注意:调用时,必须放在构造方法的第一句(非注释内容)
示例代码
public User(int id,String name,int age){ //构造方法重载
this(); //必须放在第一行 System.out.println("User类的三个参数的构造方法"); this.id = id; this.name = name; this.age = age; } |
5、作用总结
1、调用成员变量,用来解决成员变量和局部变量同名的问题。
2、调用方法,简化代码编写(IDE工具代码提示功能)。
3、在构造方法中调用其他构造方法。(注意:在构造方法中调用其他构造方法时,this语句必须方法在第一句)。
五、方法重载(overload)
1、概念
方法重载是指,在同一个类中,方法名相同,参数列表不同的方法。(与方法的访问控制符和方法的返回值类型无关)
2、为什么要重载
为了节约词汇,把相近的概念用相同的词汇表达。这样便于记忆,可以根据参数的类型来区分是哪个方法。
- 重载的列子
class 电视机{ … public void 换频道(int x){ … } public void 换频道() … } x.换频道(); x.换频道(8); |
作业
1、什么是面向对象?
- 是一种编程思想
- 和面向过程的区别
- 面向对象的好处
- 面向对象的特征
- 举例子
2、面向对象的三大思想特征是什么?
3、什么是类,什么是对象?
4、如何使用类中的成员变量和成员方法?
5、成员变量和局部变量的区别有哪些?
6、什么是匿名对象?什么时候使用?
7、什么是封装?封装的好处、原则分别是什么?
8、this的作用是什么?
9、根据如下需求,完成代码(按照标准格式写:属性私有,提供get、Set方法),然后在测试类中测试。
需求一:
手机类Phone
属性:品牌brand,价格price
行为:打电话call,发短信sendMessage,玩游戏,playGame
需求二:
人类Person
属性:姓名name,年龄age,性别gender
行为:学习study,睡觉sleep
需求三:
动物类Animal
属性:姓名name,年龄age
行为:吃饭eat
需求四:
狗类Dog
属性:姓名name,年龄age
行为:吃饭eat,看家lookHome
需求五:
猫类Cat
属性:姓名name,年龄age
行为:吃饭eat,抓老鼠catchMouse
需求六:
学生类Student
属性:语文成绩chinese,数学成绩math,英语成绩english
行为:求总成绩的方法getSum()
需求七:
长方形类
属性:
行为:求取长方形的周长和面积