0%

Java基础--05面向对象

1 程序设计的开发范式(面向对象、面向过程……)

  1. 面向过程 POP

    image-20230728105140135

  2. 面向对象 OOP

    image-20230728105212908

  3. 指令式编程

  4. 函数式编程

2 面向对象-基础

面向对象是抽象化的过程

  • Java 类和类的成员:属性、方法、构造器、代码块、内部类
  • [面向对象的特征](.\06 面向对象特性.md):封装、继承、多态、(抽象)
  • 其他关键字:this、super、package、import、private、public、static、final、interface、enum、abstract。。。

2.1 类和对象

类(class)对象(Object)是面向对象的核心概念。

  • 类是具有相同特征的事物的抽象描述,是抽象的,概念上的定义。
    • 属性Field
    • 方法Method
    • 构造器Constructor
1
2
3
4
5
6
7
8
9
@Data	// getUser() 方法
// User() 构造器
public class User { // User 类 抽象出来的
private String name; // name 属性

public static void main(String[] args) {
User user = new User(); // user 对象实例 具体的
}
}
  • 对象是实际存在的该类事物的每个个体,是具体的,也叫实例(instance)

2.2 类和对象的内存解析

2.2.1 对象的内存解析—-对象入堆

  • 堆(heap):new出来的结构,如对象中的属性。
  • 栈(stack):方法内定义的变量,存储在栈中。
  • 方法区(method area):存放类的模板?
  1. 创建类的一个对象,并赋值:

    image-20230728112624646

  2. 创建类的多个对象,赋值

    image-20230728112928228

2.2.2 方法调用的内存解析—-方法入栈

  • 形参
  • 实参
  1. 对象调用方法的过程

    image-20230728152501135

2.2.3 对象数组的内存解析

image-20230728153325305

企业真题:

  1. Java内存结构:01. Java和JVM
  2. main方法可以将public替换成private,变成普通方法,不再是程序入库。

3. 面向对象-进阶

3.1 this 关键字、super关键字

  • this:调用自己的属性、方法、构造器,当属性名和方法形参名一致时必须使用this来区分
  • super:调用父类的属性、方法、构造器
  • 在子类的构造方法中,首行要么使用this,要么使用super。

3.2 重写和重载

  • 在方法名,参数列表,返回类型(除过子类中方法的返回值是父类中方法返回值的子类时)都相同的情况下, 对方法体进行修改或重写,这就是重写。要注意子类函数的访问修饰权限不能少于父类的。
  • 一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载。同时,重载对返回类型没有要求,可以相同也可以不同,但不能通过返回类型是否相同来判断重载

3.3 子类对象实例化的全过程

  • 从结果的角度看,体现了类的继承性:创建子类对象后,子类对象获取了父类中声明的所有属性和方法,在权限允许时可调用。
  • 从过程的角度看:当通过子类的构造器创建对象时,子类的构造器一定会直接或间接的调用父类的构造器……直到调用了Object 类中的构造器为止。正因为我们调用过父类的构造器,所以会将父类中声明的所有属性和方法加载到内存中。

3.4 Object类

Java 中声明的类,如果没有显示的声明其父类,默认继承于Object 类(java,lang.Object)。

  • clone():不是复制地址,在堆空间创建一个相同的实例对象。
  • equals(xx)和hashCode()
  • toString()
  • finalize():垃圾回收器GC要回收此对象时,调用如下的方法;子类重写此方法,可在释放对象前进行某些操作。9+不建议了,可能导致内部出现循环引用,导致此对象无法回收。
  • getClass()
  • wait() \ wait(xx) \ notify() \ notifyAll():线程睡眠和唤醒

企业真题:

  1. == 和equals的区别
    • ==是运算符,适用于基本数据类型和引用数据类型。
    • 基本数据类型判断数值是否相等(自动类型提升可比较不同基本数据类型char c1 = 'A'; int i = 65; sout(c1 == i); // true)。
    • 引用数据类型比较两个引用变量的地址值是否相等。
    • equals是方法,适用于引用数据类型。

临时思考:

  1. Object中equals如下,一个实例对象指向其在堆空间中的首地址,故如果没有重定义equals,则只有同一个实例对象才会返回true。
1
2
3
public boolean equals(Object obj) {
return (this == obj);
}
  1. 堆内存空间释放后,物理内存未及时返还。每次调用GC回收,观察到堆内存确实释放了,但是物理内存每次都增加了。参考:运维:你们 JAVA 服务内存占用太高,还只增不减!告警了,快来接锅 - 个人文章 - SegmentFault 思否
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
26
27
private List<SdResultPo> tempList;
public AjaxResult importDataTxt(MultipartFile multipartFile) throws Exception {
if (multipartFile == null || multipartFile.isEmpty()) {
return AjaxResult.error("文件不能为空");
}
// 清楚了对旧的全部实例的引用
tempList = null; // 清楚 tempList 的引用
List<SdResultPo> sdResultPoList = new ArrayList<>();

try (InputStream is = multipartFile.getInputStream();
InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(isr)) {
String line;
while ((line = reader.readLine()) != null) {
SdResultPo sdResultPo = new SdResultPo(); // 每一次都会在堆空间创建一个新的实例对象
sdResultPoList.add(sdResultPo);
}
} catch (IOException e) {
return AjaxResult.error("文件读取错误");
}

// 这里应该将sdResultPoList传递给对应的服务方法,进行进一步的处理。
// 这是一个假设的服务方法,实际的方法可能会有所不同。
tempList = sdResultPoList;
System.gc();
return AjaxResult.success();
}

image-20230731105820012image-20230731105909896

4. 面向对象-高级

跳过

  1. static关键字
  2. 代码块
  3. final关键字
  4. 抽象类和抽象方法abstract
  5. 接口interface:接口的本质是契约、标准、规范,就像我们的法律一样。制定好后大家都要遵守。
  6. 内部类

4.1 单例设计模式(等复习算法)

4.2 模板方法设计模式(等复习算法)

4.3 枚举类enum:定义的是枚举实例

枚举类必须在开头实现多个对象,对象间用,隔开

  • name():获取实例名称

  • values():获取所有的枚举实例数组

  • valueOf(String objName):获取指定的枚举实例

  • 枚举类实现接口

    1. 枚举类重写接口方法,不同枚举对象调用方法,执行的是同一个方法。
    2. 每一个枚举对象也可单独重写接口方法

4.4 注解

  • 基本注解:@Override等
  • 自定义注解
1
2
3
4
5
6
7
8
9
10
/**
* 自定义导出Excel数据注解
*
* @author ruoyi
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Excel
{
}
  • 元注解:对现有的注解进行解释说明的注解。@Target、@Retention、@Documented、@Inherited
    • @Target:注解能修饰的结构
    • @Retention:注解保留的时间
  • 框架:注解 + 反射 + 设计模式

4.5 JUnit 单元测试

测试分为黑盒测试和白盒测试。JUnit 单元测试属于白盒测试。

4.6 包装类

  1. 为什么需要包装类?

java 中有基本数据类型和引用数据类型。使用基本数据类型在于效率,但是在使用只针对对象设计的API或新特性(例如泛型)时,怎么办?转包装类。

Object的equals方法和List的add方法。

但是包装类是无法使用 +- 等运算的,所以包装类有时候也要转化为基本数据类型

包装类默认值是null

  1. 包装类
基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
boolean Boolean
char Character

内存分析

image-20230731162653804

  1. String 与基本数据类型和包装类型间的转换
  • 基本数据类型 –> 包装类:调用包装类的valueOf方法

  • 包装类 –> 基本数据类型:调研包装类的xxxValue()

  • 自动装箱、自动拆箱

    1
    2
    3
    int i = 1;
    Integer i2 = i; // 自动装箱
    int i3 = i2; // 自动拆箱

image-20230731164052832

5. 企业真题

  1. 抽象类和接口的对比。

    抽象类和接口都不能被实例化,但可以定义抽象类和接口类型的引用。

    一个类如果继承了抽象类,必须要对其中的抽象方法全部实现,否则该类仍然需要被声明为抽象类。如果实现了接口,也必须要对其中的抽象方法全部实现,否则编译错误。(接口中方法默认的是public abstract修饰的)

    抽象类可以有构造方法,抽象方法和具体方法。

      接口不能有构造方法,而且其中的方法全部都是抽象方法。(接口中方法默认的是public abstract修饰的)(jdk8可以default定义默认实现)

    抽象类中的成员可以使private、默认、protected、public的。接口中的成员全部都是public的。(jdk9,接口可以声明为private的)

    抽象类可以 定义成员变量。接口中定义的成员变量其实都是常量。(接口中的成员变量默认是public static final 修饰的 )

    image-20230731175327979

  2. 静态变量和实例变量的区别。

  3. 静态方法不能被重写。

  4. static调用非static方法,只能通过新建对象来调用非静态方法。

  5. 静态代码块、代码块、构造器执行顺序:静态代码块、代码块、构造器