1 面向对象高级特性
面向对象包括3大要素:封装、继承、多态
1.1 封装
将数据或实现的细节隐藏内部的行为就是封装
封装特性不光体现在面向对象中,在面向过程中的提取方法的过程实际也是封装思想的体现
在面向对象编程中,如果我们不希望在类外访问成员变量或成员方法,可以将这些成员隐藏起,限制类外的访问,这种行为就是封装
1.1.1 如何实现封装
使用 访问控制符 来实现封装,共有4种public protected 不写 private
成员变量
public,公有访问控制符 当使用该控制符时,成员变量即可以在类内使用,
也可以在类外通过 对象名.成员变量 的方式使用
private,私有访问控制符 当使用该控制符,成员变量只能在类内访问
我们通常将成员变量定义为private,为其提供一对公有的get/set方法来使用成员变量,这种规范称为javabean规范
局部变量没有访问控制符
成员方法
public,该方法即可以在类内调用,也可以在类外调用
private,该方法只能在类内调用
如果将构造方法定义为私有的(private)会有什么结果?
会阻止类来创建对象,即该类无法实例化
类
public,这个类的名字必须与java文件名相同
不写, 这个类的名字和java文件名可以任意
类前不能写private
1.1.2 包的使用
在一个工程目录中不能存在相同名字的文件,将同名的java文件分别放入不同的包中
包的命名通常使用倒置的域名,例如com.neuedu.XXX
语法:
包的定义,使用关键package 包名;
包的使用,使用关键import 包名.类名; 或者 import 包名.*;
前者是使用某个包中指定的类(推荐),后者是使用指定包中的所有类
注意:
如果引入的包中有同名的类,那么要使用前缀来进行区分
1.1.3 static关键字
创建一个类来描述一块手表,是一款限量版的,要增一个编号记录这是第几块表
解决方案:在内存中开辟一块特殊的空间,所有的对象都使用这块空间来进行计数
这种在内存中所有对象共有的变量,称为静态变量或者叫类变量,强调是只有一份
当一个对象改变了静态变量(类变量)的值之后,其他对象也会看到这样变化
语法:在访问控制符后,数据类型前加上static关键字
例如:
public static int id; //定义了一个静态变量
说明:
1. static可用修饰 成员变量、成员方法、代码块
2. 用于成员变量,代表该变量是所有对象共有的
3. 用于成员方法,代表该方法是所有对象共有的
4. static方法只能调用static方法和static变量
5. 非static方法可以调static方法也可以调用非static方法,可以使用static变量也可以使用非static变量
6. 可以用对象.静态变量,也可以用 类名.静态变量,推荐使用后者
7. 可以用对象.静态方法,也可以用 类名.静态方法,推荐使用后者
1.1.4 单例模式
设计模式,在工程实践中对于某些代码进行了整理,总结一套固定的代码格式,应用这些固定的格式可方便的解决某些特定问题
单例是指只有一个实例,对于某些类只能创建一个对象
步骤:
1. 将构造方法私有化
2. 提供一个公有静态方法来创建对象
3. 在该方法创建一个静态的对象
方式:
1. 饿汉式,先分配内存,再去调用,浪费空间、节省时间
2. 懒汉式,调用时分配内存,节省空间、浪费时间
1.2 继承(扩展)
在原有类的基础上,将所有功能复制过来,同时增加新的内容,从而达到代码复用的目的
语法:使用extends关键字
访问控制符 class 子类 extends 父类
{
类体
}
其中:
子类,是扩展的新类,又称为派生类
父类,是原有的类,又称为基类
说明:
1. 使用继承会将父类中所有变量都复制过来,但是只能公有成员可以使用
2. 构造方法不继承
3. 在同一个类中可以使用this关键字来调用另外的构造方法
使用this调用构造方法的代码必须写在第一行
4. java中只支持单继承,每个类只有一个直接父类
5. 类的继承可以有多重
1.2.1 子类对象的初始化
在继承关系下,子类对象的由两部分构成:从父类继承来的 + 子类新增的
当要初始化子类对象时,需要初始化继承来的变量和新增的变量
使用super关键字,调用父类的构造方法来初始化父类中的私有成员变量
注意:super关键字只能写在构造方法的第一行
通过参数列表来区分调用哪个构造方法
如果在子类中没有显式调用父类中的构造方法,那么系统将自动的调用父类中
无参的构造方法,假如父类中没有提供无参的构造方法,那么将编译错误
如果一个类想做为基类,那么一定要提供无参构造方法
通常:各司其职
使用父类的构造方法初始父类的成员变量,不论这些变量是私有还有公有
使用子类的方法来初始化子类的成员变量
说明:
1. 在多重继承条件下,构造中只需要调用直接父类的构造方法
2. 在初始化对象的时间,先初始化从父类继承来的成员变量,再初始子类的成员变量
如果有多重继承,这个过程会递归执行
课堂练习
设计一个类,来描述一块手表,可以更改、显示日期和时间
扩展这个表类,增加一个播放音乐
1.2.2 this和super
这两个关键分别有2种用法
1. this/super . 用来引用变量,this引用成员变量,super引用父类的成员变量
2. this/super( )用来调用构造方法,this调用同类中的构造方法,super调用父类中的构造方法
1.2.3 继承条件下成员方法
在继承条件,如果子类中方法的 返回类型、方法名、参数列表与父类中的方法相同,当使用子类对象调用该方法时,会执行子类中的方法体,这种现象称为方法的重写
如果想调用被重写了的父类方法,可以使用super.父类方法名 的形式,
不论this还是super只能在子类内部使用
如果仅是方法名相同,而参数列表不同,那么该方法与其它方法互为重载方法
1.2.4 final修饰符
final关键字强调的是不变性,static关键字强调的是唯一性
final修饰符可以应用于:类、成员变量、局部变量、成员方法
类:
表示该不能被继承
成员变量:
表示该变量在初始化之后不能再次改变
有两个位置可以提供初始化,一是在定义变量时,二是在构造方法中,如果错过了这两个位置那么将编译出错
局部变量:
变量必须在定义时初始化
通常给局部变量加final修饰的目的是为了防止程序内部无意中改变变量的值
成员方法:
表示该方法不能被重写
final和static可以连用,修饰成员变量和成员方法,成员变量必须在定义时初始化
总结:
定义类:
public
[final] class 类名 [extends 父类名] { 类体 }
不写
定义方法:
public 返回值类型
private [static] [final] 方法名([形参列表]) { 方法体 }
protected void
不写
定义成员变量:
public
private [static] [final] 数据类型 变量名[=初始值];
protected
不写
定义局部变量:
[final] 数据类型 变量名=初始值;
综合练习1
设计一个图书管理系统,能完成图书录入和查询功能
例如:
录入功能,通过键盘将数据写入计算机
西游记 吴承恩 75.6
红楼梦 曹雪芹 94.5
水浒 施耐庵 92
。。。
查询功能,通过单价查询书名和作者
通过书名查询作者和单价
分析:用面对象的思想来处理
1. 创建类
图书类(存储图书信息)、界面类(数据的输入输出)
2. 成员变量和成员方法
图书类
书名、作者、价格 get/set
界面类
输入数据,Scanner类
输出数据,System类
整理代码:
1. 利用封闭将代码抽取为独立的方法
选择代码 à 右键Refactor àExtract à Method à 填写方法名 –>ok
2. 处理参数传递
当多个方法共享某个变量时,可以将变量定义为成员变量
3. 优化代码结构
用switch替换if else
综合练习2
设计一个学生成绩管理系统,完成学生成绩的录入和查询功能
例如
录入成绩
张三 英语90.2 语文79.6 数学 89.1
李四 英语70.2 语文73.6 数学 79.1
…
查询成绩
输入 张三
显示 英语90.2 语文79.6 数学 89.1
提示:不能直接比较字符串,要使用equals方法
if (name.equals("张三")) //比较2个字符串是否相同
1.3 多态
在日常生活中,不同的对象接同一个消息(事件)时,会表现出不同的行为,这种现象就称为多态
在编程语言中
同一对象调用同一个方法,却能完成不同的功能,是一种静态多态
当变量的编译时类型与运行时类型不一致时就发生了动态多态
编译时类型,指的是在程序运行之前就确定下来的类型
运行时类型,指在程序开始执行后才能确定下来的类型
1.3.1 分类
一种是,静态多态
重载就是一种静态多态。
一种是,动态多态
编译时类型与运行时类型不一致时
1.3.2 产生多的态的前提条件
1. 必须有继承
2. 必须重写父类的方法
3. 必须通父类的对象去调用方法