java学习笔记(八)- 面向对象中级

一、包

  • 包实际上就是创建不同的文件夹/目录来保存类文件

1. 语法

1
2
3
4
5
6
7
8
package com.study;
//1. package 关键字,表示打包
//2. com.study表示包名

//引入包
import 包;
//案例
import java.util.*;//将java.util包下的所有类都引入

2. 作用

  • 区分相同名字的类
  • 管理类
  • 控制访问范围

3. 命名规则

  • 只能包含数字、字母、下划线、小圆点,但是不能以数字开头,不能是关键字和保留字
  • 一般是小写字母+小圆点
1
2
3
4
com.公司名.项目名.业务模块名

//案例
com.sina.crm.user//用户模块

4. 常用的包

1
2
3
4
java.lang.*//lang包是基本包,默认引入
java.util.*//util包是系统提供的工具包,工具类,如Scanner
java.net.*//网络包,网络开发
java.awt.*//java的界面开发,GUI

5. 注意事项

  • package的作用是声明当前类所在的包,需要放在class的最上面,一个类中最多只有一句package
  • import指令位置放在package的下面,在类定义前面,可以有多句且没有顺序要求

二、访问修饰符

1. 介绍

  • 用于控制方法和属性(成员变量)的访问权限(范围),共4种:
    • 公开级别:用public修饰,对外公开
    • 受保护级别:用protected修饰,对子类和同一个包中的类公开
    • 默认级别:没有修饰符号,向同一个包的类公开
    • 私有级别:用private修饰,只有类本身可以访问,不对外公开

2. 访问范围

1 访问级别 访问控制修饰符 同类 同包 子类 不同包
2 公开 public
3 受保护 protected ×
4 默认 没有修饰符 × ×
5 私有 private × × ×

3. 注意事项

  • 修饰符可以用来修饰类中的属性,成员方法以及类
  • 只有默认的和public才能修饰类,并且遵循上述访问权限的特点
  • 成员方法的访问规则和属性完全一样

三、面向对象编程三大特征

1. 封装

  • 封装(encapsulation)就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作[方法],才能对数据进行操作
  • 封装可以隐藏细节:方法(连接数据库)<—调用(传入参数)
  • 封装可以对数据进行验证,保证安全合理

1.1 封装实现步骤

  • 将属性进行私有化private
  • 提供一个公共(public)的set方法,get方法
1
2
3
4
5
6
7
8
public void setXxx(类型 参数名){
//逻辑代码
属性 = 参数名;
}

public 数据类型 getXxx(){
return xxx;
}

2. 继承

  • 继承可以解决代码复用,当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可

2.1 语法

1
class 子类 extends 父类{}
  • 子类就会自动拥有父类定义的属性和方法
  • 父类又叫超类,基类
  • 子类又叫派生类

2.2 注意事项

  • 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问

  • 子类必须调用父类的构造器,完成父类的初始化

  • 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过

  • 如果希望指定去调用父类的某个构造器,则显式的调用一下

    • ```java
      super(参数列表)
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25

      - super在使用时,必须放在构造器第一行(super只能在构造器中使用)

      - super()和this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器

      - java所有的类都是Object的子类,Object类是所有类的基类

      - 父类的构造器的调用不限于直接父类,将一直追溯到Object类

      - 子类最多只能继承一个父类(直接继承),**java为单继承机制**

      #### 2.3 内存布局

      {% asset_img 继承的内存布局.png 继承的内存布局 %}

      #### 2.4 super关键字

      - 代表父类的引用,用于访问父类的属性、方法、构造器

      ##### 2.4.1 语法

      - 访问父类的属性,但是不能访问private属性

      ```java
      super.属性名;
  • 访问父类的方法,但是不能访问private方法

    1
    super.方法名(参数列表);
  • 访问父类的构造器

    1
    super(参数列表);//只能放在第一句,只能出现一句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Text extends A {

//访问父类的属性 但不能访问父类的private属性 [super.属性名]
public void hi() {
System.out.println(super.n1 + super.n2 + super.n3);
}

//访问父类的方法 但不能访问父类的private方法 [super.方法名(形参列表)]
public void ok() {
super.text20();
super.test100();
super.text300();
}
//
//访问父类的构造器 [super.参数列表]
//只能在构造器中使用 且必须放在第一条语句
public Text() {
//super();访问父类的无参构造器
//super("jack");访问父类的形参列表为String类型的有参构造器
super("jack" , 10);//访问父类的形参列表为String类型 和 int类型的有参构造器

}
2.4.2 注意事项
  • 分工明确,父类属性由父类初始化,子类属性由子类初始化
  • 当子类中有和父类的成员(属性和方法)重名时,访问父类的成员,需要通过super
  • super的访问不限于直接父类,其访问遵守就近原则
2.4.3 super和this的比较
No 区别 this super
1 访问属性 访问本类中的属性,如果本类没有该属性就从父类中查找 从父类开始查找属性
2 调用方法 访问本类中的方法,如果本类没有就从父类查找 从父类开始查找方法
3 调用构造器 调用本类构造器,必须放在构造器首行 调用父类的构造器,必须放在子类构造器首行
4 特殊 表示当前对象 子类访问父类对象

2.5 方法重写

  • 子类有一个方法和父类的某个方法的名称、返回类型、参数一致
1
2
3
4
5
6
7
8
9
10
class Animal{
public void cryO{
System.out.println("动物叫唤。");
}
}
class Dog extends Animal{
public void cryo{
System.out.println("小狗汪汪叫...");
}
}
2.5.1 注意事项
  • 子类的方法的形参列表方法名称,要和父类方法的形参列表,方法名称完全一样
  • 子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类,比如父类返回类型是 Object ,子类方法返回类型是String
  • 子类方法不能缩小父类方法的访问权限,但是可以扩大public > protected > 默认 > private
2.5.2 重载和重写的比较
名称 发生范围 方法名 形参列表 返回类型 修饰符
重载(overload) 本类 必须一样 类型,个数或者顺序至少有一个不同 无要求 无要求
重写(override) 父子类 必须一样 相同 子类重写的方法,返回类型和父类的返回类型一致,或为其子类 子类方法不能缩小父类方法的访问范围

3. 多态

  • 多态的前提是两个对象(类)存在继承关系

  • 一个对象的编译类型和运行类型可以不一致

  • 编译类型在定义对象的时候就确定了,不能改变
  • 运行类型可以变化
  • 编译类型看 = 号的左边,运行类型看 = 号的右边
1
2
Animal animal = new Dog(); //animal编译类型是Animal,运行类型Dog
animal = new Cat(); //animal的运行类型变成了Cat,编译类型仍然是 Animal

3.1 向上转型

  • 父类的引用指向子类的对象
3.1.1 语法
1
父类类型 引用名 = new 子类类型();
  • 可以盗用父类的所有成员(需遵守访问权限)
  • 不能调用子类中特有成员

3.2 向下转型

3.2.1 语法
1
子类类型 引用名 = (子类类型)父类引用;
  • 只能强转父类的引用,不能强转父类的对象
  • 父类的引用必须指向的是当前目标类型的对象
  • 向下转型后可以调用子类类型中的所有成员
3.2.2 注意事项
  • 属性没有重写,属性值看编译类型
1
instanceOf//比较操作符
  • 用于判断对象的运行类是否为xx类型或xx子类型
3.2.3 java的动态绑定机制
  • 当调用对象方法时,该方法会和对象的内存地址/运行类型进行绑定
  • 当调用对象属性时,没有动态绑定机制,哪里声明哪里使用
3.2.4 多态参数
  • 方法定义的形参列表为父类类型,实参类型允许为子类类型

四、Object类

1. equals方法

1.1 == 和equals的对比

  • ==:既可以判断基本类型,又可以判断引用类型

    • 如果判断基本类型,判断的是值是否相等

    • 如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象

  • equals:只能判断引用类型

  • 默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等
1
2
3
4
5
6
7
8
9
Integer integer1 = new Integer(1000);
Integer integer2 = new Integer(1000);
System.out.println(integer1 ==integer2);//false
System.out.println(integer1.equals(integer2));//true

String str1 = new String("hspedlu ");
String str2 = new String("hspedu ");
System.out.println(str1 ==str2);//false
System.out.println(str1.equals(str2));//true

2. hashCode方法

  • 提高具有哈希结构的容器的效率
  • 两个引用,如果指向的是同一个对象,则哈希值肯定是一样的
  • 两个引用,如果指向的是不同对象,则哈希值是不一样的
  • 哈希值主要根据地址号来的,不能完全将哈希值等价于地址

3. toString方法

1
全类名 + @ + 哈希值的十六进制//一般情况下会重写toString方法,用于返回对象的属性信息

4. finalize方法

  • 当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作
  • 什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法
  • 垃圾回收机制的调用,是由系统来决定(即有自己的GC算法),也可以通过System.gc()主动触发垃圾回收机制

五、断点调试

  • 在断点调试过程中,是运行状态,以对象的运行类型来执行的