面向过程与面向对象
1.面向过程:
首先怎么理解面向过程:举个例子,拿买笔记本电脑而言,最新的配置,各品牌有没有新上市的电脑,各品牌中的各个型号哪个性价比高,哪一种类型比较适合我们,搞清楚之后,我们得去商城,看电商,哪里的价格合适。从准备买到买到手,所有的事情都一手解决,这我们就可以理解为是 面向过程。一系列过程对于不懂电脑的人而言,可能查半天也弄不清楚。这时就需要寻求帮助,找一个懂电脑的朋友,告诉他你对电脑的需求,上述的问题他可以很快的解决并向你推荐出适合你的电脑,并且可以让他帮你找一个合适的渠道购买。这个朋友对你而言便是面向对象,过程便可以由这个对象去解决。
面向对象是基于面向过程的编程思想
特点:
- 是一种更符合我们思想习惯的思想
- 可以将复杂的事情简单化
- 将我们从执行者变成指挥者
面向对象开发,就是不断的创建对象,使用对象,指挥对象做事情
面向对象设计,其实就是在管理和维护对象之间的关系
面向对象特征,封装,继承,多态
面向过程和面向对象都是人类的常用思考方式。
是不是互斥的? 不是
是不是相互依赖的? 不是 没有纯粹的面向对象 但是有纯粹的面向过程
面向对象的思想其实是基于面向过程
2.对象在需求中的使用
需求:把大象装冰箱里
对象:大象、冰箱 分三步:
- 打开冰箱门
- 将大象装进去
- 关闭冰箱门
分析发现打开、装、关闭都是冰箱的功能。
即冰箱对象具备如下功能:
冰箱打开 冰箱存储 冰箱关闭
用伪代码描述,上述需求中有两个具体的事物 :
大象 和 冰箱
描述大象:
大象 {
}
描述冰箱
冰箱 {
打开(){
//打开的方法
}
存储(大象){
//将大象传进去,储存
}
关闭(){
//关闭的方法
}
}
当把具体的事物描述清楚之后,需要使用这些具体的事物,Java使用具体的事物,需要通过new关键 字来创建这个事物的具体实例
使用对象
- 创建冰箱的对象
冰箱 bx = new 冰箱();
- 调用冰箱的功能
对象.功能();
bx.打开();
bx.存储(new 大象());
bx.关闭()
总结:
3. 先按照名词提炼问题领域中的对象
4. 对对象进行描述,其实就是在明确对象中应该具备的属性和功能
5. 通过new的方法就可以创建该事物的具体对象
6. 通过该对象调用它以后的功能
3.类与对象
学习编程语言的目的,就是为了模拟世界的事物,实现信息化。
如何表示一个现实世界的事物:
- 属性:就是该事务的描述信息(成员变量)
- 行为:就是该事务能够做什么(成员函数)
类:是一系列具有相关属性和行为的事物的集合,是一个抽象的概念
对象:是该类事物的具体表现形式,具体存在的个体
定义类其实就是定义类的成员(成员变量,成员函数)
- 类是对象的模板。它定义对象的属性,并提供用于创建对象的构造方法以及操作对象的普通方法。
- 类也是一种数据类型。可以用它声明对象引用变量。对象引用变量中似乎存放了一个对象,但事实上,它包含的只是对该对象的引用。严格地讲,对象引用变量和对象是不同地,但是大多数情况下,它们地区别是可以忽略地。
4.构造方法:
构造方法在使用new操作符创建对象的时候被调用
构造方法是一种特殊的的方法。它有以下三个特殊性:
- 构造方法必须具备和所在类相同的名字。
- 构造方法没有返回值,甚至连void也没有。
- 构造方法是在创建一个对象使用new操作符时调用。构造方法的作用是初始化对象。
和所有其他方法一样,构造方法也可以重载(也就是说,可以有多个同名的构造方法,但它们要有不同的签名),这样更易于用不同的初始数据值来构造对象。
通常,在不需要写构造方法的情况下,类会提供一个隐藏的无参的默认构造方法,当且仅当类中没有明确定义任何构造方法时才会自动提供它。
class refrigerator{ //冰箱的类
pritave double temperature; //冰箱的属性,温度
refrigerator(){ //无参的构造方法
}
refrigerator(double temperature){ //有参的构造方法,可以在创建对象的时候对冰箱的温度赋值
}
}
创建对象的时候可以对对象进行初始化? 可以
构造函数能否重载? 可以
构造函数有没有返回值? 没有 但是有return
构造函数能否调用其他构造函数? 可以 this(…) 必须在第一行
构造函数之间能够相互调用? 不能 是递归调用,会不停的进栈
构造函数能够调用成员函数? 可以,无非是构造函数中某段代码的封装不应该作为对象的特有行为 需要private
成员函数能否调用构造函数? 不能
既然有了构造函数 还需要setget不?不一定,看具体业务需求
5.成员变量和局部变量的区别
在类中的位置不同
- 成员变量 类的里面,方法的外面
- 局部变量 声明和使用都在方法的内部
在内存中的位置不同
- 成员变量 堆内存中对象的所属空里间
- 局部变量 栈内存中函数的所属空间里
生命周期不同
- 成员变量 随着对象的创建而存在,随着对象的消失而消失
- 局部变量 随着方法的进栈而存在,随着方法的弹栈而消亡
初始化值不同
- 成员变量 在堆内存中有 默认初始化 > 显示初始化 > 针对性初始化
- 局部变量 没有默认的初始化值 必须先定义在赋值后才能使用
调用范围
成员变量 基本全局(不能被静态函数直接调用)
局部变量 在函数中其所属最近的 { } 内
注意:
为避免混淆和错误,除了方法中的参数,不要将实例变量或静态变量的名字作为局部变量名。
6.对象在内存中创建的流程
- 在堆内存中开辟空间并分配地址(空间大小由系统底层控制)
- 对成员变量进行【默认初始化】
- 相应的构造函数进栈
- 先对成员变量进行【显式初始化】
- 再执行构造函数的代码【针对性初始化】
- 构造函数出栈 对象创建完毕 返回地址
注意:
- 引用类型数据域的默认值是 null
- 数值类型数据域的默认值是 0
- boolean 类型数据域的默认值是 false
- char类型数据域的默认值是 ’\u0000‘
- 但是,Java 没有给方法中的局部变置赋默认值
7.形式参数的分类
- 基本数据类型作为形式参数:传值(传值 是常量在常量池中的地址)
- 引用数据类型作为形式参数:传址(对象在堆内存中的地址)
8.匿名对象
匿名对象:就是没有名字的对象,是对象的一种简化表示形式
匿名对象的两种使用情况:
- 对象调用方法仅仅一次的时候
- 作为实际参数传递
9.封装概述
封装概述:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
好处:
- 隐藏实现细节,提供公共的访问方式
- 提高代码的复用性
- 提高安全性
封装原则:
- 将不需要对外提供的内容都隐藏起来
- 把属性隐藏,提供公共方法对其访问
10.private关键字
private关键字是一个权限修饰符,可以修饰成员,被修饰的成员只在本类中才能访问。防止外界直接修改值。
在定义私有数据域的类外的对象是不能访问这个数据域的。
private最常见的应用:
- 把成员变量用private修饰
- 提供对应的get(访问器)和set(修改器),二者根据需求决定是否需要存在
class Demo03{
public static void main(String[] args){
Person p1=new Person();
p1.setAge(25); //通过set接间传值
p1.getAge(); //通过get接间访问
}
}
class Person{
private int age;
private String name;
Person(){
this(0,null);//this(...) 调用当前类的其他构造函数 必须在第一句
print();
}
//通过set方法,避免直接传值,产生出错误地信息
public void setAge(int age){
//局部变量age 成员变量age
if(age<0){
this.age=0;
}else{
this.age=age;
}
}
public int getAge(){
return this.age;
}
}
注意:
为防止数据被篡改以及使类更易于维护,最好将数据域声明为私有的。
11.this关键字
this代表所属类的对象引用,方法被哪个对象调用,this就代表哪个对象。this引用通常是省略掉的。然而,在引用隐藏数据域以及调用一个重载的构造方法的时候,this引用是必须的。
12.对象 演示
class Demo01{
public static void main(String[] args){
Person p=new Person(); //创建默认属性的Person对象
p.show(); //调用Person类中的方法
Person p1=new Person(10,"旺财"); //创建赋值的Person对象
p1.show(); //调用Person类中的方法
//return; //return默认隐藏
}
}
class Person{
private int age; //Person的属性(成员变量)
private String name="宝宝"; //Person的属性(成员变量)
Person(){ //无参的构造方法
}
Person(int age,String name){ //有参的构造方法,将传的age和name赋值给当前所创建的对象
this.age=age; //this指当前对象; .age当前对象的属性
this.name=name;
//return;
}
public void show(){ //对象的行为
System.out.println(age+"岁,叫"+name);
}
}
案例
模拟枪战射击,
分为:玩家,枪,弹夹,子弹 ,4个类;再加一个运行程序的主类,共5个类
玩家
名字; 血量值; 枪; 捡枪(枪); 装弹夹(弹夹); 射击(玩家); 掉血(伤害值)
枪
弹夹; 装弹夹(弹夹); 开枪(玩家)
弹夹
子弹[]; 上子弹(子弹); 出子弹()
子弹
伤害值; 击中(玩家)
class Demo{
public static void main(String[] args){
//创建名为老张,老王血量各100的两个玩家
Player p1=new Player("老张",100);
Player p2=new Player("老王",100);
//老张对老王开枪,没有枪
p1.shoot(p2);
//创建枪,给p1(老张)
Gun gun=new Gun();
p1.takeGun(gun);
//老张对老王开枪,没有弹夹
p1.shoot(p2);
//创建弹夹,给枪上弹夹
Clip clip=new Clip();
p1.loadClip(clip);
//老张对老王开枪,没有子弹
p1.shoot(p2);
System.out.println("=========");
//上10颗子弹
for(int i=1;i<=10;i++){
clip.putBullet(new Bullet());
}
System.out.println("=========");
// //老张对老王连续开枪
for(int i=1;i<=11;i++){
p1.shoot(p2);
}
}
}
//玩家
class Player{
//姓名,血量和枪
private String name;
private int HP;
private Gun gun;
//玩家的构造函数,对创建对象的属性赋值
public Player(String name,int HP){
this.name=name;
this.HP=HP;
this.gun=null;
System.out.println("玩家"+this.name+"诞生,血量"+this.HP);
}
//拿枪
public void takeGun(Gun gun){
//如果没有枪,引用类型默认为null
if(this.gun==null){
this.gun=gun;
System.out.println("玩家"+name+"拿起了一把枪");
}else{
System.out.println("玩家"+name+"已拿枪");
}
}
//上弹夹
public void loadClip(Clip clip){
//判断有没有枪
if(this.gun==null){
System.out.println("玩家"+name+"没有枪,装不了弹夹");
}else{
System.out.println("玩家"+name+"给枪装了弹夹");
this.gun.loadClip(clip);
}
}
//开枪
public void shoot(Player enemy){
if(this.gun==null){
System.out.println("玩家"+name+"没有枪,不能向"+enemy.getName()+"开枪");
}else{
System.out.println("玩家"+name+"向玩家"+enemy.getName()+"开了一枪");
//调用的对象向传入的对象开枪
this.gun.fire(enemy);
}
}
//掉血
public void bloodLoss(int damage){
//当前对象的生命值大于子弹的伤害值,掉血;小于,死亡
if(this.HP>damage){
this.HP-=damage;
System.out.println("玩家"+name+"收到伤害"+damage+",剩余"+this.HP+"血量");
}else{
System.out.println("玩家"+name+"已死亡");
}
}
//get方法,获取姓名,不需要改变姓名所以没有set方法
public String getName(){
return this.name;
}
}
//枪
class Gun{
private Clip clip;
//弹夹的构造函数
public void loadClip(Clip clip){
this.clip=clip;
System.out.println("枪装上了弹夹");
}
//开枪的函数,
public void fire(Player enemy){
if(clip==null){
System.out.println("枪没有弹夹,放了个空枪");
}else{
//有弹夹,创建子弹的对象,如果子弹不为空,则发射
Bullet bullet=clip.getBullet();
if(bullet!=null){
System.out.println("枪向"+enemy.getName()+"发射了一个子弹");
//向传入对象发射子弹
bullet.hit(enemy);
}else{
//没子弹
System.out.println("枪放了个空枪");
}
}
}
}
//弹夹
class Clip{
private Bullet[] bullets;
private int size;
//弹夹的构造方法,创建一个弹夹对象,默认拥有30个子弹空间,size用来表示当前子弹数
public Clip(){
this.bullets=new Bullet[30];
this.size=0;
}
//发射子弹
public Bullet getBullet(){
if(size==0){
System.out.println("弹夹为空");
return null;
}else{
//[1,1,1,1,1,1,1,0,0,0,0,0]
//每发射一次,子弹数-1
Bullet bullet=bullets[size-1];
size--;
System.out.println("弹夹剩余"+size+"/"+bullets.length);
return bullet;
}
}
//上子弹
public void putBullet(Bullet bullet){
if(size==bullets.length){
System.out.println("弹夹已满");
}else{
bullets[size]=bullet;
size++;
System.out.println("弹夹剩余"+size+"/"+bullets.length);
}
}
}
//子弹
class Bullet{
private int damage=30;
//子弹击中对方
public void hit(Player enemy){
System.out.println("一个子弹击中了"+enemy.getName());
//调用的对象掉血,掉血血量为子弹伤害值
enemy.bloodLoss(damage);
}
}