封装概念

面向对象具有四大特征:

  1. 封装
  2. 继承
  3. 多态
  4. 抽象

“封装”包含了两层含义“封”和“装”:

  • 装的目的是将散的东西统一在一起,方便处理和使用
  • 封是为了将信息隐藏,还包括对方法的具体实现的隐藏
  • 前面学习过的类的定义、访问修饰符也都是属于面向对象中“封装”这个特性,访问修饰符存在3个关键字和4种情况:
    • public 公共的,可以任意访问
    • private 私有的,仅本类可以自己访问
    • protected、不写的两种情况后面再做讨论
  • 日常生活中能体会到封装实际就是打包装箱

在前面学习“类”的定义,其本质就是在学习“装”的这个过程。我们将所需要的数据、功能进行分门别类的放置,有些设计在 A 类中,有些在 B 类中。我们可以认为“类定义”的{}就是装的边界。
7.png

包 package

包的引入也是一个“装”的体现。一个包里的类,理论上只能认识本包中其他类,来自于其他包的类必须使用 import 来导入,向编译器指定这个类型的位置和名称,例如经常使用到的 import java.util.Scanner。以下是使用类时不需要用 import 来告知的情况:

  1. 来自于 java.lang 包中的 JDK 类,例如使用的 String 就属于 java.lang 包,在使用时并不需去提前 import
  2. 自定义于本包中的类
  3. 还有一种特殊情况,当我们要在自定义类中,使用多个需要 import 进来的同名类,该如何处理呢?就譬如在 java 类库里有两个类都叫 Date 类,一个来自于 java.util 包,一个来自 java.sql 包 。

8.png
java 中一个类的真正名称是 包名.类名 称为 “类的限定名”。使用自定义类来模拟一下不同包同名类的情况:
当前在 a 包中有 A 类,b 包中也有 A 类:
9.png
可以看到使用 包名.类 的方式可以清晰地区分 a.A 类 或是 b.A 类。在 new 构造函数时加上包名可以分别访问到不同包的同名类中的属性值,构造函数的名字与类名一致,所以其实构造方法的名字也是类的限定名。都不用 import 提前去导入。只是平时我们都是用的 “类的简单名” (simple name)

对象数组

回忆一下我们对于多个同类型的对象是如何处理管理的?
装进到一个集合里去,对不对?
就像当前存在 10 个 int 类型的数字,我们可以将它们装进到一个集合中去。目前对于集合的学习,只学习过一种 数组
数组是通过 new 出来的,new int[5] 也就证明了数组本身就是一个引用数据类型,是对象,是存放在内存的“堆”中的。例如 int [] arr = new int[5] 可以看作:arr 这个变量名指向了一个对象,该对象有 5 个 int 类型的属性用来装数据,默认初始化为 0,只不过没有给 5 个属性命名,而是通过编号(下标)去表示,即 0-4。而且数组除了装数据的属性,至少还拥有一个 length 这样的公共属性。所以我们访问数组长度的语法是 数组名.length
10.png

数组 vs 基本数据类型数组 vs 引用数据类型数组

数组可以被分为两类:“基本数据类型数组”和“引用数据类型数组”,注意区分清楚:

  • 数组,一种数据类型,它肯定是引用数据类型
  • 基本数据类型数组是指数组里的 元素 是基本数据类型;引用数据类型数组 是指数组中的 元素 是引用数据类型
    1. // 基本数据类型数组
    2. int [] intArray = new int[10];
    3. // 引用数据类型数组
    4. Person [] personArray = new Person[10];
    new 数组对象时,不是将 10 个 Person 对象放在一起,而是 10 个 Person 变量。换句话说只是 new 了10 个位置,用来放对象的引用。

    数组的拷贝

    System.arraycopy() 是 java 语言提供的一种本地静态方法,用于将元素从源数组复制到目标数组以实现数组拷贝:
    语法:
    1. System.arraycopy(arr, oldStartIndex, newArr, newArrIndex, copyCount)
    参数说明:
  1. 源数组
  2. 源数组的起始下标
  3. 目标新数组
  4. 从新数组的起始下标
  5. 拷贝的元素个数 ```java // 基本数据类型数组 int[] arr = {1, 3, 5, 7, 9}; // 原数组 int[] newArr = new int[arr.length]; // 新数组长度等于源数组长度

System.arraycopy(arr, 0, newArr, 0, arr.length);

// 打印拷贝数组各元素 for (int i = 0; i < newArr.length; i++) { System.out.println(“新数组第” + i + “位:” + newArr[i]); } // 修改源数组一项 arr[0] = 2;

// 原数组已被修改 for (int i = 0; i < arr.length; i++) { System.out.println(“老数组:” + arr[i]); }

// 新数组保持不变,拷贝成功 for (int i = 0; i < newArr.length; i++) { System.out.println(“新数组:” + newArr[i]); }

  1. ```java
  2. // 引用类型数组
  3. // Car.java
  4. public class Car {
  5. public String name;
  6. public Car(String name) {
  7. this.name = name;
  8. }
  9. }
  10. // TestMain.java
  11. Car cars[] = new Car[3];
  12. cars[0] = new Car("BMW");
  13. cars[1] = new Car("Porsche");
  14. cars[2] = new Car("Land Rover");
  15. for (int i = 0; i < cars.length; i++) {
  16. System.out.println("原数组:" + cars[i].name);
  17. }
  18. Car newArr[] = new Car[cars.length];
  19. System.arraycopy(cars, 0, newArr, 0, cars.length);
  20. for (int i = 0; i < newArr.length; i++) {
  21. System.out.println("新数组:" + newArr[i].name);
  22. }
  23. cars[0].name = "Audi";
  24. for (int i = 0; i < newArr.length; i++) {
  25. System.out.println("修改后新数组:" + newArr[i].name);
  26. }