Object类
- 性质
- Java中的根类
- 特点
- 所有的引用类型均继承自Object类
- Object类要么是一个类的直接父类, 要么是一个类的间接父类
- 说明
- 如果一个类没有指明其父类, 则其继承自Object
- 如:
class Test{}
, 相当于class Test extends Object{}
- 常见方法
-
protected void finalize()
- 无需手动调用
- 当GC确定一个对象无变量引用时, 就会调用该方法回收该对象的内存空间
-
public final Class getClass()
- 获得调用对象的类型
-
public int hashCode()
- 获得调用对象的哈希值(不同对象的哈希值是不同的)
-
public boolean equals(Object obj)
- 建议自定义类中覆盖该方法
- 默认情况下, 比较两个对象的内存地址值
-
public String toString()
- 建议自定义类中覆盖该方法
- 默认情况下, 返回的是对象的
类名 + "@" + hashCode
值 - 控制台打印对象时, 底层调用的正是
对象.toString()
方法
-
多态
- 定义: 对象的多种状态
- 核心: 父类变量可以引用子类
- 理解核心: 子类继承自父类, 但子类仍然是父类的一种
- 例: Student继承自Person, Student仍然是Person
- 对象的两种类型
- 编译类型: 编译器看到的类型, 当使用父类变量引用子类对象时, 编译器会将其看做是一个父类对象
- 运行类型: 程序运行后, 对象的真实类型
- 编译类型要么和运行类型相同, 要么是运行类型的父类
- 存在多态时, 编译器看到的是一个父类对象, 实际运行时是一个子类对象
- 多态存在的前提
- 编译类型和运行类型可以是继承关系, 也可以是实现关系(接口和实现类), 在开发中一般指实现关系
-
多态的作用
- 1 编译时屏蔽子类之间的差异
- 2 运行时体现子类之间的差异
- 3 代码通用, 功能各异
多态时的方法调用问题
-
背景
- 存在多态时, 编译器将对象作为父类类型, 运行时其为子类类型
- 如果父类类型和子类类型存在着 所调用的方法 不一致的情况, 就会有很多可能性
-
可能性分析
-
考虑因素: 父类是否存在方法A, 子类是否存在方法A, 子类能否继承父类方法A
情况1 父类存在方法A, 子类存在方法A 且 父类方法A可以被子类继承
情况2 父类存在方法A, 子类不存在方法A 且 父类方法A可以被子类继承
情况3 父类存在方法A, 子类存在方法A 且 父类方法A不可以被子类继承
情况4 父类存在方法A, 子类不存在方法A 且 父类方法A不可以被子类继承
情况5 父类不存在方法A, 则编译时就会报找不到方法错误, 无需考虑子类是否有方法A
-
非静态方法
情况1 编译通过, 调用子类方法A
情况2 编译通过, 调用父类方法A, 此时this变量 == 子类对象
情况3 编译通过, 调用子类方法A
情况4 编译通过, 运行报错 ???结论是否正确???
核心思想: 父类有方法A, 编译通过; 子类有或者可继承方法A, 运行通过
-
静态方法
情况1 编译通过, 调用父类方法A
情况2 编译通过, 调用父类方法A
情况3 编译通过, 调用父类方法A
情况4 编译通过, 调用父类方法A
核心思想: 父类有方法A, 编译通过, 运行也通过
-
引用类型的转换
- 基本类型转换
- 自动: 小转大
- 强制: 大转小
- 引用类型转换
- 考虑: 父类 和 子类
- 可以理解为: 父类 == 大类型, 子类 == 小类型
- 自动: 子类转父类, 即:
父类变量 = 子类对象
- 强制: 父类转子类, 即:
父类变量 = 子类对象; 子类变量 = (子类类型)父类变量
(不觉得是强转)-
子类变量 = (子类类型)父类变量;
错误: 编译通过, 运行异常
-
-
instanceof
- 性质: 运算符
- 作用: 判断某个类是否是某个对象的本类或父类
- 格式:
对象 instanceof 类
- 结果为 boolean类型数据
- 只判断某个类是否是某个对象的本类:
对象.getClass() == 类.class
多态时的字段访问
-
结论: 只有非静态方法有多态特征, 静态方法和字段均没有多态特征
- 静态方法: 通过编译类型去寻找静态方法
- 字段: 编译时期就决定调用哪一块存储空间. 所以表现不出运行时的特征
- 注意: 当父类和子类存在着名称相同的字段时, 在各自的内存空间中都存储着对应的同名字段
- 参考: day09 - 继承关系中子类对象创建的内存分析
代码块
-
定义: 使用{}括号括起来的一段代码
-
代码块内变量: 局部变量, 只在代码块中有效
-
语法格式
[修饰符] { // 代码块内容 }
-
分类
-
局部代码块
- 定义在方法中的代码块
- 一般不用直接局部代码块, 而是和if,while,for等关键字结合使用
-
初始化代码块
- 定义在类中方法外的代码块
- 又称: 构造代码块
- 执行时机: 使用new创建所在对象时, 首先执行初始化代码块, 而后执行构造器
- 反编译: 反编译后可以看到, 初始化代码块被放到了构造器中, 作为构造器的最初几条语句
- 实际使用: 一般不使用, 如果需要进行初始化操作, 直接在构造器中添加初始化方法即可
-
静态代码块:
-
static 修饰的初始化代码块
-
执行时机: 字节码加载进JVM时, 先执行静态代码块, 而后才会执行main方法
-
如果一个类中没有main方法, 那么在字节码加载进JVM时只执行静态代码块
class ClassA { static { System.out.println("静态代码块"); } } class ClassB { public static void main(String[] args) { System.out.println("主方法"); new ClassA(); ClassA a = new ClassA(); } } /* 打印结果: 主方法 静态代码块 ClassA.class 加载进JVM的时机: 程序中第一次使用到ClassA类时. 并且只加载一次 */
-
-
实际使用: 初始化操作, 加载资源和配置文件等
-
-
初始化代码块和静态代码块定义的位置没有意义
-
final修饰符
-
表示: 最终的
-
作用
- final修饰的类: 该类无法创建子类, 为最终类
- final修饰的方法: 子类不能再覆盖该方法, 只能调用
- final修饰的变量: 该变量只能赋值一次, 无法再修改变量的值
-
注意:
- 多个修饰符是没有先后顺序的, 如修饰方法:
final public static test(){};
-
构造方法不能使用final修饰
- 因为构造方法不能被子类继承, 已经是最终方法
- 多个修饰符是没有先后顺序的, 如修饰方法:
-
使用场景
-
何时使用final修饰一个类
- 1 不是为继承设计的
- 2 类中的实现方法只许使用, 不许覆盖
- 3 该类不会再被拓展
- Java中常见的final修饰类: String, 八大基本类型包装类
-
何时使用final修饰一个方法
- 1 构造器中调用的方法
- 2 父类中统一的算法骨架
-
何时使用final修饰一个变量
-
1 统一使用的数据, 将其定义为一个final变量. 如:
final double pi = 3.1415;
-
2 常量类中的数据, 均使用final修饰
public class Consts { public static final double PI = 3.1415; ...... }
-
-
-
final修饰的变量的特点
- 该变量只能初始化一次, 其后不能修改
- 如果变量是基本数据类型, 则其中的值不能修改
- 如果变量是引用类型, 则其中的地址值不能修改
- final是局部变量唯一能使用的修饰符
- final修饰符不会改变变量的作用域
-
final变量的命名规范
- 变量名全部大写, 中间以 _线隔开 如:
MAX_INT
- 变量名全部大写, 中间以 _线隔开 如:
-
全局静态常量
public static final double PI = 3.1415;
- 使用
类名.变量名
调用
单例设计模式
- 设计模式: 一种之前开发者总结的代码设计经验.
- 单例: 一个项目中只有一份该类的对象
-
单例设计步骤
- 1 添加一个私有的, final修饰的, 该类型类成员, 并设置一个初始值
- 2 私有化本类构造器
- 3 提供一个公共静态方法, 用于返回创建的私有类成员
工具类的设计
- 根据访问方式的不同, 分为
-
单例工具
- 工具中的成员使用 public 修饰, 不使用 static 修饰
- 设计为一个单例
-
类工具
- 工具中的成员使用 public static 修饰
- 将构造器私有化
- 首选使用类工具
-
单例工具
- 工具类的包名:
xxx.util, xxx.utils, xxx.tool, xxx.tools
- 如:
com._520it.util
- 如:
- 工具类名:
XxxUtil, XxxUtils, XxxTool, XxxTools
- 如:
com._520it.util.ArrayUtil, com._520it.util.StringUtil
- 如:
网友评论