文章目录
- 面向对象
- 一、类和对象
- 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();
}
}
运行结果为:
``