Java面向对象02
类的方法
方法基本格式
访问修饰符 其他可选修饰符 返回数据类型/void 方法名 (形参列表) { 方法体 }
- 如果方法有返回类型 必须存在return语句返回对应类型的值
- 如果标记为void无返回类型 可以没有return语句
- 使用return语句 视为终止该方法
return;
方法的重载 Overload
- 当类中存在两个同名方法时 且这两个方法的参数列表不同时 此时发送方法的重载
- 当一个相同功能有不同参数需要不同方式处理的时候使用
- 当方法调用时 区分具体用哪个方法的决定因素是参数列表
方法的重写/覆盖 Overwrite/Override
- 当子类继承父类时 子类对父类原有方法不满意 要重新定义该方法时 这个就是方法的覆盖
- 覆盖时 方法的返回类型 参数列表 都要完全相同
- 任何一项不同时 此时发生的不是覆盖 是方法的重载 因为父类原始方法此时还在
- 覆盖时 方法访问权限只能升高 不能降低
- 覆盖时 抛出的异常只能增加 不能减少
- 父类的私有方法 构造方法不继承 所以没有覆盖现象
- 父类的静态方法不能被覆盖
方法中的参数
- 方法中的参数 传递时传递的是数值
- 对于基本数据类型 传入的是变量的字面值
- 对于引用数据类型 传入的是引用 即指向对象的内存地址
- 可变长度参数
- 可变长度参数相当于接收一个数组 传入参数时也可以传入一个数组
- 可变长度参数必须是最后一个参数 而且只能有一个可变长度参数
- 传参可以传入0个参数
public void method(int ...args) { ... }
构造方法
class A {
public A() {
}
}
- 构造方法用于实例化一个新对象 在new关键字构建时调用
- 构造方法没有返回类型 也不需要写返回类型 方法名必须和类名相同
- 构造方法可以重载 也就是可以写多个用于不同的初始化情况
- 当构造方法缺省时 编译器默认提供一个无参数构造方法
- 当任意一个构造方法被显示编写时 编译器不再提供构造方法
- 无参数构造方法非常常用 因此建议大部分情况都要提供无参构造
- 例如
- 使用反射机制时 使用newInstance()构建新对象 要调用无参构造
- 不编写this()/super()方法时 隐式调用super()父类无参构造方法
- this()与super()
- 两个方法都必须编写在构造方法第一行 而且只能写一个
- this()用于调用其他的构造方法
- super()用于调用父类构造方法
类的特殊结构
静态代码块
class A {
static {
}
}
- 用于初始化 当类被加载时会调用 而且只会执行一次
- 在某些特殊需求使用
- 例如
Integer
中的整数常量池IntegerCache
中的静态代码块中初始化了整数常量池- JDBC规范中给
DriverManger
注册驱动是在静态代码块中
- 可以编写多个 执行顺序从上到下
- 如果仅仅想调用静态代码块中内容(例如JDBC注册驱动时) 可以使用
Class.forName(完整类名)
加载一下类
实例代码块
class A {
{
}
}
- 与静态代码块类似 也是用于初始化 但是给对象初始化 只在实例化对象时执行一次
- 执行时机在构造方法之前
Java内部类
- 内部类就是在类的内部定义一个内部类
- 分类
- 静态内部类
- 使用staic修饰的内部类与静态变量类似 依附于类上
- 静态内部类中可以定义静态变量 静态方法
- Integer中的IntegerCache就是一个静态内部类
- 静态内部类初始化的时机是在使用到时才加载 不会随之外部类的加载而加载
- 单例模式中的懒汉式 使用静态内部类实现的就是利用了这个原理 可以延迟加载 节约了资源 而且初始静态变量时JVM会保证其原子性 保证其线程安全性
- 实例内部类
- 非static修饰的内部类 与对象绑定
- 不能定义静态变量 静态方法 但是可以定义静态常量
- 局部内部类
匿名内部类
- 匿名内部类是局部内部类的一种 匿名只得是这种类没有名字 无法二次使用
- 匿名内部类中没有构造方法
- 这种类用于快速实现接口 而不用单独编写一个实现类
- 与Lambda表达式
- 用Lambda表达式有一定的限制 不是所有的匿名内部类都能写成Lambda表达式形式
- Lambda表达式只能扩展接口 而且接口中只能有一个方法
- Lambda表达式只能重写接口中的唯一方法 不能额外添加其他方法
- Lambda无法实例化
- 在Lambda表达式中 没有this(因为无法实例化) 指向的是外部对象
- 处理单方法接口时代码非常简洁
new Thread(new Runnable() {
@Override
public void run() {
}
}).start();
new Thread(() -> {
System.out.println("a");
}).start();
Java的数组
- Java数组是引用数据类型 不是基本数据类型
- 数组是一个数据的集合 是最简单一种数据结构
- 数组可以存放基本数据类型 也可以存放引用数据类型
- 数组实际会在堆内存中开辟空间存放数据
- 数组中各项数据的内存地址是连续的
- 数组中的length属性 代表数组的长度 即数组的最大个数
- 一维数组
- 最简单数据结构 元素内存连续
- 首元素地址就是数组地址 数组下标从0开始
- 多维数组
- 数组声明
int[] arr
int arr[]
C++代码风格 支持但不建议使用
- 数组的初始化
int[] a = {1, 2, 3};
int[] b = new int[3];
动态初始化 比较常用int[] c = new int[]{1, 2, 3};
- 数组的扩容
- 数组没法原地扩容
- 每次扩容都需要准备一个更大的数组 然后把原始的数据复制到新数组
- 使用
System.arraycopy()
方法可以复制一个数组
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
Object src
原始数组int srcPos
原始数组起始位置Object dest
目标数组int destPos
目标数组起始位置length
复制的长度
- 数组的扩容很消耗资源 尽量减少数组的扩容 尽量预估数组的长度 减少扩容次数