面向对象概念
在学习面向对象之前,我们可以先了解一下面向过程。
面向过程是一种编程思想,它强调的是过程,意思是我们做任何事,都需要亲力亲为。
面向对象也是一种编程思想,相对于面向过程,我们的身份可以由原来问题的执行者变为指挥者,进而把生活中很多复杂的问题变得简单化。
面向过程强调的是过程,比如,把大象装冰箱,一共分3步:
第1步:打开冰箱门
第2步:把大象放进去
第3步:关上冰箱门
而面向对象强调的是结果,比如:
谁负责把大象装进去?
有没有发现,如果是面向对象的话,干这件事的主体并不是你自己,你变成了一个指挥者?
再比如,衣服脏了,我们可以让女盆友帮忙洗,不需要关注中间过程是怎么洗的,就可以拿到干净的衣服,当然,这首先需要有一个对象(加油哦)~
还有,当我们想吃一道菜,其实并不需考虑这道菜是怎么做的,怎么送达的,只需点菜即可.传菜和做菜都有具体的对象来完成具体的功能.我们不需要关注实现的过程,只需要关注结果就好。
这就是我们所说的面向对象的编程思想(OOP,Object Oriented Programming)
如果面试官问什么是面向对象?你答万物皆对象!额,不建议这样做哈,因为我们还没到大佬的这个高度,还是最好举例。
就像是你说 : 空即是色 色即是空…信你个鬼鬼
2 面向对象的三大特征
- 封装: 把相关的数据封装成一个“类”组件
- 继承: 是子类自动共享父类属性和方法,这是类之间的一种关系
- 多态: 增强软件的灵活性和重用性
3 类和对象
3.1 类
- Java语言最基本单位就是类,相当于类型。
- 类是一类事物抽取共同属性与功能形成的。
- 可以理解为模板或者设计图纸。
注意:类在现实世界并不存在,它只是一种对象的数据类型
3.2 对象
每个对象具有三个特点:对象的属性,对象的功能和对象的标识。
- 对象的属性用来描述对象的基本特征。
- 对象的功能用来描述对象的可以完成的操作。
- 对象的标识是指每个对象在内存中都有一个唯一的地址值用于与其他对象进行区分,类似于我们的身份证号。
3.3 类和对象的关系
- 我们先创建类,再通过类创建出对象
- 我们可以通过一个类创建出多个对象
- 类是抽象的,对象是具体的
3.4 练习:类的创建使用
在编写代码之前,我们需要分析下需求:
比如我们要把手机这一类事物抽象成代码:
那么这个事物的类型就是"手机",可以用类来描述.
类中包含的就是手机抽取出来的共性的属性与功能.
手机的属性:颜色,尺寸,品牌,价格
手机的功能功能:打电话,发短信,听音乐
我们通过class关键字创建类,通过new关键字创建对象。
接下来我们开始编码吧!
创建包: cn.tedu.oop
创建类: TestCreateClass.java
package cn.tedu.oop;
/**本类用作面向对象入门案例
* 设计手机这一类事物:
* 分析属性:品牌 价格 尺寸 颜色
* 分析功能:打电话 发短信 看直播*/
/**在一个java文件中可以写多个class`,但是,被public修饰的class只能有一个
* 而且要求这个公共类的名字必须与文件的名字保持一致*/
public class TestCreateClass {
public static void main(String[] args) {
//help-findAction 或者 Alt+7
//4.创建手机类的对象p1
Phone p1 = new Phone();
//5.通过手机类对象调用手机类的功能
p1.call();
p1.message();
p1.video();
//6.通过手机类对象打印查看属性值
System.out.println(p1.color);//null
System.out.println(p1.price);//0.0
System.out.println(p1.size);//0.0
System.out.println(p1.brand);//null
}
}
//1.通过class关键字创建手机类--用来描述手机这一类事物--属性+功能
class Phone{
//2.定义手机类的属性--用成员变量来描述--位置:类里方法外
String brand;//品牌
double price;//价格
double size;//尺寸
String color;//颜色
//3.定义手机类的功能--用方法来描述--格式:修饰符 返回值类型 方法名(参数列表){方法体}
public void call(){
System.out.println("正在打电话~");
}
public void message(){
System.out.println("正在发短信!");
}
public void video(){
System.out.println("正在看直播~");
}
}
3.5 对象在内存中的存储
Java把内存分成5大区域,我们重点关注栈和堆。
- 一般来讲局部变量存在栈中,方法执行完毕内存就被释放
- 对象(new出来的东西)存在堆中,对象不再被使用时,内存才会被释放
- 每个堆内存的元素都有地址值
- 对象中的属性都是成员变量,是有默认值的
TIPS: 栈与队列指的是一种数据的结构。
栈:先进后出(FILO – First In Last Out)
队列:先进先出(FIFO – First In First Out)
对象的创建过程分析:
Phone p = new Phone(); 这句代码,再内存中会发生什么呢?
1.在栈内存中开辟一块空间,存放引用类型Phone类型的变量p
2.在堆内存中开辟一块空间,存放Phone类型的对象
3.要给这个对象进行初始化,比如:String brand = null;
4.当对象准备好以后,会生成一个唯一的地址值,然后将此地址值交给引用类型的变量p来保存
5.如果以后想要操作此对象的各种资源,可以通过p变量保存的地址值找到该对象,比如:p.call(); p.price = 66.6;
3.6 练习2:创建多个对象
package cn.tedu.oop;
/**本类用作面向对象入门案例
* 设计手机这一类事物:
* 分析属性:品牌 价格 尺寸 颜色
* 分析功能:打电话 发短信 看直播*/
/**在一个java文件中可以写多个class`,但是,被public修饰的class只能有一个
* 而且要求这个公共类的名字必须与文件的名字保持一致*/
public class TestCreateClass {
public static void main(String[] args) {
//help-findAction 或者 Alt+7
//4.创建手机类的对象p1
Phone p1 = new Phone();
//5.通过手机类对象调用手机类的功能
p1.call();
p1.message();
p1.video();
//6.通过手机类对象打印查看属性值
System.out.println(p1.color);//null
System.out.println(p1.price);//0.0
System.out.println(p1.size);//0.0
System.out.println(p1.brand);//null
//7.创建手机类的第2个对象p2
Phone p2 = new Phone();
//8.通过p2对象,调用Phone类的3个方法
p2.call();
p2.message();
p2.video();
//9.给p2对象的4个属性赋值
p2.brand = "HUAWEI";
p2.color = "中国红";
p2.price = 6666.66;
p2.size = 5.6;
//10.打印查看p2对象的4个属性值
System.out.println(p2.brand);
System.out.println(p2.price);
System.out.println(p2.color);
System.out.println(p2.size);
//11.查看两个对象的地址值
System.out.println(p1);//cn.tedu.oop.Phone@1b6d3586
System.out.println(p2);//cn.tedu.oop.Phone@4554617c
}
}
//1.通过class关键字创建手机类--用来描述手机这一类事物--属性+功能
class Phone{
//2.定义手机类的属性--用成员变量来描述--位置:类里方法外
String brand;//品牌
double price;//价格
double size;//尺寸
String color;//颜色
//3.定义手机类的功能--用方法来描述--格式:修饰符 返回值类型 方法名(参数列表){方法体}
public void call(){
System.out.println("正在打电话~");
}
public void message(){
System.out.println("正在发短信!");
}
public void video(){
System.out.println("正在看直播~");
}
}
p2.brand = “HUAWEI”;
就是先到栈内存中找到p2中保存的唯一的地址值
然后根据地址值找到对应的Phone对象,并对其对应的属性值进行修改
p2.eat();
也是先到栈内存中找到p2中保存的唯一的地址值
然后根据地址值找到对应Phone对象,执行Phone对象的eat()方法
4 封装
4.1 概述
封装是隐藏对象的属性和实现细节,仅仅对外提供公共的访问方式,比如类和方法
好处:
- 提高安全性
- 提高重用性
4.2 private关键字
是一个权限修饰符 ,可以用来修饰成员变量和成员方法.被私有化的成员只能在本类中访问
4.3.1练习:封装的必要性
创建包: cn.tedu.oop
创建类: TestPrivate1.java
package cn.tedu.oop;
/*本类用于测试封装的必要性*/
public class TestPrivate1 {
public static void main(String[] args) {
//3.创建用户类的对象
User u = new User();
//4.修改对象的属性值
u.name = "李逵";
/*需要封装属性,如果不封装的话,就可以直接修改属性的值,不安全*/
//u.money = 999999999;
//5.查看修改后的属性值
System.out.println(u.name);
//System.out.println(u.money);
//6.4调用两个方法修改和查看属性值
u.setMoney(8888888.88);
System.out.println(u.queryMoney());
}
}
//1.创建一个用户类User
class User{
//2.定义用户类的属性
String name;
//6.1封装属性--通过private关键字封装属性
private double money = 10000;
//6.2提供方法1:查询当前账户的余额
public double queryMoney(){
/*后续可以添加权限校验的操作*/
return money;
}
//6.3提供方法2:修改当前账户的余额
public void setMoney(double money){
/*后续可以添加权限校验的操作*/
/*当本类的成员变量与局部变量同名时
可以使用this关键字指定本类的成员变量*/
this.money = money;
}
}
4.3.2 练习:封装学生案例
创建包: cn.tedu.oop
创建类: TestPrivate2.java
package cn.tedu.oop;
/*本类用于练习OOP的第一大特性:封装*/
public class TestPrivate2 {
public static void main(String[] args) {
//4.创建学生类对象s
Student s = new Student();
//5.通过对象修改并查看属性值
s.sno = 1;
//s.name = "黄飞鸿";
//s.subject = "Java培优";
System.out.println(s.sno);
//System.out.println(s.name);
//System.out.println(s.subject);
//6.通过对象调用方法
s.study();
s.eat();
s.sleep();
//7.3使用刚刚生成的set()设置值方法与get()获取值方法
s.setName("十三姨");
s.setSubject("美容美发");
System.out.println(s.getName());
System.out.println(s.getSubject());
}
}
//1.定义类描述学生这一类型Student
class Student {
//2.特征:学号sno 姓名name 科目subject
//7.1 封装属性--用private修饰属性
int sno;
private String name;
private String subject;
//7.2提供被封装属性的get与set方法
//右键->Generate->Getter and Setter->Shift选择属性->OK
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
//3.定义学生的功能:学习 吃饭 睡觉
public void study() {
System.out.println("正在学习中...");
}
public void eat() {
System.out.println("吃饭ing...");
}
public void sleep() {
System.out.println("我一点也不想睡觉,就想学Java!");
}
}
4.3.3 练习:封装方法测试
创建包: cn.tedu.oop
创建类: TestPrivate3.java
package cn.tedu.oop;
/*本类用于测试方法的封装*/
public class TestPrivate3 {
public static void main(String[] args) {
//4.创建对象测试
Apple a = new Apple();
//5.没有封装方法时,调用没有限制
//a.eat();//封装eat(),此处调用报错
a.clean();
}
}
//1.创建苹果类
class Apple{
//2.定义方法1
public void clean(){
System.out.println("苹果还是要洗洗的~");
//6.在已有的公共方法clean()中调用被封装eat()方法的功能
eat();
}
//3.定义方法2
private void eat(){
System.out.println("要吃苹果啦~");
}
}
TIPS:如何封装?封装后的资源如何访问?
我们可以使用private关键字来封装成员变量与方法
如何访问私有资源?
关于成员变量:
setXxx – 对外提供公共的设置值方式
getXxx – 对外提供公共的获取值方式
关于成员方法:
把私有方法放在公共方法里供外界调用即可
5 拓展:OOP综合练习
创建包:cn.tedu.oop
创建类:TestCar
package cn.tedu.oop;
/*本类用于面向对象的巩固练习*/
public class TestCar {
//创建程序的入口函数main()
public static void main(String[] args) {
//3.创建汽车类对象c
Car c = new Car();
//4.通过汽车类对象c设置属性值
// c.color = "暗夜紫";
// c.brand = "BMW";
// c.price = 200;
// c.length = 0.2;
//5.查看刚刚设置好的属性值
// System.out.println(c.brand);
// System.out.println(c.price);
// System.out.println(c.color);
// System.out.println(c.length);
//6.通过c对象调用汽车类的方法
c.start();
//c.stop();
//7.3调用提供的set与get方法,设置并获取对应属性的值
c.setBrand("特斯拉");
c.setColor("black");
c.setPrice(200.02);
c.setLength(3);
System.out.println(c.getBrand());
System.out.println(c.getColor());
System.out.println(c.getLength());
System.out.println(c.getPrice());
//8.3 调用公共方法来实现私有方法功能的使用
c.start();
}
}
//1.抽象汽车这一类事物的属性与行为,封装成一个类组件
class Car{
//2.属性--用成员变量来描述
//7.1封装所有的属性值--使用private修饰
private String color;
private String brand;
private double price;
private double length;
//7.2 生成所有属性的get与set方法
/*右键空白处->Generate->Getter and Setter->按住Shift全选所有属性生成即可*/
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
//3.行为--用方法来描述
//8.2 可以在本类公共的方法里,调用私有方法
public void start(){
System.out.println("汽车开动了~");
stop();//我们通过方法名+参数列表确定要调用哪个方法
}
//8.1封装方法,通过private修饰符
private void stop(){
System.out.println("汽车停止了~");
}
}
6 访问控制符
用来控制一个类,或者类中的成员的访问范围。
TIPS:default是表示不写修饰符,默认,如果写default单词来修饰会报错
拓展7 匿名对象
没有名字的对象,是对象的简化表示形式。
使用场景:
当被调用的对象只调用一次时(多次会创建多个对象浪费内存)
Demo d = new Demo();
d.sleep();
d.game();
//这个d就是对象的名字。
也可以写成:
new Demo().show();//创建了一个对象调方法
new Demo().game();//又创建了一个对象调方法