为满足移动端和PC端的双重阅读体验,以及文章质量的保证,开始重构的以及新写的文章都会基于 “语雀” 平台编写,公众号会同步刚发布的文章,但随后的修改或者更新只会在语雀中维护。
👉 点击底部左下角 “阅读原文” 即可跳转到文章最新页面!理想二旬不止@BWH_Steven
面向过程——步骤化
面向对象——行为化(概念相对抽象,可结合下面的例子理解)
例如我们设计一个桌球游戏(略过开球,只考虑中间过程)
A:面向过程方式思考: 把下述的步骤通过函数一步一步实现,这个需求就完成了。(只为演示概念,不细究逻辑问题)。 ① palyer1 击球 —— ② 实现画面击球效果 —— ③ 判断是否进球及有效 —— ④ palyer2击球 —— ⑤ 实现画面击球效果 —— ⑥ 判断是否进球及有效 —— ⑦ 返回步骤 1—— ⑧ 输出游戏结果
B:面向对象方式思考: 经过观察我们可以看到,其实在上面的流程中存在很多共性的地方,所以我们将这些共性部分全集中起来,做成一个通用的结构
我们将繁琐的步骤,通过行为、功能,模块化,这就是面向对象,我们甚至可以利用该程序,分别快速实现8球和斯诺克的不同游戏(只需要修改规则、地图和球色即可,玩家系统,击球效果系统都是一致的)
A:面向过程 优点:性能上它是优于面向对象的,因为类在调用的时候需要实例化,开销过大。 缺点:不易维护、复用、扩展 用途:单片机、嵌入式开发、Linux/Unix等对性能要求较高的地方
B:面向对象 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护 缺点:一般来说性能比面向过程低
低耦合:简单的理解就是说,模块与模块之间尽可能的独立,两者之间的关系尽可能简单,尽量使其独立的完成成一些子功能,这避免了牵一发而动全身的问题。这一部分我们会在面向对象学习结束后进行系统的整理和总结。 总结:只通过教科书后的例题是无法体会到面向过程所存在的问题的,在一些小例程中,面向过程感觉反而会更加的简单,但是一旦面临较大的项目,我们需要编写N个功能相似的函数,函数越来越多,代码量越来越多,你就知道这是一场噩梦了。
说明:关于性能的问题,这里只是在笼统意义上来说,具体性能优劣,需要结合具体程序,环境等进行比对
类:一组相关的属性和行为的集合,是一个抽象的概念。 对象:该类事物的具体表现形式,具体存在的个体。 成员变量:事物的属性 成员方法:事物的行为 上面我们说了这几个概念,那么到底应该怎么理解呢?
所以可以得出结果:类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而真正根据类实例化出具体的对象,就需要占用内存空间了。
A:在类中的位置不同
B:在内存中的位置不同
C:生命周期不同
D:初始化值不同
有一个问题,在我们学习 Java 中内存分配的时候,有这样一句话,“堆内存用来存放 new 创建的对象和数组”。换句话说对象存在于堆中,而成员变量又存在于类中,而且对象是类具体的个体,所以成员变量也存在于堆中,那么问题就来了,同理,是不是方法也和成员变量一样存在于对象中,而局部变量又定义在方法中,岂不就是说,局部变量也存在于堆中呢?这明显与我们上面的定义有区别
解释:一个类可以创建 n 个不同的对象,当我们 new 一个对象后,这个对象实体,已经在堆上分配了内存空间,由于类的成员变量在不同的对象中各不相同(例如,小李和老王的姓名不同),都需要自己各自的存储空间,所以类的成员变量会随着对象存储在堆中,而由于类的方法是所有对象通用的,所以创建对象时,方法还未出现,只有声明,方法里面的局部变量也并没有被创建,只有等到对象使用方法的时候才会被压入栈。
补充:类变量(静态变量)存在于方法区,引用类型的局部变量声明在栈,存储在堆
访问权限 | 类 | 包 | 子类 | 其他包 |
---|---|---|---|---|
public | √ | √ | √ | √ |
protect | √ | √ | √ | |
default | √ | √ | ||
private | √ |
public class Student {
private String name = "BWH_Steven";
private Integer age = 22;
// 是个无参构造,为了演示初始化顺序,特意加了两个赋值语句
public Student (){
name = "阿文";
age = 30;
}
}
public class Test {
public static void main(String[] args) {
Student stu = new Student();
}
}
例如:Student stu = new Student();
其在内存中做了如下的事情:
首先加载 Student.class (编译成字节码文件)文件进内存,在栈内存为 stu 变量开辟一块空间,在堆内存为 Student 类实例化出的学生对象开辟空间,对学生对象的成员变量进行默认初始化(例如 name = null,age = 0 ),对学生对象的成员变量进行显示初始化( 例如name = "BWH_Steven",age = 22),接着就会通过构造方法对学生对象的成员变量赋值(执行构造函数内,我们特意加的赋值语句 name = "阿文",age = 30)学生对象初始化完毕,把对象地址赋值给 stu 变量
static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。—— 《Java编程思想》P86
可以知道,被 static 关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。也就是说,即使没有创建对象也可以进行调用(方法/变量) static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。
static 修饰的方法一般叫做静态方法,静态方法不依赖于对象访问,因此没有 this 的概念(this 代表所在类的对象引用),正因如此静态方法能够访问的成员变量和成员方法也都必须是静态的
类名.A
访问静态方法 A,此时对象还不存在,非静态成员 B 自然也根本不存在,所以就会有问题。调用非静态方法 C 也是如此,你不清楚这个方法 C 中是否调用了费静态变量static 修饰的变量也称作静态变量,静态变量属于类,所以也称为类变量,存储于方法区中的静态区,随着类的加载而加载,消失而消失,可以通过类名调用,也可以通过对象调用。
静态代码块是在类中(方法中不行)使用static关键字和{} 声明的代码块
static {
... 内容
}
执行: 静态代码块在类被加载的时候就运行了,而且只运行一次,并且优先于各种代码块以及构造函数。 作用: 一般情况下,如果有些代码需要在项目启动的时候就执行,这时候 就需要静态代码块。比如一个项目启动需要加载的 很多配置文件等资源,我们就可以都放入静态代码块中。
1.6.3.1 构造代码块(补充) 概念:在java类中使用{}声明的代码块(和静态代码块的区别是少了static关键字) 执行:构造代码块在创建对象时被调用,每次创建对象都会调用一次,但是优先于构造函数执行。 作用 :和构造函数的作用类似,都能对对象进行初始化,并且只创建一个对象,构造代码块都会执行一次。但是反过来,构造函数则不一定每个对象建立时都执行(多个构造函数情况下,建立对象时传入的参数不同则初始化使用对应的构造函数)。 因为每个构造方法执行前, 首先执行构造代码块,所以可以把多个构造方法中相同的代码可以放到这里,
其它部分直接阅读下面的子章节,我会把面相对象中关键的几个概念和知识点分篇讲解。