Java基础学习笔记(二) o(* ̄︶ ̄*)o

101 阅读13分钟

十、面向对象

1. 面向对象概述

面向对象(Object-Oriented-Programming,简称 OOP) 是软件开发中的一类编程思想、开发范式。它将现实世界中的事物抽象为 “对象”,通过对象之间的交互来实现功能。其核心是以 “对象” 为中心,强调事物的属性行为,并通过封装、继承、多态三大特性提高代码的可维护性、复用性和灵活性。

封装(Encapsulation)

  • 定义:将对象的属性和行为隐藏在类内部,仅通过公共接口(如方法)对外暴露必要的功能,限制外部直接访问内部细节;
  • 作用:保护数据安全性,避免外部随意修改,同时降低代码耦合度。
  • 实现:通过访问修饰符(如privatepublic)控制访问权限。

耦合度是指程序中,某一模块与另一模块之间信息或参数依赖的程度

继承(Inheritance)

  • 定义:子类可以继承父类的属性和方法,并可以新增自己的属性或重写父类的方法;
  • 作用:代码复用,减少重复代码(如“大学生类”继承“学生类”,“高中生类”也可以继承 “学生类”);
  • 实现:通过extends关键字,在 Java 中一个子类只能继承一个父类(单继承)。

多态(Polymorphism)

  • 定义:同一方法在不同对象上有不同的实现方式,即 “一个接口,多种实现”;
  • 作用:提高代码灵活性和扩展性,允许用父类引用指向子类对象,简化调用逻辑;
  • 实现:通过方法重写Overrite(子类重写父类方法)和接口实现implements(不同类实现同一接口)实现。

除了面向对象,还有面向过程指令式编程函数式编程。在所有的编程范式中,我们接触最多的还是面向过程和面向对象两种。

维度面向过程(Procedure-Oriented-Programming)面向对象(Object-Oriented-Programming)
核心以 “过程” 为中心,强调步骤和函数以 “对象” 为中心,强调事物的属性和行为
特点代码模块化(函数),数据与操作分离代码封装为类,数据与操作绑定
适用场景简单程序(如计算器、脚本)复杂程序(如电商系统、游戏)
扩展性修改难度大,牵一发而动全身易扩展,通过继承、多态灵活扩展功能

面向对象面向过程二者相辅相成,并非是对立的关系!

2. Java语言的基本元素(类、对象)

2.1 核心概念

类(Class)

  • 定义:对一类具有相同属性和行为的对象的抽象描述,是对象的模板;
  • 方便理解:人类,灵长类等;
  • 举例:“学生类” 定义了所有学生共有的属性(姓名、年龄等)和行为(上课、考试等);

对象(Object)

  • 定义:具体的事物或抽象的概念,具有属性和行为;
  • 方便理解:一个名叫张三的人,一只5岁的黑猩猩等;
  • 举例:“学生对象 张三” 是一个具体的学生,是学生类的实例化对象;

2.2 类的概述

类(class)是一组相关属性行为的集合,这也是类最基本的两个成员;

属性:是类中定义的变量,用于存储对象的状态。也称为 “成员变量”

  • 属性 <=> 成员变量 <=> Field

行为:是类中定义的方法,用于描述对象的行为。也称为 “成员方法”

  • 行为 <=> 成员方法 <=> Method

类的声明

[权限修饰符] class 类名 {
    属性声明;
    方法声明;
}

-- 举例 --
public class Person {
    String name;// 属性(成员变量)name
    int age;// 属性(成员变量)age
    
    // 行为(成员方法)showName
    public void showName() {
        System.out.println("name =" + name);
    }
    
    // 行为(成员方法)showAge
    public void showAge() {
        System.out.println("age =" + age);
    }
}

2.3 对象的概述

对象(Object)是类的实例化结果,可以将理解为现实世界中具体存在的事物在程序中的抽象表示。

特点

  • 封装性:对象将数据(属性)和操作数据的方法封装在一起,对外隐藏内部实现细节。
  • 独立性:每个对象都是独立的个体,拥有自己的属性值,不同对象之间互不干扰。
  • 交互性:对象之间可以通过方法调用进行交互,协作完成复杂功能。

对象的创建
在 Java 中,通过 new 关键字创建对象,语法如下:

类名 对象名 = new 类名();

// 举例:创建Person类的实例对象
Person person = new Person();

对象的使用

  • 访问属性:通过 对象名.属性名 访问或修改对象的状态
  • 调用方法:通过 对象名.方法名() 让对象执行特定操作
// 举例:创建Person类的实例对象
Person person = new Person();

// 获取person对象的name属性
String name = person.name;
// 将person对象的name属性修改为“张三”
person.name = "张三";
// 调用person对象的showName方法
person.showName();

3. 对象的内存解析

3.1 JVM内存结构划分

HotSpot JVM(Java虚拟机)的架构图如下:

20250820152019.png

其中我们主要关心的是运行时数据区部分(Runtime Data Area)。

  • 栈(Stack):是指虚拟机栈,用于存储局部变量等。局部变量表存放了编译期可知长度的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不是对象本身,而是对象在堆内存的首地址)。方法执行完成后,自动释放。

  • 堆(Heap):此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。

  • 方法区(Method Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

3.2 代码内存解析

示例代码:

// 定义一个“人”类
class Person {
    String name;
    int age;
}

// 定义一个测试类,在测试类中使用 main 方法执行具体代码
public void Test {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.name = "TheShy";
        p1.age = 25;
        
        Person p2 = new Person();
        p2.name = "clearlove7";
        p2.name = 32;
        
        P2 = P1;
        
        Person p3 = new Person();
    }
}

内存解析流程图:

wechat_2025-08-28_103544_419.png

Tips:

  • 新创建一个类的多个对象时(比如p1、p2),则每个对象都拥有当前类的一个“副本”,多个对象之间互不影响,当修改其中一个对象的属性时,不会影响其它对象此属性的值。
  • 当一个变量指向另一个变量进行赋值时(比如p2 = p1),此时并没有在堆空间中创建新的对象,而是两个变量共同指向了堆空间中同一个对象。此时,通过其中一个变量修改指向对象的属性时,将会影响所有指向该对象的变量的调用。

3.3 对象数组

数组的元素可以是 基本数据类型,也可以是 引用数据类型

当元素是引用数据类型中的类时,我们称为 对象数组

示例:

public class Person() {
    int number; //编号
    int age; //年龄
}

public class Test() {
    Person[] personArr = new Person[8];
    for (int i = 0; i < personArr.length; i++) {
        personArr[i] = new Person();
        personArr[i].number = i;
        personArr[i].age = i+20;
    }
}

内存解析:

image.png

Tips:

  • 定义对象数组时,必须确定数组长度,否则对象数组为null

4. 类的成员之一:变量

前面我们提到 “属性,即是类中定义的变量”,在Java中,可分为成员变量局部变量两种变量。

变量的声明格式

[修饰符] 数据类型 变量名 [= 初始化值]; 

4.1 成员变量和局部变量

位置在类中,方法体外 的变量,即为 成员变量;

位置在类中,方法体内 的变量,即为 局部变量。

示例:

public class Person {
    String name; // 成员变量1
    int age; // 成员变量2
    
    public void sayHello(String yourName) { // 局部变量1
        String info = "hello!"; // 局部变量2
        System.out.println(info + yourName);
    }
}

4.2 成员变量 VS 局部变量

相同点:

  • 声明格式相同,所有变量的声明格式都是移植的
  • 所有变量都仅在其自己的作用域内有效

不同点:

  • 位置不同

    • 成员变量的位置是,在类中,方法体外的变量
    • 局部变量的位置是,在类中,方法体内的变量(代码块中也属于局部变量)
  • 内存中存储位置不同

    • 成员变量在内存中存储于堆内存
    • 局部变量在内存在存储于栈内存
  • 生命周期不同

    • 成员变量与对象的生命周期一致,跟随对象的创建而产生,跟随对象的销毁而销毁;即使多个对象的数据类型相同,但每个对象的成员变量独立存在
    • 局部变量与方法的执行周期一致,跟随方法的调用而产生,跟随方法的结束而销毁。即使多次方法的调用,但每次方法调用的局部变量独立存在
  • 作用域不同

    • 成员变量在本类中可直接调用,其他类中获取方式有 对象.变量名get方法
    • 局部变量仅在本方法中可调用
  • 可用修饰符不同

    • 成员变量:public,privite,final,static,volatile
    • 局部变量:final
  • 默认值不同

    • 成员变量有默认值,引用数据类型的默认值为null
    • 局部变量无默认值,只有在方法被调用时才有意义,其中形参的依靠实参进行初始化

5. 类的成员之一:方法

前面我们提到 “行为,即是是类中定义的方法”,在其他语言中也常称为函数过程

5.1 什么是方法?

  • 方法是一个类行为特征的抽象,用来完成某个功能或一组操作
  • 方法存在的目的是为了实现代码重用,减少冗余
  • 在Java中,方法无法独立存在,必须定义在类中

方法声明的格式

权限修饰符 [其他修饰符] 返回值类型 方法名(形参列表) [throws 异常列表] {
    // 方法体
    [return xxx;] //当返回值类型不为void时,方法体中必须使用return结束方法进行返回
}

注:[]表示非必填
权限修饰符:publicprotected、缺省、private
其他修饰符:staticfinal等
返回值类型:基本数据类型、引用数据类型、void表示无返回值
方法名:该方法的标识符
形参列表:调用该方法需要传递的参数,可无
异常列表:后续讲解
方法体:整个方法的核心,方法体中的内容决定该方法可以干什么
return1. 作用是结束方法的执行,同时将方法的结果返回
    2. 当返回值类型为void时,该方法可以没有return或直接写 "return;"
    3. 当返回值类型为基本数据类型或引用数据类型时,该方法必须有"return xxx;",其中"xxx"的数据类型必须与返回值类型一致
    4. return语句后面的"所有代码将不会执行!且不可再编写代码!"

方法的举例:

  • Math.random()的random()方法
  • Math.sqrt(x)的sqrt(x)方法
  • Arrays类中的sort()、equals()方法
  • 类中常见的get、set方法

5.2 方法的调用

方法调用格式:对象.方面名(参数);

示例:

/**
 * 方法调用案例演示
 */
public class MethodInvokeDemo {
    public static void main(String[] args) {
        System.out.println("-----------------------方法调用演示-------------------------");

        //调用Demo类中无参无返回值的方法sayHello,调用一次,执行一次,不调用不执行
        Demo md = new Demo();
        md.sayHello();
        //调用Demo类中有参无返回值的方法sayHello,调用一次,执行一次,不调用不执行
        String name = "刘旭涛";
        int age = 25;
        md.sayHello(name,age);
        //调用Demo类中有参无返回值的方法sayHello,调用一次,执行一次,不调用不执行
        String name = "刘旭涛";
        int age = 25;
        String info = md.sayHello(name,age);
        //举例 info 的内容为:大家好,我是刘旭涛,我今年25岁
    }
}

5.3 方法相关的注意事项

  • 必须先声明后使用,且方法必须定义在类的内部
  • 调用一次就执行一次,不调用不执行
  • 方法中可以调用类中的方法或属性,不可以在方法内部定义方法

5.4 方法中的 return 语句

  • 作用: 结束一个方法,同时返回一个结果
  • 当返回值类型为void时,该方法可以没有return或直接写 "return;"
  • 当返回值类型为基本数据类型或引用数据类型时,该方法必须有"return xxx;",其中"xxx"的数据类型必须与返回值类型一致
  • return语句后面的"所有代码将不会执行!且不可再编写代码!"

5.5 方法调用的内存解析

  • 方法在未被调用的时候,都在方法区中的字节码(.class)文件中存放
  • 方法在被调用的时候,需要进入栈内存中执行,称之为入栈,即在栈内存中开辟独立的内存供该方法执行,该内存中将存储该方法执行过程中产生的局部变量等
  • 方法在被调用结束的时候,会释放刚才分配的内存,称之为出栈。当该方法有返回值时,会将返回值返回至调用处;当没有返回值时,则继续执行调用处的后续代码
  • 栈结果的特点:先进后出,后进先出

示例代码:

public class Person {
    String name;
    
    /**
    * 调用eat方法时,会先调用sleep方法,再执行打印睡醒了
    */
    public void eat() {
        sleep();
        System.out.println(name+"睡醒了,可以吃饭了!");
    }
    /**
    * 调用sleep方法时,会先调用sport方法,再执行打印运动结束
    */
    public void sleep() {
        sport();
        System.out.println(name+"运动结束,可以睡觉了!");
    }
    /**
    * 调用sport方法时,直接打印开始运动
    */
    public void sport() {
        System.out.println(name+"开始运动!");
    }
}

public class Test {
    public static void main() {
        Person p1 = new Person();
        p1.eat();
    }
}

内存解析图:

image.png

5.6 方法进阶

5.6.1 方法的重载

概念: 在一个类中,允许存在相同方法名的方法,前提是他们的形参列表不相同

意味着,当一个类中的多个方法的方法名相同,但形参列表各不相同时,我们称之为方法的 重载

在方法被调用时,JVM 通过形参列表调用最匹配的方法,先找形参个数、类型最匹配的,其次找个数和类型可兼容的,多个兼容时会报错。例如:形参为int、double、long 等类型时。

5.6.2 可变个数形参

在JDK5版本中,新增了 “Varargs(variable number of arguments)” 机制,即当定义一个方法时,形参列表的个数可动态不确定,通俗讲就是 可变个数形参

格式:

方法名(参数类型... 参数名)

举例1:
add(int... numbers) {
    //方法体
}
举例2:
add(String name, int... numbers) {
    //方法体
}

Tips:

  • 可变个数形参等同于数组参数,二者不可同时存在
  • 可变个数形参必须声明在参数列表的最后
  • 一个方法中只能存在一个可变个数形参

7.方法进阶

十一、异常

十二、多线程

十三、常用类与基础API

十四、集合框架

十五、泛型

十六、数据结构与集合源码

十七、File类与IO流

十八、网络编程

十九、反射机制

二十、JDK新特性