标题:Java面向对象编程
文章目录
- 标题:Java面向对象编程
- 前言:面向对象的三条主线
- 一、面向对象编程概述
- 1.1 程序设计思路
- 1.2 Java语言的基本元素:类和对象
- 1.3 对象的内存解析
- 二、类的成员1—成员变量
- 2.1 “变量”定义&分类
- 2.2 实例变量(属性)VS局部变量
- 2.3 变量的内存分析
- 三、类的成员2—方法
- 3.1 方法介绍&理解
- 3.2 方法的返回值&调用方法
- 3.3 方法调用内存分析
- 四、类的成员3—构造器
- 4.1
- 五、类的成员4—内部类
- 5.1
- 六、类的成员5—代码块
- 6.1
- 七、面向对象特征1—封装
- 7.1
- 八、面向对象特征2—继承
- 8.1
- 九、面向对象特征3—多态
- 9.1
前言:面向对象的三条主线
- Java类及类的成员:(重点)属性(因为是对象,所以不说范围更广的成员变量了)、方法、构造器;(熟悉)代码块、内部类
类的成员之间是可以相互包含的 - 面向对象的特征:封装、继承、多态、(抽象)
- 其他关键字的使用:this、super、package、import、static、final、interface、abstract等
类的成员之一成员变量:定义在方法外的,分为静态的(属于类的)、非静态的(属于实例的)。而方法等结构体中定义的变量叫做局部变量,局部变量也可以分为静态的和非静态的。
非静态的成员变量:又叫做属性、实例变量、field(字段、域),因为静态的成员变量是属于类的,而不是实例的!
总结:类中称为成员变量(静态、非静态都可),但是当实例化类后也可以说是成员变量(只不过这个范围比较大),准确地应该说是属性/非静态的成员变量/实例变量。属性是非静态的成员变量。
静态方法(所有对象共享的)称类方法,非静态方法又称实例方法。
静态的可以被类调用,非静态的可以被不同的对象调用!
一、面向对象编程概述
1.1 程序设计思路
1、定义:是软件开发中的一类编程风格、开发范式。
- 面向过程的程序设计思想(Process-Oriented Programming, POP):关注操作数据的步骤,某个过程的实现代码重复出现,将这个过程抽取为一个函数,简化冗余代码。
比如C语言:以函数为组织单位。是一种“ 执行者思维 ”,适合解决简单问题。扩展能力差、后期维护难度较大。 - 面向对象OOP:关注类(属性/行为),在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,用类来表示。如Java、C#、C++、Python、Ruby和PHP等
比如Java:是一种“ 设计者思维 ”,适合解决复杂问题。代码扩展性强、可维护性高。
面向对象可以帮助我们从宏观上把握、从整体上分析整个系统。 但是,具体到实现部分的微观操 作(就是一个个方法),仍然需要面向过程的思路去处理。 当需求单一,或者简单时,我们一步步去操作没问题,并且效率也挺高。可随着需求的更改,功能的增多,发现需要面对每一个步骤很麻烦了,这时就开始思索,能不能 把这些步骤和功能进行封装,封装时根据不同的功能,进行不同的封装,功能类似的封装在一起。这样结构就清晰了很多。用的时候,找到对应的类就可以了。这就是面向对象的思想。
1.2 Java语言的基本元素:类和对象
1、类和对象概述
- 类:具有
相同特征
的事物的抽象描述,是 抽象的 、概念上的定义。 - 对象:实际存在的该类事物的每个个体 ,是具体的 ,因而也称为实例(instance) 。
2、类的成员:(重点)属性/方法/构造/(熟悉)内部类/代码块
设计类:本质就是设计类的成员
类的成员:类,是一组相关 属性 和 行为
的集合(基本成员:属性、行为——对应类中的成员变量(非静态)、方法)
- 属性:即类中的成员变量(非静态),表示该类事物的状态信息。
非静态的成员变量<=>属性<=> Field - 行为:即类中的成员方法,表示该类事物要做什么操作,或者基于事物的状态能做什么。对应
(成员)方法 <=>函数 <=> Method
3、 使用面向对象步骤:定义/创建/调用
- 步骤1:定义类:使用class关键字
- 步骤2:实例化类(又称创建类的对象/实例):使用new关键字(
使用new创建的实体对象都在堆中
)。
注意还有一种匿名对象:以不定义对象的句柄,而直接调用这个对象的方法。用途:只用一次/作为方法实参。 - 步骤3:通过对象调用其内部声明的属性(实例变量/非静态的成员变量)或方法完成相关功能:对象是类的一个实例,必然具备该类事物的属性和行为(即方法)。
访问对象成员语法格式:" 对象名.属性(这里的说法比较准确,而非成员变量) " 、 " 对象名.方法 "
使用面向对象的步骤:
//步骤1:定义类
[修饰符] class 类名{
属性声明;
方法声明;
}
//步骤2:创建对象
//方式1:给创建的对象命名
//把创建的对象用一个引用数据类型的变量保存起来,这样就可以反复使用这个对象了
类名 对象名 = new 类名();
//方式2:
new 类名()//也称为匿名对象
//调用方法
new Person().shout();
图示理解
1.3 对象的内存解析
先理解引用数据类型:引用数据类型的变量中存储的是对象的地址(它指向堆中对象的首地址堆中)。引用类型的对象名存储堆中的首地址(其格式为:“类型@对象的hashCode值"。方法执行完,自动释放),基本数据类型的变量名存储具体的值。
引用类型理解:虚拟机栈存储对象名(对象引用),该变量名的值是堆中的首地址值。真正的实体存放在堆中。
创建一个类的多个对象(比如p1、p2),则每个对象都拥有当前类的一套"副本"(即属性)。当通过一个对象修改其属性时,不会影响其它对象此属性的值。 但是如果p1=p2,此时他们指向堆中的同一个地址,p2改变时,p1也会随之改变。
1、JVM内存结构划分:虚拟机栈、本地方法栈、堆、方法区、程序计数器
HotSpot Java虚拟机的架构图。JVM理解为一种规范,HotSpot JVM是一种实现。这里关注运行时数据区部分(Runtime Data Area)。
需要存储的:变量(局部变量、成员变量【属性、静态成员变量】、常量)——这些又包含基本数据类型&引用数据类型、对象实体、方法(类中的方法、引用方法【实例对象的方法】)。所有的这些又分为静态的和非静态的。
主要区域有:
- 堆(Heap) :new出来的结构(数组实体、对象实体)、对象的属性(类的非静态成员变量)
- 虚拟机栈(Stack) :方法中定义的(非静态)局部变量(首先压入栈中的是main方法)——局部变量:基本数据类型、对象引用(reference类型);对象调用方法(引用方法)
- 局部变量:定义在(方法/构造器/内部类/代码块等内或其形参)中,存储编译期可知长度的各种基本数据类型(boolean、byte、char、short、int、float、long、double),还有引用类型
- 方法区(Method Area) :存放类的模板。比如Person类的模板。用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
总结:只要是局部变量就在栈中,只要是成员变量(非静态、也称属性/实例变量)就在堆中!不管java成员之间如何相互定义、引用。即如果是对象中的局部变量也是在栈中。
//首先进栈的是main方法
class Student{
static int num = 0;//静态的成员变量
int number;//非静态的成员变量,属性
int state;
//slee表示方法
void sleep(int i){//i表示局部变量(基本数据类型)
}
}
class shixian{
//首先进栈的main方法帧,只有这样才能实现一系列的调用、实例化等等!
public static void main(string[] args){
static int num = 0;//静态的局部变量
int num1 = 2;//局部变量——基本数据类型
Student[] stus = new Student[3];//局部变量:stus为引用数据类型——数组类型
for (inti=0;i< stus.length; i++){//i表示局部变量,stus.length表示属性
stusli] = new Student();//stus数组存储堆的数组的首地址,每个地址中存储的又是Students对象在堆中的地址
}
stus[0].number = 1;//对象的属性,又称作实例变量!
stus[0].state = 5;
stus[0].sleep(6);//引用方法,调用对象的方法
}
}
2、内存举例
- 每一个方法的调用对应的是一个栈帧
- 程序开始:main方法进栈,其相关的局部变量、对象引用(指向对象对内存地址)进栈
- 对象调用方法:对象的方法进栈
- 对象赋值对象:p3=p1,得到p1和p3指向同一个堆内存的实体对象首地址
- 对象数组内存解析:数组的元素类型是对象,首先栈中存数组对象引用,数组元素中存实体对象的地址
总结:
- 堆:凡是new出来的结构(对象、数组)都放在堆空间中。 对象的属性存放在堆空间中。
- 创建一个类的多个对象(比如p1、p2),每个对象在堆空间有一个对象实体,每个对象实体中保存着一份类的属性。当通过一个对象修改其属性时,不会影响其它对象此属性的值。
- 当声明一个新的变量使用现有的对象进行赋值时(比如p3 = p1),此时并没有在堆空间中创 建新的对象。而是两个变量共同指向了堆空间中同一个对象。当通过一个对象修改属性时, 会影响另外一个对象对此属性的调用。
二、类的成员1—成员变量
静态的成员变量又称属性、实例变量、field
2.1 “变量”定义&分类
1、变量分类:变量必须先声明后赋值再使用,作用域内有效
注意:这里是变量的分类,不是成员变量!
- 数据类型不同:基本数据类型(8种)、引用数据类型(数组、类、接口、枚举、注解、记录)
- 变量在类中声明的位置不同:
成员变量
:static将其分类为静态的(属于类的,所有对象共用这一个
)、非静态的(属于实例的,又称为实例变量、属性
)。- 局部变量(方法/构造器/内部类/代码块等内或其形参):也分为静态和非静态的,同时根据放的位置不同也可以分类。
- static修饰:静态变量、非静态变量
总结:以上三种分类可以组合
2.2 实例变量(属性)VS局部变量
1、实例变量(属性)VS局部变量
- 相同点
- 必须先声明后使用,且声明格式相同:数据类型 变量名 = 初始化值
- 都有其对应的作用域,只在作用域内是有效的。
- 不同点
- 声明位置&内存位置:定义在类中方法外,随着对象的创建存储在堆中;方法体或其形参列表/块中,随着方法的调用存储在栈中。
- 作用域&生命周期:实例变量本类中直接调用,其他类中"对象名.属性",而局部变量超出作用域就不生效了。
- 与对象声明周期一致,对象创建-GC回收,回收对象其实就是回收对象实体的这些属性。每一个对象的实例变量都是独立的。
- 方法栈帧入栈→局部变量在栈中分配→方法栈帧出栈,局部变量消亡。即从方法调用到方法执行结束。每一次方法调用都是独立。
- 修饰符:public,protected,private,final,volatile,transient等;final,因为局部变量作用域就是方法,如果声明像前面的那种也没意思,外面根本也不能访问!
- 默认值:属性有默认值(不显示赋值也有值);局部变量没有默认值,必须手动初始化。其中的形参比较特殊,依靠实参给它初始化!
2、实例变量(属性)的默认初始化赋值
- 什么时候给实例变量赋默认值?
当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值。 - 各个类型的对象属性的默认值
- 整数(int/byte/short):0;long:0L,因为java中整数的默认类型是int型
- 浮点型:float:0.0F,double:0.0,java中默认的数据类型是double
- char:0或 ‘\u0000’
- boolean:false(0)
- 引用类型:null
2.3 变量的内存分析
只要是局部变量就在栈中,只要是成员变量(非静态、也称属性/实例变量)就在堆中!不管java成员之间如何相互定义、引用。即如果是对象中的局部变量也是在栈中。
三、类的成员2—方法
方法又称函数、method。方法不调用不执行,每调用一次执行一次(进栈-出栈)
为什么需要方法:比如游戏中人物每次出拳就是一个重复的动作,可以单独抽取出来成为一个方法!
静态方法只有通过类才能被调用,非静态方法(又称实例方法)可以被不同的对象调用!
3.1 方法介绍&理解
1、方法定义:方法 是类或对象行为特征的抽象,用来完成某个功能操作。也称为函数或过程 。将功能封装为方法是为了可以实现代码重用,减少冗余,简化代码。必须定义在类中,不能独立存在!在C/js语言中是可以独立存在的
2、方法构成:方法头 + 方法体
- 方法头:也称方法签名
- [修饰符]:权限修饰符:public、缺省、protected、private;static(是否静态)、abstract(是否抽象)、native、final、synchronized等。
- 返回值类型: 表示方法运行的结果的数据类型,方法执行后将结果返回到调用者。分类:void、有返回值(任何类型,与return搭配)
- 方法名:属于标识符,命名遵循标识符命名规则和规范。
- [形参列表]:表示完成方法体功能时需要外部提供的数据列表。0/多个,形参需指定数据类型和参数名,()不能省,逗号分隔!
- [throws 异常列表]:在异常处理中理解。
- 方法体:方法被调用后要执行的代码(方法功能),必须有{}括起来。
//一个完整的方法 = 方法头 + 方法
[修饰符] 返回值类型 方法名([形参列表])[throws 异常列表(受检查异常)]{
方法体的功能代码
}
3.2 方法的返回值&调用方法
1、方法返回值return语句实现:
- void时,return后不能跟返回值,可以省略
- 不是void时,return 返回值,一定要有。
return在方法中的作用:结束一个方法;结束一个方法的同时,返回数据给方法的调用者
注意点:在return关键字的直接后面不能声明执行语句,否则会报错Unreachable code!
怎么可以结束循环?
条件不满足;return语句(直接把循环所在的方法都结束了);break。注意continue不行,它只是结束本次循环!
2、方法的调用:
- 静态方法:又称类方法,在同一个类中直接通过方法名调用,不同的类中只能通过类调用,所有对象共享这一个方法。
- 实例化方法:在同一个类中直接通过方法名调用,
不同类中,实例化对象调用实例方法
。
两种方法调用返回值情况:
- 实例方法无返回值:无需定义变量去接收方法的结果
- 实例方法有返回值:定义变量来接收实例方法的返回值,如果没有接收实例方法的返回值那么会导致结果丢失,但是实例方法会正常执行。
3、方法使用的注意点
- 必须先声明后使用,且方法必须定义在类的内部
- 调用一次就执行一次,不调用不执行。
- 方法中可以调用类中的方法或属性,
不可以在方法内部定义方法。
但是方法级别不一样的时候可以,比如static的main方法中定义方法了!
3.3 方法调用内存分析
每一个方法属于一个栈帧,栈帧是栈的基本结构!
- 方法没有被调用的时候,都在方法区中的字节码文件(.class)中存储。
- 方法被调用的时候,需要进入到栈内存中运行。方法每调用一次就会在栈中有一个入栈动作,即给当前方法开辟一块独立的内存区域,用于存储当前方法的局部变量的值。
- 当方法执行结束后,会释放该内存,称为出栈,如果方法有返回值,就会把结果返回调用处,如果没有返回值,就直接结束,回到调用处继续执行下一条指令。
- 栈结构:先进后出,后进先出。
注意:调用太多的方法(比如递归太多次时),可能会导致栈中溢出
!
- 方法调用一个从栈中出去一个,这里为了形象一点还是放在里面的。如果在方法中调用方法不是的,比如main方法一直在里面,在main方法中调用了很多其他的方法。递归也不是的。
- 实例方法中的属性可以通过"对象名.属性操作",也可以在对象类中定义方法来操作相关的属性,那么当调用该方法时,也可以实现对属性的操作。比如:(1)创建Person类的对象,设置该对象的name、age和sex属性,调用study方法,输出字符串“studying”,调用showAge()方法显示age值,调用addAge()方法给对象的age属性值增加2岁。 (2)创建第二个对象,执行上述操作,体会同一个类的不同对象之间的关系