一、面向对象OOP

​ 面向对象以校园管理系统为例,变量之间的关联性不明确,无法将他们作为一个整体来处理,如果学生的信息量很大,那么会出现代码冗余和难以维护的问题。

​ 变量的内存空间随机分配,在设置变量时,他们的存储位置不相邻。

/**
 * @document: 分离变量来存储学生信息
 * @Author:SmallG
 * @CreateTime:2023/7/25+9:19
 */

public class Demo01 {
    public static void main(String[] args) {
        //定义一个学生
        String name1 ="tom";
        int age1 = 22;
        char gender1 = '男';
        double score1 = 85.5;

        //定义另一名学生
        String name2 = "Jerry";
        int age2 = 21;
        char gender2 = '男';
        double score2 =86.5;

        //输出第一名学生的信息
        System.out.println("姓名:"+name1);
        System.out.println("年龄:"+age1);
        System.out.println("性别:"+gender1);
        System.out.println("成绩:"+score1);

        //输出第二名学生的信息
        System.out.println("姓名:"+name2);
        System.out.println("年龄:"+age2);
        System.out.println("性别:"+gender2);
        System.out.println("成绩:"+score2);
    }
}

面向对象概述

​ 面向对象编程的核心思想是将数据和操作数据的方法封装到一起,形成称为对象的实体。

​ 面向对象的三大特点:封装、继承、多态

封装:将数据和对数据的操作封装在一个单元中,只暴露必要的接口供外部访问,可以确保数据的安全性和一致性。通过类的实例化创建对象。

继承:继承允许一个类继承另一个类的属性和方法,实现代码的重用和扩展。

多态:同一个方法可以在不同的对象上具有不同的行为。多态性使得不同类型的对象可以以统一的方式进行操作,提高代码的灵活性和可扩展性。

二、类和对象

1、类

类是创建对象的模版和蓝图,它定义了对象的属性和行为。

对象是类的实例化结果,它是类的具体实体。

/**
 * @document: 定义一个类,一个java程序可以定义多个类,但是只能有一个public类
 * 程序的入口main方法在public声明的类中。
 * @Author:SmallG
 * @CreateTime:2023/7/25+10:21
 */

public class Demo02 {
    public static void main(String[] args) {

    }
}

//定义(声明)一个类
class Student {
    //属性(变量)
    String name; //名字
    int age;     //年龄
    char gender; //性别
    double score;//成绩
}

//定义教师类
class Teacher {
    String name;
    int age;
    char gender;
    double salary; //薪水
}

2、对象

创建对象的过程通常被称为“实例化”

局部变量需要初始化才能使用,类中的成员属性不需要初始化,它有默认值。

3、引用类型

引用类型是一种操作对象的数据类型,与基本数据类型相比,基本数据类型存储内容直接存储到相应位置,引用数据类型存储的是对象的引用或内存地址,也就是说引用类型开辟了两个内存空间一个存对象的首地址,一个存数据

/**
 * @document: 定义一个类,一个java程序可以定义多个类,但是只能有一个public类
 * 程序的入口main方法在public声明的类中。
 * @Author:SmallG
 * @CreateTime:2023/7/25+10:21
 */

public class Demo02 {
    public static void main(String[] args) {
        //创建学生对象
        Student student1 = new Student();
        //为对象的属性赋值 field(属性)
        student1.name = "Tom";
        student1.age = 22;
        student1.gender = '男';
        student1.score = 85.5;

        Student student2 = new Student();
        student2.name = "Jerry";
        student2.age = 21;
        student2.score = 86.5;
        student2.gender = '男';

        System.out.println("学生1的信息");
        System.out.println("姓名:" + student1.name);
        System.out.println("性别:" + student1.gender);
        System.out.println("年龄:" + student1.age);
        System.out.println("成绩:" + student1.score);

        System.out.println("学生2的信息");
        System.out.println("姓名:" + student2.name);
        System.out.println("性别:" + student2.gender);
        System.out.println("年龄:" + student2.age);
        System.out.println("成绩:" + student2.score);

    }
}

//定义(声明)一个类
class Student {
    //属性(变量)
    String name; //名字
    int age;     //年龄
    char gender; //性别
    double score;
}

//定义教师类
class Teacher {
    String name;
    int age;
    char gender;
    double salary; //薪水
}

4、构造器

是一种特殊的方法,用于封装对象属性的初始化过程,也叫构造方法。构造器的名称与类名相同,并且没有返回类型声明。

public class Demo02 {
    public static void main(String[] args) {
        Student student1 =new  Student("Tom",21,'男',85.5);
        Student student2 =new  Student("Jerry",19,'男',86.5);
        System.out.println("学生1的信息");
        System.out.println("姓名:" + student1.name);
        System.out.println("性别:" + student1.gender);
        System.out.println("年龄:" + student1.age);
        System.out.println("成绩:" + student1.score);

        System.out.println("学生2的信息");
        System.out.println("姓名:" + student2.name);
        System.out.println("性别:" + student2.gender);
        System.out.println("年龄:" + student2.age);
        System.out.println("成绩:" + student2.score);

    }
}

//定义(声明)一个类
class Student {

    //属性(变量)
    String name; //名字
    int age;     //年龄
    char gender; //性别
    double score;

    //定义一个构造方法
    public Student(String name_, int age_, char gender_, double score_) {
        //为属性赋值
        name = name_;
        age = age_;
        gender = gender_;
        score = score_;
    }

}

//定义教师类
class Teacher {
    String name;
    int age;
    char gender;
    double salary; //薪水
}

5、this关键字

用在构造器中,引用当前对象实例,用于访问当前对象的属性和方法,以后的构造方法中的参数的名字和类中的属性名都是一致的。

/**
 * @document: 定义一个类,一个java程序可以定义多个类,但是只能有一个public类
 * 程序的入口main方法在public声明的类中。
 * @Author:SmallG
 * @CreateTime:2023/7/25+10:21
 */

public class Demo02 {
    public static void main(String[] args) {
        Student student1 =new  Student("Tom",21,'男',85.5);
        Student student2 =new  Student("Jerry",19,'男',86.5);
        System.out.println("学生1的信息");
        System.out.println("姓名:" + student1.name);
        System.out.println("性别:" + student1.gender);
        System.out.println("年龄:" + student1.age);
        System.out.println("成绩:" + student1.score);

        System.out.println("学生2的信息");
        System.out.println("姓名:" + student2.name);
        System.out.println("性别:" + student2.gender);
        System.out.println("年龄:" + student2.age);
        System.out.println("成绩:" + student2.score);

    }
}

//定义(声明)一个类
class Student {

    //属性(变量)
    String name; //名字
    int age;     //年龄
    char gender; //性别
    double score;

    //定义一个构造方法
    public Student(String name, int age, char gender, double score) {
        //为属性赋值,this为创建的对象
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.score = score;
    }

}

//定义教师类
class Teacher {
    String name;
    int age;
    char gender;
    double salary; //薪水
}

6、默认构造器

如果一个类没有声明任何构造器,那么系统会生成一个默认构造器。

如果类中定义了构造器,则不再添加默认构造器,需要自己添加一个默认构造器。

/**
 * @document: 定义一个类,一个java程序可以定义多个类,但是只能有一个public类
 * 程序的入口main方法在public声明的类中。
 * @Author:SmallG
 * @CreateTime:2023/7/25+10:21
 */

public class Demo02 {
    public static void main(String[] args) {
        Student student1 = new Student("Tom", 21, '男', 85.5);
        Student student2 = new Student("Jerry", 19, '男', 86.5);
        System.out.println("学生1的信息");
        System.out.println("姓名:" + student1.name);
        System.out.println("性别:" + student1.gender);
        System.out.println("年龄:" + student1.age);
        System.out.println("成绩:" + student1.score);

        System.out.println("学生2的信息");
        System.out.println("姓名:" + student2.name);
        System.out.println("性别:" + student2.gender);
        System.out.println("年龄:" + student2.age);
        System.out.println("成绩:" + student2.score);

        //默认构造器
        Teacher teacher1 = new Teacher();

    }
}

//定义(声明)一个类
class Student {

    //属性(变量)
    String name; //名字
    int age;     //年龄
    char gender; //性别
    double score;
    
    //默认构造器
    public Student(){
        
    }
    //构造器
    public Student(String name, int age, char gender, double score) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.score = score;
    }

}

//定义教师类
class Teacher {
    String name;
    int age;
    char gender;
    double salary; //薪水
}

7、构造器重载

指在一个类中同时声明多个参数不同的构造器。构造器重载的好处是可以有更多的对象创建方式,使用起来更加灵活方便,用this时慎重。

/**
 * @document: 定义一个类,一个java程序可以定义多个类,但是只能有一个public类
 * 程序的入口main方法在public声明的类中。
 * @Author:SmallG
 * @CreateTime:2023/7/25+10:21
 */

public class Demo02 {
    public static void main(String[] args) {
        //创建一个学生对象 只提供了姓名 设置学生的年龄默认为18
        Student student4 = new Student("Spike");
        System.out.println("学生4的信息");
        System.out.println("姓名:" + student4.name);
        System.out.println("年龄:" + student4.age);
    }
}

//定义(声明)一个类
class Student {

    //属性(变量)
    String name; //名字
    int age;     //年龄
    char gender; //性别
    double score;

    //默认构造器
    public Student(){

    }
    //只有名字的构造器
    public Student(String name) {
        this(18); //调用只有年龄参数的构造器 this必须写在第一行
        this.name = name;
    }
    //只有年龄的构造器
    public Student(int age) {
        this.age = age;
    }

    public Student(String name, int age, char gender, double score) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.score = score;
    }

}

三、方法的声明和调用

1、声明方法

定义方法五要素:修饰词、返回值类型、方法名、参数列表、方法体

public    static    int        sum    (int num1,int num2){
//    修饰词        返回值类型   方法名     参数列表
         方法体
}
/**
 * @document: 方法
 * @Author:SmallG
 * @CreateTime:2023/7/25+15:14
 */

public class Demo03 {
    public static void main(String[] args) {
        //调用方法首先要创建对象
        Person person = new Person();
        //调用方法
        person.say();
        person.talk("SmallG");
        int sum = person.sum(1, 2);
        System.out.println(sum);
    }
}

class Person {
    //定义一个无参方法
    public void say() {
        System.out.println("Hello World");
    }

    //定义一个有参的方法
    public void talk(String name) {
        System.out.println("My name is " + name);
    }

    //定义包含多个参数的方法
    public int sum(int num1, int num2) {
        return num1 + num2;
    }
}

银行实例练习:

/**
 * @document: 银行账户
 * @Author:SmallG
 * @CreateTime:2023/7/25+15:31
 */

public class Account {
    double balance; //账户余额
    String log; //账户日志

    public Account() {
        this.balance = 1000.0; //初始余额
    }

    //存钱的方法 第一参数是存钱金额  第二参是交易记录
    public void add(double amount, String message) {
        this.balance += amount;
        this.log += "收入:" + amount + ",当前余额:" + balance + ",备注:" + message;
        System.out.println(log);

    }

    //查看余额是否充足
    public boolean isEnough(double amount) {
        boolean isEnough = this.balance - amount >= 0;
        return isEnough;
    }
}

2、方法的重载

一个类中,不可以有两个方法的签名完全相同,如果一个类的两个方法知识方法名相同,而参数列表不同是可以的。不同指的是类型和个数至少有一个不同。

/**
 * @document: 银行账户
 * @Author:SmallG
 * @CreateTime:2023/7/25+15:31
 */

public class Account {
    double balance; //账户余额
    String log; //账户日志

    public Account() {
        this.balance = 1000.0; //初始余额
    }

    //存钱的方法 第一参数是存钱金额  第二参是交易记录
    public void add(double amount, String message) {
        this.balance += amount;
        this.log += "收入:" + amount + ",当前余额:" + balance + ",备注:" + message;
        System.out.println(log);
    }
    //方法的重载 没有备注的存钱
    public void add(double amount) {
        this.balance += amount;
        this.log += "收入:" + amount + ",当前余额:" + balance+"备注:无";
        System.out.println(log);
    }

    //查看余额是否充足
    public boolean isEnough(double amount) {
        boolean isEnough = this.balance - amount >= 0;
        return isEnough;
    }
}

四、Java对象内存管理

1、内存管理规则

JVM内存分为3个区域:方法区、栈、堆

1、方法区是一个静态区,Java的类(.class)以及类中方法都加载到这个区域,在使用类之前Java会将类自动加载到方法区,只加载一次。

2、栈是Java局部变量的空间,局部变量是指在方法中声明的变量,包括方法参数和this都是局部变量。在方法运行期间所有局部变量都在栈中分配,当方法结束时候方法中分配的局部变量

3、堆是Java对象空间,Java的全部对象都在堆中分配,按照对象的属性在堆内存中分配对象的存储空间。对象使用以后,当对象不再被引用时候,对象变成内存垃圾,Java垃圾回收器会自动回收内存垃圾。

2、*创建对象的过程

创建对象过程

具体流程如下:

  • 把Memory.class文件和Person.class文件加载进内存的方法区
  • 在栈内存中,开辟空间,存放变量p
  • 在堆内存中,开辟空间,存放Person对象
  • 对成员变量进行默认的初始化
  • 对成员变量进行显式初始化
  • 执行构造方法
  • 堆内存完成
  • 把堆内存的地址值赋值给变量p ,p就是一个引用变量,引用了Person对象的地址值

3、堆内存

用于存储使用new关键字所创建的对象

4、成员变量的生命周期

从对象在堆中创建开始到对象从堆中被回收结束。

Person   p  =  new  Person();
p = null ;  
//不再指向刚分配的对象空间,成员变量失效

5、垃圾回收机制(GC)

是JVM自带的一个线程(自动运行的程序),用于回收没有任何引用指向的对象。垃圾回收机制自动进行回收管理。

6、内存泄露和内存溢出

内存泄露是指,不再被使用的内存没有被及时的回收,严重的内存泄露会因过多的内存占用而导致程序的崩溃。在程序中应该尽量避免不必要的内存浪费。

GC线程判断对象是否可以被回收的依据是该对象是否有引用来指向,因此,当确定该对象不再使用时,应该及时的将其引用设置为null,这样,该对象即不再被引用,属于可回收的范围。

7、栈

栈在运行结束后自动就没了,不用垃圾回收机制进行回收。

8、*成员变量和局部变量

成员变量与局部变量的差别如下:

局部变量:

  • 定义在方法中
  • 没有默认值,必须自行设定初始值
  • 方法被调用时,存在栈中,方法调用结束时局部变量从栈中清除

成员变量:

  • 定义在类中,方法外
  • 由系统设定默认初始值,可以不显式初始化
  • 所在类被实例化后,存在堆中,对象被回收时,成员变量失效

五、练习

1 设计类并创建对象

定义一个手机(Phone)类,要求:

  • 包含属性为:品牌brand、型号style、价格price、硬盘大小diskSize(单位默认为GB)
  • 包含一个方法showInfo,以字符串形式返回当前手机的全部信息
  • 包含一个无参构造器和一个带4个参数的构造器,用于简化对象的创建

再编写一个测试类,在类中创建一个手机对象,并在控制台输出该手机对象的全部信息,运行效果如下所示:

练习1

/**
 * @document: 设计类并创建对象
 * @Author:SmallG
 * @CreateTime:2023/7/25+8:14
 */

public class Phone {
    static String brand; //品牌
    static String style; //型号
    static double price; //价格
    static int diskSize; //硬盘大小

    public Phone() {
    }

    //构造器
    public Phone(String brand, String style, double price, int diskSize) {
        this.brand = brand;
        this.style = style;
        this.price = price;
        this.diskSize = diskSize;
    }

    public static String showInfo() {
        return "Phone{" +
                "brand='" + brand + '\'' +
                ", style='" + style + '\'' +
                ", price=" + price +
                ", diskSize=" + diskSize +
                '}';
    }
}
/**
 * @document: Phone类的测试类
 * @Author:SmallG
 * @CreateTime:2023/7/25+8:18
 */

public class PhoneTest {
    public static void main(String[] args) {
        Phone phone = new Phone("华为", "P30 Pro", 3999.0, 128);
        System.out.println(showInfo());
    }
}

2 学生成绩管理

模拟学生成绩管理系统:录入3名学生的成绩,并提供信息查询功能。

程序设计要求:包含3个类

1、Student 类:表示学生,用于记载学生信息

  • 包含id(整型),name(字符串),score(整型)三个属性
  • 学生的成绩范围为0-100分
  • Student类包含一个方法(getInfo),该方法以字符串形式返回当前学生的信息
/**
 * @document: 设计类并创建对象
 * @Author:SmallG
 * @CreateTime:2023/7/25+8:14
 */

public class Phone {
    static String brand; //品牌
    static String style; //型号
    static double price; //价格
    static int diskSize; //硬盘大小

    public Phone() {
    }

    //构造器
    public Phone(String brand, String style, double price, int diskSize) {
        this.brand = brand;
        this.style = style;
        this.price = price;
        this.diskSize = diskSize;
    }

    public static String showInfo() {
        return "Phone{" +
                "brand='" + brand + '\'' +
                ", style='" + style + '\'' +
                ", price=" + price +
                ", diskSize=" + diskSize +
                '}';
    }
}

2、RecordSystem 类:表示记录系统,用于提供综合服务(录入数据、查询信息等)

  • 包含一个 Student 数组类型的属性(studentArray),用于保存所有学生的信息,数组长度为3
  • 包含两个方法,分别用于录入学生成绩(addScore)和显示学生信息(showInfo)
  • addScore 方法:参数列表中包含2个整型参数,分别是学生id和学生分数,该方法的具体功能是更新studentArray数组中目标id的学生的score属性值
  • showInfo方法:参数列表中没有参数,该方法的具体功能是按学生id顺序输出全部学生信息
  • 在RecordSystem类的构造器中初始化studentArray数组,并添加3个学生对象到数组中,学生的id和姓名分别是:1 Tom,2 Jerry,3 Spike
/**
 * @document: 表示记录系统,用于提供综合服务(录入数据,查询信息等)
 * @Author:SmallG
 * @CreateTime:2023/7/25+8:32
 */

public class RecordSystem {
    //包含一个student数组类型的属性,用于保存所有学生的信息,数组长度为3
    Student[] studentArray = new Student[3];

    //初始化学生信息
    public RecordSystem() {
        studentArray[0] = new Student(1, "Tom");
        studentArray[1] = new Student(2, "Jerry");
        studentArray[2] = new Student(3, "Spike");
    }

    //方法一:录入学生成绩
    public void addScore(int id, int score) {
        //控制id和分数的范围
        if (id < 1 || id > 3) {
            System.out.println("输入有误,id超出范围!请重新输入!");
        } else if (score < 0 || score > 100) {
            System.out.println("分数录入有误,score有误!请重新输入");
        } else {
            studentArray[id - 1].score = score;
        }
    }

    //方法二:显示学生信息
    public void showInfo() {
        for (int i = 0; i < studentArray.length; i++) {
            System.out.println(studentArray[i].getInfo());
        }
    }
}

3、Main 主类

  • 包含 main 方法,用于启动程序并和用户进行交互

    • main方法中,首先创建RecordSystem类的对象和Scanner对象,然后输出菜 单,与用户进行交互

运行效果如下所示:

练习2

/**
 * @document: 学生成绩系统
 * @Author:SmallG
 * @CreateTime:2023/7/25+8:28
 */

public class Student_Grade_System {
    public static void main(String[] args) {
        RecordSystem recordSystem = new RecordSystem();
        Scanner scanner = new Scanner(System.in);

        boolean s = true;
        while (s){
            System.out.println("欢迎使用学生成绩录入系统");
            System.out.println("1 显示学生信息");
            System.out.println("2 录入学生成绩");
            System.out.println("3 退出");
            System.out.println("请输入(1-3):");
            int a = scanner.nextInt();

            switch (a) {
                case 1: //显示学生信息
                    System.out.println("---------------------------");
                    recordSystem.showInfo();
                    System.out.println("---------------------------");
                    break;
                case 2: //录入学生成绩
                    System.out.println("---------------------------");
                    System.out.println("请输入学生id和分数,用空格分隔");
                    int id = scanner.nextInt();
                    int score = scanner.nextInt();
                    recordSystem.addScore(id, score);
                    recordSystem.showInfo();
                    System.out.println("---------------------------");
                    break;

                case 3: //退出
                    System.out.println("谢谢使用");
                    System.out.println("---------------------------");
                    s = false;
                    break;
                default:
                    System.out.println("输入有误,请重新输入");
                    break;
            }
        }

    }
}

3 完善“学生成绩管理”

完善学生成绩系统系统,增加查看成绩排行功能,按照学生成绩由高到低显示学生的成绩。

提示:可能会用到快速拷贝数组的方法:Arrays.copyOf() 以及数组排序的方法。

运行效果如下所示:

练习3

将2中的代码进行修改:

/**
 * @document: Student类,表示学生,用于记载学生信息
 * @Author:SmallG
 * @CreateTime:2023/7/25+8:29
 */

public class Student {
    int id;
    String name;
    int score;

    public Student() {
    }

    public Student(int id, String name){
        this.id = id;
        this.name = name;
    }
    //获取学生信息
    public String getInfo() {
        return "Student\t" + id + "\t" + name + "\t" + score;
    }
}

/**
 * @document: 表示记录系统,用于提供综合服务(录入数据,查询信息等)
 * @Author:SmallG
 * @CreateTime:2023/7/25+8:32
 */

public class RecordSystem {
    //包含一个student数组类型的属性,用于保存所有学生的信息,数组长度为3
    Student[] studentArray = new Student[3];

    //初始化学生信息
    public RecordSystem() {
        studentArray[0] = new Student(1, "Tom");
        studentArray[1] = new Student(2, "Jerry");
        studentArray[2] = new Student(3, "Spike");
    }

    //方法一:录入学生成绩
    public void addScore(int id, int score) {
        //控制id和分数的范围
        if (id < 1 || id > 3) {
            System.out.println("输入有误,id超出范围!请重新输入!");
        } else if (score < 0 || score > 100) {
            System.out.println("分数录入有误,score有误!请重新输入");
        } else {
            studentArray[id - 1].score = score;
        }
    }

    //方法二:显示学生信息
    public void showInfo() {
        for (int i = 0; i < studentArray.length; i++) {
            System.out.println(studentArray[i].getInfo());
        }
    }

    //方法三:查询整体成绩
    //提示:可能会用到快速拷贝数组的方法:Arrays.copyOf() 以及数组排序的方法。
    public void checkScore() {
        //拷贝数组
        Student[] students = Arrays.copyOf(studentArray, studentArray.length);
        for (int i = 0; i < students.length - 1; i++) {
            for (int j = 0; j < students.length - 1 - i; j++) {
                if (students[j].score > students[j + 1].score) {
                    Student t = students[j];
                    students[j] = students[j + 1];
                    students[j + 1] = t;
                }
            }
        }
        for (int i = students.length - 1; i >= 0; i--) {
            System.out.println(students[i].getInfo());
        }
    }
}
/**
 * @document: 学生成绩系统
 * @Author:SmallG
 * @CreateTime:2023/7/25+8:28
 */

public class Student_Grade_System {
    public static void main(String[] args) {
        RecordSystem recordSystem = new RecordSystem();
        Scanner scanner = new Scanner(System.in);

        boolean s = true;
        while (s){
            System.out.println("欢迎使用学生成绩录入系统");
            System.out.println("1 显示学生信息");
            System.out.println("2 录入学生成绩");
            System.out.println("3 查询整体成绩");
            System.out.println("4 退出");
            System.out.println("请输入(1-3):");
            int a = scanner.nextInt();

            switch (a) {
                case 1: //显示学生信息
                    System.out.println("---------------------------");
                    recordSystem.showInfo();
                    System.out.println("---------------------------");
                    break;
                case 2: //录入学生成绩
                    System.out.println("---------------------------");
                    System.out.println("请输入学生id和分数,用空格分隔");
                    int id = scanner.nextInt();
                    int score = scanner.nextInt();
                    recordSystem.addScore(id, score);
                    recordSystem.showInfo();
                    System.out.println("---------------------------");
                    break;
                case 3: //查询整体成绩
                    System.out.println("---------------------------");
                    recordSystem.checkScore();
                    System.out.println("---------------------------");
                    break;

                case 4: //退出
                    System.out.println("谢谢使用");
                    System.out.println("---------------------------");
                    s = false;
                    break;
                default:
                    System.out.println("输入有误,请重新输入");
                    break;
            }
        }


    }
}
最后修改:2023 年 07 月 25 日
如果觉得我的文章对你有用,请随意赞赏