第四章 面向对象编程(上)
一. 引入
Java面向对象学习的三条主线:
1.Java类及类的成员:属性、方法、构造器;代码块、内部类
2.面向对象的三大特征:封装性、继承性、多态性(、抽象性)
3.其它关键字:this、super、static、final、abstract、interface、package、import等
面向过程POP Vs. 面向对象OOP
Procedure Oriented Programming Object Oriented Programming
e.g. “人把大象装进冰箱”
面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做
①把冰箱打开
②抬起大象,塞进冰箱
③把冰箱门关闭
面向对象:将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做
人{
打开( 冰箱 ){
冰箱.开开( );
}
抬起( 大象 ){
大象.进入(冰箱 );
}
关闭( 冰箱 ){
冰箱.闭合( );
}
}
冰箱{
开开( ){ }
闭合( ){ }
}
大象{
进入( 冰箱 ){ }
}
二. 类和对象
类:对一类事物的描述,是抽象的、概念上的定义
对象:是实际存在的该类事物的每个个体,因而也称为实例(instance)
> 面向对象程序设计的重点是类的设计
> 设计类,就是设计类的成员
属性 = 成员变量 = field = 域、字段
方法 = 成员方法 = 函数 = method
创建类的对象 = 类的实例化 = 实例化类
类和对象的使用(面向对象思想落地的实现):
①创建类,设计类的成员
②创建类的对象
③通过“对象.属性”或者“对象.方法”调用对象的结构
说明:某个类的多个对象有独立的一套类属性( 非static的 ),相互之间互不影响
对象的内存解析:
编译完源程序以后,生成一个或多个字节码文件
我们使用JVM中的类的加载器和解释器对生成的字节码文件进行解释运行。意味着,需要将字节码文件对应的类加载到内存中,涉及到内存解析。
1.类中属性的使用
- 成员变量和局部变量的区别:
注:局部变量没有初始化值,意味着调用局部变量之前一定要显示赋值
非static成员变量加载到内存的堆空间,static变量加载到方法区中
2.类中方法的声明和使用
什么是方法(method、函数):
- 方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中也称为函数或过程。
- 将功能封装为方法的目的是,可以实现代码重用,简化代码
- Java里的方法不能独立存在,所有的方法必须定义在类里。
理解“万事万物皆对象”
1. 在java语言范畴中,我们都将功能、结构等封装到类中,通过类的实例化来调用具体的功能结构
>Scanner,String等
>文件:File
>网络资源:URL
2. 涉及到java语言与前端、后端数据库的交互时,前后端的结构在java层面交互时都体现为类、对象
内存解析的说明
>引用类型的变量,只可能存储两类值:null 或 地址值(含变量的类型)
匿名对象的使用:
1. 理解:我们创建的对象,没有显式的赋给一个变量名。即为匿名对象
2. 特征:匿名对象只能调用一次 e.g. new phone( ).price = 1999;
3. 使用如下
3.方法的重载
定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可
“两同一不同”:同一个类、相同方法名
参数列表不同:参数个数、参数类型不同(参数顺序)
3.1 可变个数形参的方法
> jdk 5.0新增的内容
> 具体使用:
① 可变个数形参的格式: 数据类型 … 变量名 e.g. String … strs
②当调用可变个数形参的方法时,传入的参数个数可以是0, 1, 2….
③可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
e.g. public void show( String s ) 参数明确为一个 ; public void show( String … strs ) 参数个数不确定
④可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载,二者不能并存,方法的定义和调用区别见下图:
⑤可变个数形参在方法的形参中,必须声明在末尾
⑥可变个数形参在方法的形参中,最多只能声明一个可变形参
3.2 关于变量的赋值
> 如果变量是基本数据类型,此时赋值的是变量所保存的数据值
> 如果变量时引用数据类型,此时赋值的是变量所保存的数据的地址值
3.2 方法的形参传递机制:值传递
> 形参:方法定义时,声明的小括号内的参数
> 实参:方法调用时,实际传递给形参的数据
值传递机制:
> 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值
> 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值
三. 面向对象的特征一:封装与隐藏
1.问题的引入
当我们创建一个累的对象以后,我们可以通过“对象.属性”的方式,对对象的属性进行赋值。这里,赋值操作要受到属性的数据类型和存储范围的制约。除此之外,没有其他限制条件。但是,在实际问题中,我们往往需要给属性赋值加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加 e.g. setLegs( ) 同时,我们需要避免用户再使用“对象.属性”的方式对属性进行赋值。则需要将属声明为私有的( private ) —> 此时,针对属性就体现了封装性
2.封装性的体现
我们将类的属性XXX私有化( private ),同时,提供公共的( public )方法来获取( getXXX )和设置( setXXX )
上述只是封装性的一种体现,此外还有:不对外暴露的私有方法,单例模式等等
3.封装性的体现,需要权限修饰符来配合
Java规定的4种权限(从小到大): private、缺省、protected、public
> 具体的,4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类
> 修饰类的话,只能用:缺省、public
> 4种权限修饰符体现了类及类的内部结构在被调用时的可见性的大小
4.类的成员之三:构造器constructor
> 构造器的特征:
- 具有与类相同的名称
- 不声明返回值类型(与声明为void不同)
- 不能被static、final、synchronized、abstrat、native修饰,不能有return语句返回值
> 构造器的作用:创建对象;给对象进行初始化
> 说明:
- 每个类都至少有一个构造器
- 如果没有显示的定义类的构造器的话,系统默认提供一个隐式无参构造器
- 默认构造器的修饰符与所属类的修饰符一致
- 一旦显示定义了类的构造器之后,系统就不再提供默认的空参构造器
- 一个类中定义的多个构造器之间彼此构成重载
- 父类的构造器不可被子类继承
5.总结:属性赋值的先后顺序
① 默认初始化
② 显示初始化
③ 构造器中初始化
④ 通过 “对象.方法” 或 “对象.属性” 的方式赋值
6.拓展:JavaBean与UML类图
> JavaBean是一种Java语言写成的可重用组件
> 所谓JavaBean,是指符合如下标准的java类:
-
- 类是公共的
- 有一个无参的公共的构造器
- 有属性,且有对应的get、set方法
> 用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以用Java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。
7.关键字:this的使用
> this理解为:当前对象 或 当前正在创建的对象
> this可以调用类的属性、方法和构造器
> 在类的方法中,我们可以使用 “this.属性” 或 “this.方法” 的方式,调用当前对象属性或方法。但通常情况下我们都选择省略“this.”。特殊情况下,若方法的形参和类的属性同名时,我们必须显示的使用“this.属性”的方式来区分属性和形参 e.g. this.name = name
> 使用this访问属性和方法时,如果在本类中未找到,会从父类中查找
> this调用构造器:
-
- 我们在类的构造器中,可以显示的使用 “this(形参列表)” 方式,调用本类中重载的其他构造器
- 构造器中不能通过 “this(形参列表)” 方式调用自己
- 如果一个类中有n个构造器,则最多有n-1个构造器中使用了“this(形参列表)”,也就是说不能构成循环调用
- 规定:“this(形参列表)” 必须声明在当前构造器的首行
- 构造器内部,最多只能声明一个“this(形参列表)”,用来调用其他的构造器
8.关键字:package的使用
> 为了更好的实现项目中类的管理,提供包的概念
> 使用package声明类或接口所属的包,声明在源文件的首行。若缺省该语句,则指定为无名包
> 包,属于标识符,遵循标识符的命名规则、规范( xxxyyyzzz )、“见名知意”。通常使用所在公司域名的倒置:com.atguigu.xxx
> 每“.”一次,代表一层文件目录
注:同一个包下,不能命名同名的接口、类
不同包下,可以命名同名的接口和类
9.关键字:import的使用
为使用定义在不同包中的java类,需用import语句来引入指定包层次下所需要的类或全部类( .* )
import语句告诉编译器到哪里去寻找类
> 说明:
- 在源文件中显式的使用import结构导入指定包下的类、接口
- import语句声明在包的声明和类的声明之间
- 如果需要导入多个结构,并列写出即可
- 可以使用 xxx.* 的方式,一次性导入xxx包下的所有结构
- 如果导入的类或接口是java.lang包下的,或者当前包下的,则可以省略import语句
- 如果在源文件中,使用了不同包下的同名的类,则必须至少有一个类需要以全类名的方式显示
- 尽管使用 xxx.* 的方式可以调用xxx包下的所有结构,但如果使用的是xxx子包下的结构,则仍需要显式导入
- import static组合的使用:调用指定类或接口下的静态的属性或方法