文章目录
- 面向对象
- 一、类和对象
- 1. 类的介绍
- 2. 类和对象的关系
- 3. 类的组成
- 4. 创建对象和使用对象的格式
 
- 二、对象内存图
- 1. 单个对象内存图
- 2. 两个对象内存图
- 3. 两个引用指向相同内存图
 
- 三、成员变量和局部变量
- 四、this 关键字
- 1. this 可以解决的问题
- 2. this 介绍
- 3. this 内存图
 
- 五、构造方法
- 1. 构造方法概述
- 2. 构造方法作用
- 3. 构造方法注意事项
 
- 六、封装
- 1. 面向对象三大特征
- 2. 封装的设计规范
- 3. 权限修饰符
- 4. 标准 JavaBean
 
- 七、综合案例
 
 
 
面向对象

面向对象并不是一个技术,而是一种编程的指导思想,让我们以什么形式 组织代码;以什么思路 解决问题。
为什么要学习面向对象?
因为生活中,我们解决问题时,就是采用这种指导思想去解决的,所以,我们写程序去解决问题时,如果也能采用这种指导思想,就会使编程变得非常简单,程序也便于人理解 。
比如有顾客去买手机,顾客是对象,售货员也是对象,钱是对象,手机也是对象。

在我们前面的学习中,Scanner 和 Random都是 Java已经写好的类,但如果我们要解决的问题 Java 没有提供怎么办?

面向对象,重点学什么?
- 学习自己如何设计对象
- 学习已有的对象如何使用
一、类和对象
1. 类的介绍
Java 中想要创建对象,必须先要有类的存在
类指的是一组相关属性和行为的集合,我们将其理解为是一张对象的设计图

2. 类和对象的关系
- 依赖关系:Java 中需要根据类,创建对象
- 数量关系:一个类,可以创建出多个对象
3. 类的组成
- 属性: 
  - 成员变量:跟之前定义变量的格式一样只不过位置需要放在方法的外面
 
- 行为: 
  - 成员方法:跟之前定义方法的格式一样只不过需要去掉static关键字
 
下面我们定义了一个学生类,包含两个成员变量姓名、年龄;两个成员方法学习、吃饭。
package cn.edu.hgu.oop;
public class Student {
    //属性;姓名,年龄
    String name = "张三";
    int age = 23;
    //行为:学习,吃饭
    public void study() {
        System.out.println("学生学习...");
    }
    public void eat() {
        System.out.println("学生吃饭...");
    }
}
4. 创建对象和使用对象的格式
前面,我们创建了 Study 类,但是并不能直接运行,需要将类实例化——创建对象。
- 创建对象类名
对象名 = new 类名();
- 变量的使用格式
对象名.变量名;
- 方法的使用格式
对象名.方法名(实际参数);
我们来定义一个 StudyTest 类,用来创建对象和使用对象:
package cn.edu.hgu.oop;
public class StudyTest {
    public static void main(String[] args) {
        Student stu1 = new Student();
        System.out.println(stu1.name);
        System.out.println(stu1.age);
        stu1.study();
        stu1.eat();
    }
}
运行代码,输出结果为:

细节:
- 打印对象名,可以看到对象的内存地址
- 成员变量就算没有赋值,也可以直接使用,使用的是对象的默认值
我们可以看到输出结果,但这个结果使我们提前写死的,这样不灵活,接下来我们来修改一下代码:
package cn.edu.hgu.oop;
public class StudyTest {
    public static void main(String[] args) {
        Student stu1 = new Student();
        stu1.name = "张三";
        stu1.age = 23;
        System.out.println(stu1.name);
        System.out.println(stu1.age);
        stu1.study();
        stu1.eat();
        System.out.println("-------------");
        Student stu2 = new Student();
        stu2.name = "李四";
        stu2.age = 18;
        System.out.println(stu2.name);
        System.out.println(stu2.age);
        stu2.study();
        stu2.eat();
    }
}
输出结果为:

经过前面的学习,我们初步了解了类的定义与对象的创建和使用,下面我们通过两个案例来进行巩固。
案例1:手机
定义一个手机类 (Phone)
- 属性: (品牌 brand,颜色 color, 价格 price)
- 行为: 
  - 打电话 (call):输出给 xxx 打电话
- 发短信 (sendMessage):输出群发短信
 
编写一个手机测试类 (PhoneTest)
-  创建两个手机对象, 并给属性赋值 -  小米, 白色, 4999 
-  华为, 黑色, 6999 
 
-  
-  赋值之后, 校验自己有没有赋值成功, 使用打印语句校验, 调用两个对象各自的成员方法 
代码实现:
package cn.edu.hgu.oop;
public class Phone {
    String brand;
    String color;
    int price;
    public void call(String name){
        System.out.println("给"+name+"打电话");
    }
    public void sendMessage(){
        System.out.println("群发短信");
    }
}
package cn.edu.hgu.oop;
public class PhoneTest {
    public static void main(String[] args) {
        Phone p1 = new Phone();
        p1.brand="小米";
        p1.color = "白色";
        p1.price = 4999;
        System.out.println(p1.brand+"---"+p1.color +"---"+p1.price);
        p1.call("张三");
        p1.sendMessage();
        System.out.println("-----------");
        Phone p2 = new Phone();
        p2.brand="华为";
        p2.color = "黑色";
        p2.price = 6999;
        System.out.println(p2.brand+"---"+p2.color +"---"+p2.price);
        p2.call("王维");
        p2.sendMessage();
    }
}
输出结果为:

案例2:图书
编写一个图书类 (Book)
- 属性: 编号 (id) 书名(name) 价格 (price)
- 行为: 展示 (show) 该方法中需要展示出图书的所有属性信息
编写一个图书测试类 (BookTest)
-  创建 3 个图书对象, 分别赋值为 (001, 三国, 88.88) (002, 水浒, 88.88) (003, 富婆通讯录, 10000) 
-  调用3个对象, 各自的show 方法展示属性信息 
代码实现:
图书类(Book):
package cn.edu.hgu.oop;
public class Book {
    String id;
    String name;
    double price;
    public void show() {
        System.out.println("编号为:" + id + ",书名为:" + name + ",价格为:" + price);
    }
}
图书测试类(BookTest):
package cn.edu.hgu.oop;
public class BookTest {
    public static void main(String[] args) {
        Book b1 = new Book();
        b1.id = "001";
        b1.name = "三国";
        b1.price = 88.88;
        Book b2 = new Book();
        b2.id = "002";
        b2.name = "水浒";
        b2.price = 88.88;
        Book b3 = new Book();
        b3.id = "003";
        b3.name = "富婆通讯录";
        b3.price = 10000;
        b1.show();
        b2.show();
        b3.show();
    }
}
输出结果为:

二、对象内存图
1. 单个对象内存图

一开始 Student类 和 TestStudent 都在方法区,调用 main 方法,main 方法进入栈内存执行,调用 Student 类创建一个stu变量,在堆内存中新开辟一块空间,并对成员变量初始化,打印变量名会输出变量地址,打印成员变量会打印初始化变量值,根据地址对成员变量进行赋值,堆内存中的数据就会进行修改,再打印成员变量就会输出修改好的成员变量,调用成员方法,先进栈,执行完成后出栈。
2. 两个对象内存图


3. 两个引用指向相同内存图

三、成员变量和局部变量
成员变量和局部变量的区别:

四、this 关键字
1. this 可以解决的问题
定义一个 Student 类:
package cn.edu.hgu.mthis;
public class Student {
    String name;
    int age;
    public void sayHello(String name){
        System.out.println(name);
    }
}
定义一个测试类
package cn.edu.hgu.mthis;
public class ThisDemo {
    public static void main(String[] args) {
        Student stu = new Student();
        stu.name = "钢门吹雪";
        stu.sayHello("西域狂鸭");
    }
}
输出结果为:

当局部变量和成员变量出现了重名的情况,Java 使用的是 就近原则
问题:非要使用成员变量,怎么ban?
解决:使用 this 关键字进行区分,this可以区分局部变量和成员变量的重名问题

2. this 介绍
this 代表当前类对象的引用(地址)
this 关键字的作用:
-  this 可以调用本类成员(变量,方法) this.本类成员变量 this.本类成员方法 
-  this.的省略原则: 本类成员方法:没有前提条件,this.可以直接省略 本类成员变量:方法中没有出现重名的变量,this.才可以省略 
3. this 内存图


五、构造方法
1. 构造方法概述
- 构造器 
  - 初始化一个新建的对象
- 构建、创造对象的时候,所调用的方法
 
- 格式: 
  - 方法名与类名相同,大小写也要一致
- 没有返回值类型,连void都没有
- 没有具体的返回值(不能由return带回结果数据
 
- 执行时机: 
  - 创建对象的时候调用,每创建一次对象,就会执行一次构造方法
- 不能手动调用构造方法
 

2. 构造方法作用
本质作用:创建对象
结合构造方法执行时机:给对象中的属性(成员变量)进行初始化
3. 构造方法注意事项
①构造方法的创建
- 如果没有定义构造方法,系统将给出一个默认的无参数构造方法
- 如果定义了构造方法,系统将不再提供默认的构造方法
②构造方法的重载
- 构造方法也是方法,允许重载关系出现
③推荐的使用方式
- 无参数构造方法,和带参数构造方法,都自己手动给出
- 构造方法不允许手动调用
六、封装
1. 面向对象三大特征

这里我们先来学习封装。
封装:使用类设计对象时,将需要处理的数据,以及处理这些数据的方法, 设计到对象中。
计算出每一名学生的总成绩,展示学生的所有信息
| id | 姓名 | 年龄 | 数学成绩 | 语文成绩 | 
|---|---|---|---|---|
| 1 | 张三 | 23 | 90 | 87 | 
| 2 | 李四 | 24 | 69 | 91 | 
public class Student {
    int id;
    String name;
    int age;
    double mathScore;
    double chineseScore;
    // 省略构造方法
    public double getTotalScore() {
        return mathScore + chineseScore;
    }
    
    public void showStudentInfos(){
        System.out.println("学号: " + id);
        System.out.println("姓名: " + name);
        System.out.println("年龄:" + age);
        System.out.println("数学成绩:" + mathScore);
        System.out.println("语文成绩:" + chineseScore);
    }
}
public class Test {
    public static void main(String[] args) {
        Student stu1 = new Student(1, "张三", 23,90,87);
        stu1.showStudentInfos();
        Student stu2 = new Student(2, "李四", 24,69,91);
        stu2.showStudentInfos();
    }
}
这样可以更好的维护数据;使用者无需关心内部实现, 只要知道如何使用即可。
2. 封装的设计规范
合理隐藏, 合理暴露
一辆车,展示给我们的是使用功能,其他的部件都隐藏起来了。

3. 权限修饰符
我们在执行程序的时候,我们不想让对象直接调用某个方法,而是去间接使用它。

- private :同一个类中
- (defalut):同一个类中,同一个包中
- protected:同一个类中,同一个包中,不同包的子类
- public :任意位置访问
4. 标准 JavaBean
JavaBean 标准:
- 这个类中的成员变量都要私有,并且要对外提供相应的getXxx ,setXxx方法
- 类中提供无参, 带参构造方法。
实体类的应用场景是什么?
实体类只负责数据存取,而对数据的处理交给其他类来完成,以实现数据和数据业务处理相分离。

安装快速生成JavaBean的插件:


生成后的代码:
package cn.edu.hgu.domain;
public class Student {
    private String name;
    private int age;
    public Student() {
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    /**
     * 获取
     *
     * @return name
     */
    public String getName() {
        return name;
    }
    /**
     * 设置
     *
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 获取
     *
     * @return age
     */
    public int getAge() {
        return age;
    }
    /**
     * 设置
     *
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }
    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}
七、综合案例
面向对象综合案例-模仿电影信息系统
需求
- 展示系统中的全部电影(每部电影展示:名称、评分)。
- 允许用户根据电影编号(id)查询出某个电影的详细信息。


电影需要展示的信息有:
- int id; 编号
- String title; 片名
- String time; 时间
- double score; 评分
- String area; 地区
- String type; 类型
- String director; 导演
- String starring; 主演
代码实现:
package cn.edu.hgu.domain;
public class Movie {
    private int id;
    private String title;
    private String time;
    private double score;
    private String area;
    private String type;
    private String director;
    private String starring;
    public Movie() {
    }
    public Movie(int id, String title, String time, double score, String area, String type, String director, String starring) {
        this.id = id;
        this.title = title;
        this.time = time;
        this.score = score;
        this.area = area;
        this.type = type;
        this.director = director;
        this.starring = starring;
    }
    /**
     * 获取
     *
     * @return id
     */
    public int getId() {
        return id;
    }
    /**
     * 设置
     *
     * @param id
     */
    public void setId(int id) {
        this.id = id;
    }
    /**
     * 获取
     *
     * @return title
     */
    public String getTitle() {
        return title;
    }
    /**
     * 设置
     *
     * @param title
     */
    public void setTitle(String title) {
        this.title = title;
    }
    /**
     * 获取
     *
     * @return time
     */
    public String getTime() {
        return time;
    }
    /**
     * 设置
     *
     * @param time
     */
    public void setTime(String time) {
        this.time = time;
    }
    /**
     * 获取
     *
     * @return score
     */
    public double getScore() {
        return score;
    }
    /**
     * 设置
     *
     * @param score
     */
    public void setScore(double score) {
        this.score = score;
    }
    /**
     * 获取
     *
     * @return area
     */
    public String getArea() {
        return area;
    }
    /**
     * 设置
     *
     * @param area
     */
    public void setArea(String area) {
        this.area = area;
    }
    /**
     * 获取
     *
     * @return type
     */
    public String getType() {
        return type;
    }
    /**
     * 设置
     *
     * @param type
     */
    public void setType(String type) {
        this.type = type;
    }
    /**
     * 获取
     *
     * @return director
     */
    public String getDirector() {
        return director;
    }
    /**
     * 设置
     *
     * @param director
     */
    public void setDirector(String director) {
        this.director = director;
    }
    /**
     * 获取
     *
     * @return starring
     */
    public String getStarring() {
        return starring;
    }
    /**
     * 设置
     *
     * @param starring
     */
    public void setStarring(String starring) {
        this.starring = starring;
    }
    
}
MovieService类
package cn.edu.hgu.test;
import cn.edu.hgu.domain.Movie;
import java.util.Scanner;
public class MovieService {
    Scanner sc = new Scanner(System.in);
    Movie[] movies;
    public MovieService(Movie[] movies) {
        this.movies = movies;
    }
    /**
     * 启动电影信息管理系统
     */
    public void start() {
        lo:
        while (true) {
            System.out.println("----------电影信息系统----------");
            System.out.println("请输入您的选择:");
            System.out.println("1. 查询全部电影信息");
            System.out.println("2. 根据id查询电影信息");
            System.out.println("3. 退出");
            int choice = sc.nextInt();
            switch (choice) {
                case 1:
                    queryMovieInfos();
                    break;
                case 2:
                    queryMovieInfoById();
                    break;
                case 3:
                    System.out.println("感谢您的使用,再见!");
                    break lo;
                default:
                    System.out.println("您的输入有误,请检查");
                    break;
            }
        }
    }
    /**
     * 此方法根据电影编号,查询电影详情信息
     */
    private void queryMovieInfoById() {
        // 1.键盘录入用户输入的编号
        System.out.println("请输入您要查询的电影编号:");
        int id = sc.nextInt();
        // 2.遍历数组,从数组中查询电影信息
        for (int i = 0; i < movies.length; i++) {
            Movie movie = movies[i];
            if (movie.getId() == id) {
                // 3.将找到的电影信息,打印在控制台
                System.out.println(movie.getId() + "---" + movie.getTitle() + "---"
                        + movie.getTime() + "---" + movie.getScore() + "---" + movie.getArea() + "---"
                        + movie.getType() + "---" + movie.getDirector() + "---" + movie.getStarring());
                return;
            }
        }
        System.out.println("您输入的编号不存在,请检查!");
    }
    /**
     * 展示系统中全部的电影(名称,评分)
     */
    private void queryMovieInfos() {
        // 1.遍历数组,取出每一个电影对象
        for (int i = 0; i < movies.length; i++) {
            Movie movie = movies[i];
            // 2.通过电影名称,调用内部 getXxx方法,获取信息并打印
            System.out.println(movie.getTitle() + "---" + movie.getScore());
        }
    }
}
Test类
package cn.edu.hgu.test;
import cn.edu.hgu.domain.Movie;
public class Test {
    public static void main(String[] args) {
        Movie movie1 = new Movie(1, "东八区的先生们", "2022", 2.1, "中国大陆", "剧情 喜剧", "夏睿", "张翰 王晓晨");
        Movie movie2 = new Movie(2, "上海堡垒", "2019", 2.9, "中国大陆", "爱情 战争 科幻", "滕华涛", "鹿晗 舒淇");
        Movie movie3 = new Movie(3, "纯洁心灵·逐梦演艺圈", "2015", 2.2, "中国大陆", "剧情 喜剧", "毕志飞", "朱一文 李彦漫");
        Movie[] movies = {movie1, movie2, movie3};
        MovieService movieService = new MovieService(movies);
        movieService.start();
    }
}
运行结果为:

``


















