一、面向对象
1. 主要特征
1.1 封装
利用抽象数据类型(类)将数据和基于数据的操作绑定在一起,数据被保存在抽象数据类型的内部,系统只有通过被授权的操作方法才能够访问数据
- 特点:
- 数据和基于数据的操作方法构成一个统一体
- 类的操作方法实现细节被隐藏起来,只是通过操作接口名称进行调试,操作内部的变动不会影响接口的使用
- 实现
- 设置访问权限,修改可见性
- 创建 getter/setter 方法
- 在 getter/setter 方法中加入属性控制语句
- 创建类的实例、调用构造函数
- 用途
- 用户无需知道对象内部的细节,但可以通过对象对外提供的接口来访问该对象,有利于安全操作
- 高内聚,松耦合
1.2 继承
通过
extends
关键字来实现,使两个类发生继承关系is-a 关系
- 继承只能是单继承,一个类只允许有一个父类
- 用途:
- 对功能进行复用的重要手段
- 为引用带来了新的特点
1.3 多态
一个程序中同名但不同方法共存,提供两种机制——重载(overloading)与覆盖(overriding)
- 重载
- 方法间名字相同,参数列表不同(包括参数顺序、个数、类型等)
- 必须是同一个类内
- 方法功能和目的相同,但具体细节有所不同时使用
class StuManage {
public int getScore(){
return 3;
}
public int getScore(int i){
return i;
}
/*public long getScore(int i){
return i;
}*/
/*private int getScore(int i){
return i;
}*/
/*public static int getScore(int i){
return i;
}*/
/*public final int getScore(int i){
return i;
}*/
// 注释内的都不属于重载
public int getScore(Integer i){
return i;
}
//可变参数,i实质上是数组int[]
public int getScore(int ... i){
return 3;
}
}
- 覆盖
- 子类对父类的同名方法(方法名称相同,参数相同,返回类型相同)重新进行定义,即在子类中定义与父类中已定义的同名而内容不同的方法。
- 子类继承父类之后,当子类有不同于父类的业务需求时,子类可以使用方法覆盖
- 条件:
- 两个类必须有继承关系
- 重写之后的方法和之前的方法具有相同的返回值类型,相同的方法名,相同的形式参数列表,(同名方法不一定就是覆盖,可能是重载)
- 重写方法的访问权限不能比之前方法的权限更低,可以更高
- 重写方法的抛出异常数不能比之前方法的抛出异常数更多,可以更少
- 用途:
- 满足多样的需求,实现更强大的功能
class Parent {
Number getScore(int a) {
return new Integer(7);
}
}
class Son extends Parent {
@Override //所有的覆写方法需注明
Number getScore(int b){
return new Integer(8);
}
}
public class RunSon{
public static void main(String args[]){
Son s = new Son();
System.out.println(s.getScore());
}
}
2. 对象间作用
- 作用方式:对象之间可以通过组合,继承以及一个对象直接在其内部创建另一个对象。
- 作用条件:两个对象彼此之间要是可见的。
3. Object基类常用方法
方法名 | 说明 |
---|---|
Class getClass() | 获得当前对象的类对象 |
String toString() | 得到代表这个对象的字符串 |
Object clone() | 将当前对象克隆,默认是浅拷贝 |
void finalize() | 对象被释放时使用,已弃用 |
int hashCode() | 得到代表对象的一个整数,这个整数在应用程序运行时保持不变 |
Boolen equals(Object obj) | 判断两个引用是否指向同一对象,其参数不能为普通数据类型 |
void notify | 用于线程同步中唤醒等待的线程 |
void wait() | 应用于线程同步中的线程等待 |
二、访问控制修饰符
修饰符
访问修饰符 | 同类是否可以访问 | 同包是否可以访问 | 子类是否可以访问 | 不同包是否可以访问 |
---|---|---|---|---|
public | 是 | 是 | 是 | 是 |
protected | 是 | 是 | 是 | 否 |
private | 是 | 是 | 否 | 否 |
default(缺省) | 是 | 否 | 否 | 否 |
protected
- 允许子类访问定义在父类中的数据和方法,但是不允许非子类访问这些数据和方法,这种情况下就可以使用protected,它允许任何包中的子类访问父类
- 基类的 protected 成员是包内可见的,并且对子类可见
// 在resource 包中设计 FightPlane 类
package com.resource;
public class FightPlane {
protected String name;
protected int missileNum;
public void fire(){
if(missileNum > 0){
System.out.println("now fire a missile!");
missileNum -= 1;
}else{
System.out.println("No missile left!");
}
}
}
// 在run包中设计RunPlane类,且继承FightPlane类
package com.run;
import com.resource.*;
public class RunPlane extends FightPlane {
private void init(){
name = "su35";
missileNum = 6; // 可以访问另一个包中protected属性
}
public static void main (String[] args){
RunPlane fp = new RunPlane();
fp.init();
fp.fire();
}
}
- default(缺省)
- 包访问权限
- 不在一个包内,即使是继承关系也不能访问
// 在resource 包中设计 FightPlane 类
package com.resource;
class FightPlane { // 缺省,设置为包访问权限
protected String name;
protected int missileNum;
public void fire(){
if(missileNum > 0){
System.out.println("now fire a missile!");
missileNum -= 1;
}else{
System.out.println("No missile left!");
}
}
}
// 在run包中设计RunPlane类,且继承FightPlane类
package com.run;
import com.resource.*;
public class RunPlane extends FightPlane {
private void init(){
name = "su35";
missileNum = 6; // 可以访问另一个包中protected属性
}
public static void main (String[] args){
RunPlane fp = new RunPlane();
fp.init();
fp.fire();
}
}
// 报错:java: com.resource.FightPlane在com.resource中不是公共的; 无法从外部程序包中对其进行访问
继承中的访问权限
- 子类继承了父类的所有方法和属性,但只有
public
和protected
是可见的 private
不能被子类直接访问,但子类可以通过调用父类的公有方法来间接访问
class FightPlane {
private String name;
protected int missileNum;
public void fire(){
if(missileNum > 0){
System.out.println("now fire a missile!");
missileNum -= 1;
}else{
System.out.println("No missile left!");
}
}
}
public class RunPlane extends FightPlane {
private void init(){
name = "su35"; // 报错:java: name 在 com.run.FightPlane 中是 private 访问控制
missileNum = 6;
}
public static void main (String[] args){
RunPlane fp = new RunPlane();
fp.init();
fp.fire();
}
}
三、类的组合
在一个类里面使用已经定义好的类对象的引用,并通过发消息的形式调用该对象的属性和方法
has-a,包含关系,有别于继承关系
- 作用:
- 不破坏封装,类与类之间相互独立,使用其他类的方法使功能更强大
- 使对象间耦合性较为松散
class FighterPlane
{
String name;
int missileNum;
public FighterPlane(String _name,int _missileNum){
name = _name;
missileNum = _missileNum;
}
public void fire(){
if (missileNum>0){
System.out.println("now fire a missile !");
missileNum -= 1;
}
else{
System.out.println("No missile left !");
}
}
}
class A
{
FighterPlane fp;
public A(FighterPlane fpp){
this.fp = fpp; //A对象中拥有了FighterPlane对象的引用
}
public void invoke(){
//A中对象发送消息给FighterPlane的对象
System.out.println(fp.name);
}
}
public class RunPlane{
public static void main(String[] args)
{
FighterPlane ftp = new FighterPlane("su35",10);
//产生A对象,并将ftp对象引用作为参数传入
A a = new A(ftp);
//发送消息,产生调用关系
a.invoke();
}
}
总结
从面向对象的三大主要特性入手,重点关注封装、继承、多态特性,了解了组合与继承的区别,以及合理设计访问权限的重要性,从而对Java的对象语法更为熟识,也在对其思想的学习中逐渐意识到之后的学习都不能局限在编写代码的阶段,更多的应该要从开发软件的角度考虑,如何运用所学知识使代码结构清晰、简洁、美观等都是值得思考的。
在整理博客的过程中参考了一些资料以及许多他人优秀的文章,就不一一列举,在此表示感谢。