面向过程和面向对象的区别
“面向过程”(Procedure Oriented)是一种以过程为中心的编程思想,简称 OP。“面向过程” 也可称之为“面向记录”编程思想,就是分析出解决问题所需要的步骤,然后用函数把这些步 骤一步一步实现,使用的时候一个一个依次调用就可以了。所以面向过程的编程方式关注点不 在“事物”上,而是做这件事分几步,先做什么,后做什么。例如:早晨起来:起床、穿衣、 洗漱、上班,只要按照这个步骤来,就能实现“一天”的功能,整个这个过程中关注的是一步 一步怎么做,并没有关注“人”这个事物。再例如:开门、调整座椅、系好安全带、踩离合、 启动、挂档、给油,只要按照这个步骤来,车就走了,显然关注点还是在步骤上,只要实现每 一步就行,整个过程并没有关注“汽车”这个事物。
“面向对象” (Object Oriented) 是一种 以对象为中心的编程思想,简称 OO。 随着计算机技 术的不断提高,计算机被用于解决越来越复杂的问题。 一切事物皆对象,通过面向对象的方式, 将现实世界的事物抽象成对象。 通过面向对象的方法,更利于用人理解的方式对复杂系统进行 分析、设计与编程。同时,面向对象能有效提高编程的效率,通过封装技术,可以像搭积木的 一样快速开发出一个全新的系统。面向对象将对象作为程序的基本单元,将程序和数据封装其 中,以提高软件的重用性、灵活性和扩展性。 使用面向对象编程思想开发系统,在现代开发中会将面向对象贯穿整个过程,一般包括: OOA/OOD/OOP:- OOA:面向对象分析(Object-Oriented Analysis)
- OOD:面向对象设计(Object-Oriented Design)
- OOP:面向对象编程(Object-Oriented Programming)
面向过程(POP) 与 面向对象(OOP)
二者都是一种思想,面向对象是相对于面向过程而言的。面向过程,强调的 是功能行为,以函数为最小单位,考虑怎么做。面向对象,将功能封装进对 象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
面向对象的三大特征- 封装 (Encapsulation)
- 继承 (Inheritance)
- 多态 (Polymorphism)
- 根据问题需要,选择问题所针对的现实世界中的实体。
- 从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类。
- 把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序
- 语言,把类构造成计算机能够识别和处理的数据结构。
- 将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。
面向对象编程思想中关注点是“对象”或者“事物”,那么在编程语言当中要想创建对象则必须先有类,那么类和对象分别是什么,它们的区别和联系是什么呢?
类(Class)和对象(Object)是面向对象的核心概念。
- 类是对一类事物的描述,是抽象的、概念上的定义。例如:“明星”是一个类。
- 对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。“刘德华”就是一个对象。“沈腾”、“赵本山”、“宋丹丹”都是实际存在的对象。
可以理解为:类 = 抽象概念的人;对象 = 实实在在的某个人
- 面向对象程序设计的重点是类的设计
- 类的设计,其实就是类的成员的设计
笑星类都有姓名、 性别、年龄等状态信息(属性),他们还有一个共同的行为就是“演出”(方法)。但当具体 到某个对象上之后,我们发现姓名是不同的,性别是不同的,年龄也是不同的,演出的效果也 是不同的。所以我们在访问姓名、性别、年龄的时候,必须先有笑星对象,通过真实存在的笑 星对象去访问他的属性,包括“演出”的时候,只有“笑星”类是不行的,必须先有笑星对象, 让笑星对象去执行“演出”这个动作。
通过类可以创建对象,对象又被称为实例(instance),这个过程也可以称为实例化。对象具有共同特征,进行抽象形成了类,所以从对象到类称为抽象。
通过以上的描述,我们得知常见的类的成员有 属性和方法,而属性描述的是状态,方法描述的是行为动作。
Field = 属性 = 成员变量,Method = (成员)方法 = 函数
行为动作以方法的形式存在,那属性以什么形式存在呢?例如:姓名、性别、年龄,变量用来存储数据。不错,对象的属性以变量形式存在,并且 这里所说的变量是我们之前提过的“成员变量当中的实例变量”。
为什么是实例变量呢,实例变量就是对象级别的变量,这样的变量要求必须先存在对象,通过对象才能访问。
例如:“中 国人”这个类,有一个属性是“身份证号”,每一个中国人的“身份证号”都是不一样的,所 以身份证号必须使用一个真实存在的“中国人对象”来访问。不能使用“中国人”这个类去访 问身份证号。一个类可以实例化 N 多个对象,假设通过“中国人”这个类创建了 100 个“中 国人对象”,那么“身份证号”必然会有 100 个实例变量空间去存储
类的语法格式
Java 自定义Person类, 步骤如下:
- 定义类(考虑修饰符、类名)
- 编写类的属性(考虑修饰符、属性类型、属性名、初始化值)
- 编写类的方法(考虑修饰符、返回值类型、方法名、形参等)
public class Person {
//属性name,age,isMale
// 成员变量
String name;
int age = 1;
boolean isMale;
//成员方法
public void eat() {
System.out.println("人可以吃饭");
}
public void sleep() {
System.out.println("人可以睡觉");
}
public void talk(String language) {
System.out.println("人可以说话,使用的是:" + language);
}
}
对象的创建和使用
类定义之后,就可以使用类这个“模板”来创造“对象”了,一个类是可以创建多个对象 的哦!怎么创建呢,语法是什么?其实语法格式很简单:new 类名 () ,这样就可以完成对象的创建了。俗话说,你想要什么 java 都可以给你,想要啥你就 new 啥。对象的创建
创建自定义Person类的对象
public class PersonTest {
public static void main(String[] args) {
//2. 创建Person类的对象
Person p1 = new Person();
//Scanner scanner = new Scanner(System.in);
//调用对象的结构:属性、方法
//调用属性:“对象.属性”
p1.name = "Tom";
p1.isMale = true;
System.out.println(p1.name);
//调用方法:“对象.方法”
p1.eat();
p1.sleep();
p1.talk("Chinese");
//*******************************
Person p2 = new Person();
System.out.println(p2.name);//null
System.out.println(p2.isMale);
//*******************************
//将p1变量保存的对象地址值赋给p3,导致p1和p3指向了堆空间中的同一个对象实体。
Person p3 = p1;
System.out.println(p3.name);//Tom
//给age属性赋值
p3.age = 10;
System.out.println(p1.age);//10
}
}
注意事项:
- 创建对象语法: 类名 对象名 = new 类名();
- 类、数组都是引用数据类型,引用数据类型的变量中存储的是对象的地址,或者说指向堆中对象的首地址。
- 匿名对象:我们也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做匿名对象。匿名对象只能使用一次。
- 使用“对象名.对象成员”的方式访问对象成员(包括属性和方法)
- 如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的(非static)属性。意味着:如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值。
- 属性的类型可以是Java的任意类型,包括基本数据类型、引用数据类型(类、接口、数组等) 。如果属性是引用类型,则给其赋值的是其对应的内存地址值。
- 在一个类中的访问机制:类中的方法可以直接访问类中的成员变量。 (例外:static方法访问非static,编译不通过。)
- 在不同类中的访问机制:先创建要访问类的对象,再用对象访问类中定义的成员。
对象的创建和使用:内存解析
程序计数器:
- 概念:可以看做当前线程所执行的字节码的行号指示器。程序计数器是CPU中的寄存器,它包含每一个线程下一条要执行的指令的地址 。
- 特点:线程私有的内存
- 概念:描述的是 java 方法执行的内存模型。(每个方法在执行的时候会创建一个 栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每个方法 从调用直至完成的过程,就对应一个栈帧从入栈到出栈的过程。)虚拟机栈用于存储局部变量等。局部变量表存放了编译期可知长度的各种基本数据类型(boolean、byte、char 、 short 、 int 、 float 、 long 、double)、对象引用(reference类型,它不等同于对象本身,是对象在堆内存的首地址)。 方法执行完,自动释放。
- 特点 :线程 私 有, 生 命 周期 和 线 程 相同 。 这 个 区域 会 出 现 两种 异 常 : *Error 异常: 若线 程请求 的深 度大于 虚拟 机所允 许的 深度 。 OutOfMemoryError 异常:若虚拟机可以动态扩展,如果扩展是无法申请到足够的 内存。
- 概念:它与虚拟机栈所发挥的作用是相似的,区别是 java 虚拟机栈为执行 java 方 法服务,而本地方法栈是为本地方法服务。当程序中调用了native的本地方法时,本地方法执行期间的内存区域 。
- 特点:线程私有,也会抛出两类异常:*Error 和 OutOfMemoryError。
- 概念:是被所有线程共享的一块区域,在虚拟机启动时创建。
- 特点:线程共享,存放的是对象实例(所有的对象实例和数组),GC 管理的主要区域。可以处于物理上不连续的内存空间。
- 概念:存储已被虚拟机加载的类信息、常量、静态变量,即时编译器编译后的代 码等数据。
- 特点:线程共享的区域,抛出异常 OutOfMemory 异常:当方法区无法满足内存分 配需求的时候。
类的成员之一:属性
属性的类型可以是Java的任意类型,包括基本数据类型、引用数据类型(类、接口、数组等)
变量的分类 成员变量(属性)和局部变量的区别
在 java 语言当中,当实例变量 没有手动赋值,在创建对象的时候,也就是说在 new 的时候,系统会对实例变量默认赋值, 它们的默认值请参考下表:
代码示例
/*
* 类中属性的使用
*
* 属性(成员变量) vs 局部变量
* 1.相同点:
* 1.1 定义变量的格式:数据类型 变量名 = 变量值
* 1.2 先声明,后使用
* 1.3 变量都有其对应的作用域
*
*
* 2.不同点:
* 2.1 在类中声明的位置的不同
* 属性:直接定义在类的一对{}内
* 局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
*
* 2.2 关于权限修饰符的不同
* 属性:可以在声明属性时,指明其权限,使用权限修饰符。
* 常用的权限修饰符:private、public、缺省、protected --->封装性
* 目前,大家声明属性时,都使用缺省就可以了。
* 局部变量:不可以使用权限修饰符。
*
* 2.3 默认初始化值的情况:
* 属性:类的属性,根据其类型,都有默认初始化值。
* 整型(byte、short、int、long):0
* 浮点型(float、double):0.0
* 字符型(char):0 (或'\u0000')
* 布尔型(boolean):false
*
* 引用数据类型(类、数组、接口):null
*
* 局部变量:没有默认初始化值。
* 意味着,我们在调用局部变量之前,一定要显式赋值。
* 特别地:形参在调用时,我们赋值即可。
*
* 2.4 在内存中加载的位置:
* 属性:加载到堆空间中 (非static)
* 局部变量:加载到栈空间
*
*/
public class UserTest {
public static void main(String[] args) {
User u1 = new User();
System.out.println(u1.name);
System.out.println(u1.age);
System.out.println(u1.isMale);
u1.talk("韩语");
u1.eat();
}
}
class User{
//属性(或成员变量)
String name;
public int age;
boolean isMale;
public void talk(String language){//language:形参,也是局部变量
System.out.println("我们使用" + language + "进行交流");
}
public void eat(){
String food = "烙饼";//局部变量
System.out.println("北方人喜欢吃:" + food);
}
}
成员变量的分类
- 实例变量:没有static修饰,也叫对象属性,属于某个对象的,通过对象来使用
- 类变量:有static修饰,也叫类变量,属于整个类的,不是属于某个实例
实例变量和类变量相同点:
- 声明的位置都是在类中方法外。
实例变量和类变量不同点:
如何在类外面访问成员变量
类变量有2种访问方式,如下所示:
类名.静态成员变量 //推荐
对象名.静态成员变量 //不推荐
实例变量只能使用下面这种方式
对象名.静态成员变量
总结:
在Java中,一共就三种变量,他们分别是静态变量 丶成员变量丶局部变量 。我们可以从代码声明位置丶所在内存位置丶生命周期丶是否有默认值丶作用域(有效范围)大小几个方面去区分他们。
声明位置和方式
- 静态变量:在类中方法外,并且有static修饰
- 实例变量:在类中方法外,没有static修饰
- 局部变量:在方法体{}中或方法的形参列表、代码块中
在内存中存储的位置不同
- 静态变量:方法区
- 实例变量:堆
- 局部变量:栈
生命周期
- 静态变量:和类的生命周期一样,因为它的值是该类所有对象共享的,早于对象的创建而存在。
- 实例变量:和对象的生命周期一样,随着对象的创建而存在,随着对象被GC回收而消亡, 而且每一个对象的实例变量是独立的。
- 局部变量:和方法调用的生命周期一样,每一次方法被调用而在存在,随着方法执行的结束而消亡, 而且每一次方法调用都是独立。
作用域
- 静态变量和实例变量:不谈作用域 在本类中,唯一的限制,静态方法或静态代码块中不能使用非静态的,其他都可以直接使用。 在其他类中,能不能使用看修饰符(public,protected,private等)
- 局部变量:有作用域 出了作用域就不能使用
修饰符
- 静态变量:很多 public,protected,private,final,volatile等,一定有的是static
- 实例变量 public,protected,private,final,volatile,transient等
- 局部变量 final
public,protected,private:权限修饰符 final:是否是常量,即值是否可以修改 volatile:和多线程有关 transient:是否序列化,和IO有关
默认值
- 静态变量:有默认值
- 实例变量:有默认值
- 局部变量:没有,必须初始化 其中的形参比较特殊,靠实参给它初始化。