LangInteger

Java面向对象编程知识点总结

主要是针对Java面向对象部分知识点的梳理,方便日后查找。

1 类和对象

1. 类

  • 是同种对象的集合与抽象,是产生对象的模版
  • 数据类型是指数据集和基于这个数据集的操作,类则是我们的自定义类型,需要由我们定义成员变量和基于数据集的成员方法。

2. 程序设计方式

  • 面向过程程序设计
    • 把静态问题转化为一系列动作,即把动作用函数描述,其重点是算法和数据结构。
  • 面向对象程序设计
    • 代码的基本单位是类,各类间发消息推进动作,传递消息就相当于是方法调用,其重点是对对象和消息。

3. OO的真正意义

  • 是使得软件开发接近人类的正常思维,将许多原来由人完成的工作交给机器去完成。,把更多的精力放到问题本身,而不是在问题的转化中。
  • OO的完整方法
    • 面向对象的分析
    • 面向对象的设计
    • 面向对象的程序设计
    • 代码重用

2. 面向对象三大特性

1. 封装

  • 封装是一种信息隐藏技术,是指将数据和基于数据的操作封装在一起,数据被保护在内部,系统的其他部分只有通过在数据外面的被授权的操作才能够进行交互,目的在于将类使用者class user和类设计者class creator分开。在面向对象的编程中,用类来封装相关的数据和方法,保证了数据的安全和系统的严密性。
  • 封装的优点
    • 隐藏类的实现细节,实现了信息的隐藏及安全性
    • 提高了程序的模块化,且易于维护
    • 具体实现是编写该类的人控制的,让使用者只能通过事先定制好的方法来访问数据,实现者可以方便地加入控制逻辑,限制对属性的不合理操作

2. 继承

  • 使程序结构清晰,减少了编码和维护的工作量,子类可以使用父类所提供的方法,实现了代码的复用。

3. 多态

  • 编译时多态:同一类中参数不同的同名方法(重载)
    • 方法的签名(signature):声明方法的方法头中方法名加上方法的参数列表,可以唯一确定一个方法
    • 类体中不能声明签名完全相同的两个方法
    • 当两个方法具有相同的方法名,但有不同数量或类型的参数,而导致不同的方法签名时,称这两个方法互相重载
  • 运行时多态:父类和子类之间的同名方法

3. 类的定义

[修饰符] class 类名 [extends 父类名]
                    [implements 接口名]
{
    [成员变量声明;]
    [成员方法声明;]
}

1. 类体

  • 一为成员变量定义(域) Field
  • 二为成员方法定义 

2. 创建对象

  • 步骤一:申明一个对象(引用变量)
  • 步骤二:初始化
  • 步骤三:赋初值

3. 构造方法

  • 构造方法作用概述
    • 给对象的数据进行初始化
  • 构造方法格式
    • 方法名与类名相同
    • 没有返回值类型,连void都没有
    • 没有具体的返回值
  • 构造方法注意事项
    • 如果你不提供构造方法,系统会给出默认构造方法
    • 如果你提供了构造方法,系统将不再提供
    • 构造方法也是可以重载的

4. 局部变量

  • 在一个方法(参数列表里)或者方法里面的代码块中定义的变量称为局部变量
  • 局部变量在方法或代码块被执行时创建,在方法或代码块结束时被销毁。
  • 局部变量必须先赋值再使用,否则会出现编译错误。

5. 成员变量的隐藏性

  • 局部变量与成员变量名字相同时,则成员变量将被隐藏,即在这个方法内暂时失效,只有局部变量起作用

6. 类的初始化过程总结

  • Student s = new Student();在内存中做了哪些事情?
    • 加载Student.class文件进内存
    • 在栈内存为s开辟空间
    • 在堆内存为学生对象开辟空间
    • 对学生对象的成员变量进行默认初始化
    • 对学生对象的成员变量进行显示初始化
    • 通过构造方法对学生对象的成员变量赋值
    • 学生对象初始化完毕,把对象地址赋值给s变量

7. static关键字

  • 特点
    • 随着类的加载而加载
    • 优先于对象存在
    • 被类的所有对象共享
    • 可以通过类名调用(建议只用类名调用)
  • 注意事项
    • 在静态方法中是没有this关键字的
    • 静态方法只能访问静态的成员变量和静态的成员方法
  • 静态变量和成员变量的区别
    • 所属不同
      静态变量属于类,所以也称为为类变量
      成员变量属于对象,所以也称为实例变量(对象变量)
    • 内存中位置不同
      • 静态变量存储于方法区的静态区
      • 成员变量存储于堆内存
    • 内存出现时间不同
      • 静态变量随着类的加载而加载,随着类的消失而消失
      • 成员变量随着对象的创建而存在,随着对象的消失而消失
    • 调用不同
      • 静态变量可以通过类名调用,也可以通过对象调用
      • 成员变量只能通过对象名调用

8. 代码块

  • 在Java中,使用{}括起来的代码被称为代码块,根据其位置和声明的不同,可做如下分类。
    • 局部代码块
      • 在方法中出现;限定变量生命周期,及早释放,提高内存利用率
    • 构造代码块
      • 在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行
    • 静态代码块
      • 在类中方法外出现,加了static修饰
      • 在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且值执行一次。
    • 同步代码块:多线程部分讲解

9. 域的访问控制

  • 通过访问控制修饰符 (access modifiers)可以限制成员变量在类或对象外部的可见性
    • public — 共有的,域在任何地方都可以访问。
    • protected — 受保护的,仅在类体中、子类类体中或同包的其它类类体中可访问。即:在类中被申明为保护的域可以被同一个包中的该类的对象访问。也能被其子类访问,而不管它们是否在同一个包中 。
    • private - 私有的,域仅在类体中可访问。只有同一类中创建的对象才能访问私有域。在其他类中创建的对象不能访问私有域。
    • (不写)—默认的package,没有任何访问修饰符修饰的域,仅在类体中、同包的其它类类体中可访问。

4. 继承

1. 继承的理解

  • 对真实世界中对象继承关系的支持,满足面向对象建模的需要
  • 实现OOP中对象多态性(Polymorphism)的前提
  • 代码复用
  • 继承一定程度上帮助程序员摆脱java中严格类型限制的约束
    • 表现为子类对象可被声明为父类类型

2. 继承语法格式

[修饰符] class B extends A {语句}
  • 子类拥有父类中所有成员,但只能访问public和protected的成员变量和方法
  • 子类对象的成员舒适化之前,必须首先完成对父类/祖先类成员的初始化,原因是子类依赖于父类,为保证子类代码的正常运行

3. 子类对象的初始化

1. 显示初始化

  • 在子类构造函数的第一句话通过super(参数)调用父类的构造函数

    2. 隐式初始化

  • 当父类提供了默认构造函数,且父类的其它构造函数未被显式调用,则在执行子类的构造函数之前Java会自动执行父类的构造函数。

4. final关键字

  • final修饰的成员变量初始化之后不能再被重新赋值
  • 被final修饰的类不能被继承
  • 被final修饰的方法不能被覆盖

5. import和package关键字

  • import关键字进行导包操作,Java默认导入java.lang包
  • package的作用
    • 将类和接口分组,包名表示其用途
    • 创建了不同的命名空间,解决命名冲突的问题
    • 提供了对应用程序内部实现机制的保护域

5. 运行时多态

1. 运行时多态的前提

  • 要有继承关系
  • 要有方法覆盖
  • 有父类引用指向子类对象

2. 方法覆盖

  • 在子类中替换父类对某个方法的实现
  • 替换的方法要与原方法有相同的方法签名和返回值类型
  • 重写方法的修饰符不能比原方法更严格

3. 覆盖的注意事项

  • 被final,static修饰的方法无法被覆盖
  • 被synchronized,native修饰的方法可以被覆盖
  • 被覆盖的方法参数列表中有被声明为final的,不必再被声明为final
  • 只有在子类中可访问的父类的方法才可覆盖
  • 静态方法不能被覆盖,只能被隐藏
  • 构造方法并非member,不参与继承,故隐藏或覆盖无从谈起

4. 多态的核心

  • 父类引用指向子类对象
    • 父类类型 a = new 子类类型();
    • 子类 is a 父类
    • 运行时类型为引用变量所指对象的类型,编译时类型是引用变量的自身类型
  • 多态中的成员访问
    • 成员变量
      • 编译看左边:可访问成员看声明类型
      • 运行看左边:实际访问的成员变量值是声明类型中定义的
    • 成员方法
      • 编译看左边:可访问成员变量范围由声明类型决定
      • 运行看右边:实际访问到的方法由引用指向示例的实际类型确定
  • 赋值兼容性规则
    • 复制号右边表达式的类型必须与左边引用表达式类型相同或为其子类
    • 方法的return语句返回的结果的类型必为方法声明中返回类型或其子类型
    • 所有的引用变量都可以赋值为null
  • 转型
    • 向上转型:父类引用指向子类实例/对象 => 要先进行向上转型才能进行向下转型
    • 向下转型:子类引用指向父类实例/对象 => 子类中如果定义了只属于自己的成员的时候会出问题

6. 抽象类

  • 对于一些泛指的类型(如动物),并不能确定其行为的具体实现,故引入抽象内作为对对象行为的抽象,作为一个框架来使用。

1. 抽象类/方法注意事项

  • 必须加abstract修饰
  • 抽象类不可实例化
  • 抽象方法不能有方法体,大括号也没得
  • 含抽象方法的类一定为抽象类,抽象类可以没有抽象方法,这样做的目的是不想让别人实例化

2. 抽象类的成员特点

  • 成员变量可为常量也可为变量
  • 成员方法中的抽象方法强制非抽象子类实现
  • 抽象类也有构造方法
  • 抽象类的子类如实现了父类中的全部抽象方法,可以不为抽象类,否则必须为抽象类

7. 接口

  • 是一个完全抽象的类,JDK8新特性引入之前,接口中的所有成员方法都是抽象方法

1. 使用场景

  • 用来申明某些不是被所有子类所共有的行为,且这些特殊群体的表现又各有不同

2. 接口的特点

  • 接口中可以没有方法,被称为空接口,通常用作标记
  • 接口的子类为抽象类和具体类
  • 类只支持单亲继承,而接口实现了多重继承(但由于没有方法体,在1.8之前几无意义)

3. JDK1.8接口新特性

    1. 默认方法default => 与一般的可继承方法无异,在接口中新增默认方法,不会影响已经实现了该接口的类,是用来修改接口的好方法
    1. 静态方法static => 静态方法一般定义在接口中使用,但也可以在接口外通过“接口名.方法”访问,通常被用来作为一种工具方法

4. 接口成员特征

  • 接口中可以生命成员变量和成员方法
  • 接口中的成员皆为public,若不标记则默认为public
  • 接口成员默认为static final,必须显示初始化
  • 接口中方法必须被abstract(JDK1.8之前)修饰,默认为public abstract

8. 内部类

  • 就是定义在其他类内部的类

1. 重要特点

  • 内部类可以直接访问外部类的成员,包括私有

2. 按位置分类

  • 定义在类成员位置 => 成员内部类
    • 在外部类中new内部类对象可以直接访问;在外部类外访问,则需要先创建外部类对象,后在外部类对象基础上new内部类对象
    • private,static可用来修饰成员内部类
  • 定义在局部位置 => 局部内部类
    • 可直接访问外部类的成员
    • 局部内部类只能在方法体中访问
    • 在方法体中使用局部内部类创建对象
  • 匿名内部类
    • 是一个(继承了类或者实现了接口的子类)的匿名对象
    • 匿名内部类的类型是其父类类型(一般是接口或者抽象类),用到了向上转型
    • 开发中在形参为接口类型的方法中经常使用