Java 基础入门【第五章 面向对象基础】

第五章 面向对象基础

面向对象
类与对象
变量对比
封装
构造方法
this关键字


1 面向对象


OOP(object oriented programming),面向对象编程,是一种以对象为中心的编程思想,通过借助对象实现具体的功能,将大问题拆分成小问题,然后借助不同对象分别解决,最终实现功能
POP(procedure oriented Programming),面向过程编程,是一种以过程为中心的编程思想,靠自己一步一步去实现功能,需要对每个步骤精确控制,强调按步骤实现功能,先分析解决问题所需步骤,再自定义方法实现每个步骤功能,然后依次调用方法,最终实现功能
生活案例:
小明早上起床,想要吃鸡蛋饼。分别用两种不同思想去解决该问题,具体如
下:
面向过程
小明先准备面、鸡蛋等原材料,再和面,然后开火烙饼,最后成功吃到鸡
蛋饼
面向对象
小明到街上找到摊煎饼的大娘,让大娘做个鸡蛋饼,最后吃到了鸡蛋饼
面向对象特点:
更符合人类思想习惯的思想
利用对象去实现功能
将复杂事情简单化
针对要解决问题的用户而言,可以把大问题拆解成小问题,分别指挥不同
的对象去解决小问题
程序员的角色由执行者变成了指挥者
大问题:
造出一辆新能源汽车,可以自动驾驶
拆解成多个小问题:
合作伙伴1:专门研发 电池
合作伙伴2:专门研发 底盘
合作伙伴3:专门研发 电池管理系统
合作伙伴4:专门研发 自动驾驶系统
...
面向对象开发:
就是不断创建对象,使用对象,指挥对象做事情实现功能
原则:如果有对象,就指挥对象实现功能;如果没有,就创建对象,然后
再指挥

面向对象语言特征:
封装(encapsulation) 信息隐蔽
继承(inheritance) 代码重用
多态(polymorphism) 灵活、接口统

Java语言、C++、Python等都是面向对象程序设计语言中的一种,所以都
具有这三种特征
后面的课程中会对每个特征进行详细的学习


2 对象理解


自然界中客观存在的事物皆为对象 ,万物皆对象
放眼望去,我们身边的能看到的东西,都是对象,例如桌子、话筒、笔记本
电脑、电脑键盘、你、你的鞋子、眼睛等等。
观察下图,列出图上存在的对象:


理解对象
任何事物都是一个对象(object)
对象由对象组成
每个对象都有属性(静态的描述信息)、行为(动态的功能描述)
具有相似属性和行为的对象可以归为一类


3 类的定义


具有相同属性和行为的对象可以抽象为类(数据类型的一种)
类的组成:
属性:指事物的特征,静态描述,例如:手机有品牌,价格,尺寸
行为:指事物所具有的功能,动态描述,例如:手机可以打电话,也可以
发短信
类的理解:
类是对现实生活中一类具有共同属性和行为的事物的抽象
类是对象的数据类型,类是具有相同属性和行为的一组对象的集合
简单理解:类就是对现实事物的一种描述
类是引用数据类型中的一种

现实生活中,一切皆为对象,其中有些对象的属性和行为是类似的,比如大
家桌子上放的那些对象,它们的属性类似,都包含屏幕、键盘、触摸板、内存
条等,也具有相似的功能,能够开机、安装运行软件、写代码、看视频等,这
些具有相同属性和行为的对象,我们可以抽象为笔记本类。
结论:类是对象的抽象,对象是类的实例
类定义格式:
[ p u b l i c ] c l a s s 类 名 {
//属 性 , 可 以 包 含 多个
[权 限 修 饰 符 ] 数 据 类型 成 员 变 量 名 ;
//行 为 , 可 以 包 含 多个
[权 限 修 饰 符 ] 返回 值类 型 成 员 方 法名 (形 参 列表 ) {
具体功能实现
}
//构造器,可有可无,暂时不用写,后续章节讨论
[权 限 修 饰 符 ] 类 名 (形 参 列 表 ) {
初始化语句
}
}

类定义步骤:
定义类
编写类的成员变量
编写类的成员方法
具体案例:

public class Student {
// 属 性 : 姓 名 , 年 龄
// 成员变量: 跟之前 定义 变量的 格式 一样 , 只不过位 置发生 了改 变, 放到了类
中的方法之外
String name;
int age;
// 行 为 : 打 招 呼
// 成 员 方 法 : 跟 之 前 定 义 方 法 的 格 式 一 样 , 只 不 过 去 掉 了 static关 键 字
public void sayHello()
{ System.out.println("hello"
);
}
}

上述案例中,我们定义了学生类Student;
注意,Student是一种数据类型,是自定义类类型,属于引用类型;
类类型使用时跟int、double、String等类型类似,都必须先定义变量并赋值,
才能使用;
类类型和基本数据类型定义变量的方式不同,描述方式也不同,具体如下:
//基 本 数据 类 型 定义变量
i n t a = 1 0 ; //定 义 一 个 int类 型 变 量 a
double d = 2.3;
//类 类 型 定 义 变 量
//定 义 一 个 double类 型 变 量 d
S t u d e n t s 1 = n e w S t u de n t (); //实 例 化 一 个 S t u d e n t 类 对 象 s 1
S t u d e n t s 2 = n e w S t u d e n t (); //实 例 化 一 个 S t u d e n t类 对 象 s 2

 


4 对象使用


创建对象格式:
类 名 对 象 名 = n e w 类 名 ();
调用成员格式:
对 象 名 .成 员 变 量
对 象 名 .成 员 方 法 ();

案例演示 :

public class Test04_Student {
/*
创建对象的格式:
类 名 对 象 名 = ne w 类 名 ();
调用成员变量的格式:
对象名.变量名
调用成员方法的格式:
对 象 名 .方 法 名 ();
*/
public static void main(String[] args) {
// 实 例 化 对 象
// 固 定 格 式 : 类 名 对 象 名 = n e w 类 名 ();
Student stu = new Student();
// 输出对象 属性的 默认 值
// 对 象属 性 访问 格式 : 对象 名.变 量名
System.out.println(stu.name); // null
System.out.println(stu.age); // 0
// 给 对 象 属 性 赋 值
s t u .n a m e = "张 三 ";
stu.age = 23;
// 再 次 输 出 对 象 属 性值
S y s t e m . o u t . p r i n t l n (s t u . n a m e ); // 张 三
System.out.println(stu.age); // 23
// 对 象 成 员 方 法 调 用
// 固 定 格 式 : 对 象 名 .方 法 名 (实 际 参 数 列 表 );
stu.sayHello();
// 输出结果:全类名@对象内存地址
// 全 类 名 : 包 名 .类 名
System.out.println(stu);
//com.briup.chap05.test.Student@7852e922 }
}

类使用总结:
一般Java程序会写两个类:基础类,测试类
基础类就是我们要实现封装出来的那个类
测试类就是包含main方法的类
注意:只能在一个类中定义main方法,其是程序的入口,必须唯一
数据类型理解:
        Java中对数据类型的描述和定义,都是抽象的,每一种数据类型,都是对一
类数据的抽象描述,描述这种数据的基本特点。
        比如 int 类型(系统提供),是对计算机中一个32位数据的定义,描述这种
数据的基本特点和表达的含义。又比如 String 类型(系统提供),是对程序
中的字符串这种数据的定义,描述了作为一个字符串数据,应该具有哪些属
性、行为和特点。
刚才操作的 Student 类型(程序员自定义),对学生这类数据进行描述,学
生具有 name 和 age 静态特征,也具有 study 这样的动态功能。
int 、 String 和 Student 都是对数据的抽象描述,不能当做具体的数据
使用,如果想使用的这些数据的话,必须使用 int 或 String 类型定义变
量,使用 Student 实例化对象,然后使用变量或对象来参与运算。
类和对象的关系:
通过前面的学习可知,类是一组相关属性和行为的集合,它是对某一种具体事
物的抽象描述。
也可以把类看作一个模板,我们使用的对象,就是按照这个模板中的定义,来
进行创建的。
类是对一类事物的描述,是抽象的
对象是一类事物的实例,是具体的

类是对象的模板,对象是类的实体
案例理解:
抽象出来猫类:(这就相等于定义了一个类)
属性:名字、体重、年龄、颜色
行为:走、跑、叫
我家里的小猫皮皮:(这就是一个具体的对象)
名字:皮皮,体重:3KG,年龄:3岁,颜色:白色
皮皮可以走,也可以跑,也可以喵喵的叫
可以看出,皮皮这个小猫(对象),完全符合上面对猫的定义的一切属性
和行为。
案例理解:
下图是手机图纸,定义了手机一些特征(相当于定义了类)


按着上面的图纸,制造出来的俩台具体的手机(相当于创建了手机类的俩个
不同的对象)


一个类的对象,也就是这个类的具体实例。如果有需要,可以根据手机类(图
纸),创建出无数个具体的对象(手机)。
结论:类是一种抽象的数据描述,对象是类的一个具体的实例。
案例实现

定义一个手机类,属性含品牌、价格,具备打电话、发短信的功能。
再定义一个手机测试类,在手机测试类中通过对象完成成员变量和成员方法
的使用。
基础类定义:

public class Phone {
// 品 牌 , 价 格
String brand;
int price;
// 打 电 话 , 发 短 信
public void call(){
S y s t e m . o u t .p r i n t l n ( " 打 电 话 " ); }
public void sendMessage(String name, String msg){
S y s t e m .o u t .p r i n t l n (" 给 " + n a m e + " 发 短 信 : " + m s g );
}
}

测试类定义:

public class Test04_Phone {
public static void main(String[] args) {
// 1 . 创 建 对 象
Phone p = new Phone();
// 2. 给 成 员 变 量 进 行 赋 值
p .b r a n d = " 小 米 ";
p.price = 2999;
// 3. 打 印 赋 值 后 的 成 员 变 量
S y s t e m .o u t .p r i n t l n ( " 手 机 品 牌 : " + p .b r a n d + ", 价 格 : " +
p.price);
// 4 . 调 用 成 员 方 法
p.call();
p .s e n d Me s s a g e ("老 墨 ", "我 要 吃 鱼 ");
}
}


5 对象内存


观察下面案例,理解stu对象的内存构成

public class Test05_Memory {
public static void main(String[] args) {
//实 例 化 一 个 对 象
Student stu = new Student();
stu.name = "tom";
stu.sayHello();
}
}

单个对象内存图:


程序运行过程:
1. 加载main方法并运行:在栈区开辟方法帧,支持main方法的运行
2. 执行main方法代码,用到Student类,则加载该类:把Student.class加载到
方法区
3. 创建引用类型变量:在栈空间中开辟一块内存空间,用stu标识
4. 在堆中开辟内存创建对象,并给属性赋上默认初始值
5. 将堆空间对象内存地址值放入stu标识的内存区域中
6. 对象属性赋值:将"tom"和20放入堆空间对象内存区域内
7. 对象方法调用:找到方法区sayHello方法对应的代码,执行
8. main方法继续执行,遇到 } ,程序执行结束
引用类型理解:
上述案例中,stu是一个引用类型变量,其对应栈区的一块内存区域,其中
放的是一个引用值(地址值),通过这个引用值,系统可以找到对象实际
开辟的内存空间(堆区),进而进行对象属性操作或方法调用。
思考:如果创建出多个对象,其内存构成是什么样子的?
多个对象案例:

//创 建 多 个 对 象
public class Test05_TwoObject {
public static void main(String[] args) {
//创 建 对 象 s1
Student s1 = new Student();
//给对象name属性赋值
s1.name = "lucy";
Student s2 = new Student();
s2.name = "jack";
s2.age = 20;
s1.sayHello();
s2.study();
}
}

多个对象内存构成:


对象内存结论:
系统会为每个对象开辟单独的内存空间(堆空间),用来存储对象的属性。
类的成员方法存储在方法区,只保留一份,只要是该类的对象,都可以调
用。


6 变量对比


到目前为止,我们学习了两种变量:成员变量、局部变量。
观察下面代码,指出哪些是成员变量,哪些是局部变量。

//导 入 类
import java.util.Scanner;
public class Test06_Variate
{ int num;
public void setNum(int n) {
num = n;
}
public static void main(String[] args) {
//1.从 键 盘 录 入 一 个 整 形 数
Scanner sc = new Scanner(System.in);
System.out.println("input a num: ");
int number = sc.nextInt();
//2.实例化对象,然后用上述整形数给其属性赋 值
Test06_Variate t = new Test06_Variate();
t.setNum(number);
//3.输 出 对 象 属 性 值
System.out.println(t.num);
}
}

成员、局部变量区别:
定义位置不同
成员变量:类中方法外
局部变量:方法内部或方法声明上(形参列表)
内存中位置不同
成员变量:堆内存
局部变量:栈内存
生命周期不同
成员变量:随着对象的存在而存在,随着对象的消失而消失
局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
初始化值不同
成员变量:有默认初始化值
局部变量:没有默认初始化值,必须先定义、赋值才能使用
7 封装特性
1)概念理解
封装是面向对象三大特征之一,另外两个是继承,多态
封装是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
其优点如下:
通过方法来控制成员变量的操作,提高了代码的安全性
把代码用方法进行封装,提高了代码的复用性
隐藏代码实现细节,提供公共访问方式,简化操作

生活案例:
电源插座,如果不对电源插座封装,平时用电将会很不安全,容易触电。
笔记本开关按钮,用户不需要关心开机关机底层那些复杂的实现细节,只需
要知道按按钮可以开关机即可。
封装原则:
把不需要对外提供的内容隐藏起来
把属性隐藏,提供公共方法对其访问
2)private
private、public都是权限修饰符,可以用来修饰成员变量、成员方法和构造方
法;
private表示私有,用它修饰类的成员(含成员变量、成员方法),则这些成员
只能在类内(类的成员函数内部)去使用,其他地方不可以操作;
public表示公有,用它修饰类的成员(含成员变量、成员方法),则这些成员
在类内、类外都都可以操作。
3)封装实现
封装步骤:
1. 使用private修饰成员变量
2. 提供对应的setXxx()、getXxx()方法,用pubic修饰
3. 具体使用时,借助对象的setXxx方法给属性赋值,getXxx方法获取属性值
案例展示:


//银 行 账 户 类
class Account {
//步 骤 1 : private修 饰 数 据 成 员
p r i v a t e S t r i n g i d ; //卡 号
p r i v a t e d o u b l e b a l a n c e ; //金 额
//步 骤 2 : 定 义 get|set方 法 , 使 用 public修 饰
public void setBalance(double money)
{ balance = money;
}
public double getBalance() {
return balance;
}
public void setId(String accountId)
{ id = accountId;
}
public String getId()
{ return id;
}
}
public class Test07_Private {
public static void main(String[] args) {
//1.实例化对 象,使用系 统提供的无 参构 造器
Account acc = new Account();
//2.在类外通过对象访 问私有数据成员,编译报错
//acc.id = "001";
//acc.balance = 2000.5;
//步骤3:具体使用时,借助对象的setXxx方法 给属性赋值,getXxx方法
获取属性值
//3.借 助 set方 法 赋 值
acc.setId("001");
acc.setBalance(2000.5);
//4.借 助 get方 法 获 取 属 性 值
S y s t e m . o u t . p r i n t l n ( " 卡 号 : " + a c c . g e t I d ( ) ) ;
S y s t e m . o u t . p r i n t l n ( " 金 额 : " + a c c . g e t B a l a n c e ( ) ) ;
}
}


思考1:上述set方法中,如果方法的形式参数名跟类数据成员名相同,如何进
行赋值?
public void setId(String accountId)
{ id = accountId;
}
解决方案:借助this解决,
上述案例中,我们借助set方法给对象的属性赋值,如果对象的属性特别多,有
20个,我们难道每次要调用20个set方法赋初值吗,有没有更好的初始化属性值
方案?
解决方案:借助构造方法解决,


8 this关键字


在类中的普通成员方法中,可以使用this关键字, 其表示调用当前方法的对象
引用,即哪个对象调用该方法,this就代表哪一个对象。
this关键字用法:
对成员变量和局部变量进行区分
固 定 格 式 : this.数 据 成 员 ;
调用类中的成员方法
固 定 格 式 : this.成 员 方 法 (实 际 参 数 列 表 );
调用类中的其他构造器(后面章节补充)
成员变量与局部变量的区分:
方法的形参如果与成员变量同名
不带this修饰的变量指的是形参
如果要表示成员变量,则必须加this修饰
方法的形参与成员变量不同名
则不带this修饰的变量指的就是成员变量

案例展示:
重新实现Account类,要求使用this关键字,要求成员方法中形式参数名跟类
数据成员名相同。
基础类Account:
package com.briup.chap05.bean;
public class Account {
p r i v a t e S t r i n g i d ; //卡 号
p r i v a t e d o u b l e b a l a n c e ; //金 额
public void setId(String id) {
//方法的形参如果与成员变量同名,不带 this修饰的变量指的是形参,而
不是成员变量
//如 果 要 表 示 成 员 变 量 , 则 必 须 加 this修 饰
S y s t e m . o u t . p r i n t l n ( " 参 数 i d : " + i d ) ;
System.out.println("this.id: " + this.id);
this.id = id;
}
public String getId() {
//如果形参没有与成员变量同名,不带this修饰的变量指的是成员变量
return id;
//return this.id; }
public void setBalance(double balance)
{ this.balance = balance;
}
public double getBalance()
{ return balance;
}
public void show()
{ System.out.println("id: " +
this.id);
//使 用 this去 调 用 普 通 成 员 方 法
System.out.println("balance: " + this.getBalance()); }
}
测试类:
package com.briup.chap05.test;
import com.briup.chap05.bean.Account;
public class Test08_This {
public static void main(String[] args) {
//1.实 例 化 对 象
Account acc = new Account();
//2.借 助 set方 法 赋 值
acc.setId("001");
acc.setBalance(2300.5);
System.out.println("---------------------");
acc.show();
}
}

 


测试代码较为简单,注意观察注释描述。
this内存构成理解:
public static void main(String[] args)
{ Student stu1 = new
Student("zs",21); stu1.sayHello();
Student stu2 = new Student("tom",19);
stu2.sayHello();
}

单个对象内存图


多个对象内存图


观察上图可知:每一个对象中,都有自己的this,和其他对象中的互不影响。
当前执行 stu1.sayHello() 代码的时候,this代表的就是stu1
当前执行 stu2.sayHello() 代码的时候,this代表的就是stu2
结论:成员方法被哪个对象调用,方法中的this就代表那个对象,即谁调用,
this就代表谁。


思考:在生活中, 我们每一个人心中的this,指的是哪一个汉字?


9 构造方法


构造方法可以对对象进行初始化操作,即为对象开辟内存空间的同时,给对象
的成员赋初值。
构造方法定义及调用:
//固 定 定 义 格 式
[修 饰 符 ] 类 名 (参 数 列 表 )
{初 始 化 语 句 s;
}
//构造方法调用格式,实参列表可以为空
类 名 对 象 = new 类 名 (实 参 列 表 );

注意事项:
构造方法一般使用 public 修饰
构造方法没有返回值类型,连 void 都没有
构造方法名和类名相同(区分大小写)
构造方法可以重载
案例演示:

public class Teacher {
private String name;
private double salary;
//无 参 构 造 方 法
public Teacher() {
//构造器中一般只写赋值语句,不放输出语句,此处写出是为了方便学生
理解构造方法过程
System.out.println("Teacher() ..."); }
//有参构造方法,注意:构造方法可以重载
public Teacher(String name, double salary)
{ System.out.println("Teacher(String,double) ..."
);
//赋 值 语 句
this.name = name;
this.salary = salary;
}
public void show()
{ System.out.println("name: " + name);
System.out.println("salary: " + salary);
}
}

执行时机 :
创建对象的时候会被自动调用,每创建一个对象,就会执行一次构造方法
不要,也不能手动调用构造方法
功能测试:

import com.briup.chap05.bean.Teacher;
public class Test09_Constructor {
public static void main(String[] args) {
//借助无参构造器 实例化对象
Teacher t1 = new Teacher();
t1.show();
System.out.println("-----------------");
//借助有参构造器 实例化对象
Teacher t2 = new Teacher("kevin", 13099.5);
t2.show();
//手动调用构造方法,错误用法,无法通过编译
//t2.Teacher(); }
}

 


观察运行效果可知,创建对象时构造器会被自动调用(实例化对象时指定的
那个构造方法),其完成了对象属性的初始化。
注意事项补充:
用户不定义构造方法,则系统会提供一个无参构造方法
p u b l i c 类 名 ( ) {
//什 么 都 不 干
}
用户定义构造方法,则系统不再提供无参构造方法
用户不需要也不可以主动调用构造方法,系统会自动调用
对象创建步骤(理解即可):
public static void main(String[] args)
{ Student s = new
Student(“zhang”,23);
}
1. 将Student.class文件加载到内存方法区
2. 在main栈帧中开辟一块内存,用s标识(定义s变量)
3. 在堆中开辟内存(new 对象)
4. 对堆空间的属性进行默认初始值(null,0)
5. 对属性进行显式初始化(如果存在的话,如 private int age = 10;)
6. 调用构造方法,用("zhang",23)给属性赋值
7. 将堆中对象的内存地址赋值给s内存,对象创建完成


10 this补充


this特殊用法:
在构造方法中,可以借助this关键字调用其他构造方法。
具 体 格 式 为 : this(实 际 参 数 列 表 );
案例展示:
基础类补充:

public class Teacher {
/ / 省 略 . . .
//该 类 已 经 成 功 定 义 2参 构 造 器 , 定 义 过 程 省 略 ...
//public Teacher(String name, double salary);
//this特殊 用 法 : 在构 造 方 法 中, 调 用 其 他构 造 方 法
public Teacher(String name) {
//必须是构造方法的第一行有效代码
this(name,0); }
}
测试类代码:


public class Test10_This {
public static void main(String[] args) {
//调 用 Teacher(String)构 造 方 法 实 例 化 对 象
//底 层 借 助 T e ac he r(St ri ng , do ub le ) 实 现
Teacher t = new Teacher("larry");
t.show();
}
}

构造方法Teacher(String)底层借助Teacher(String, double)实现了
功能。
注意: this(实际参数列表) 必须是构造方法中的第一行有效代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时肆 知还

你的鼓励将是我创作的最大动力,

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值