目录
面向对象
三大特征:封装、继承、多态
一、类和对象
1.定义
Java中想要创建对象,必须先要有类的存在
类:指的是一组相关属性和行为的集合,我们将其理解为是一张对象的设计图
对象:是根据设计图(类)创建出来的实体
2.关系
-
依赖关系:Java中需要根据类,创建对象
-
数量关系:一个类,可以创建出多个对象
3.类的组成
属性:在代码中使用成员变量表示,跟之前定义变量的格式一样,只不过位置需要放在方法的外面
行为:在代码中使用成员方法表示,跟之前定义方法的格式一样,只不过需要去掉static关键字
4.创建对象的格式
*类名 对象名 = new 类名();
5.使用对象成员变量的格式
对象名.成员变量;
6.使用对象成员方法的格式
对象名.成员方法();
package Test; public class Student { String name = "小严"; int age = 18; public void study(){ System.out.println("学生学习..."); } public void eat(){ System.out.println("学生吃饭..."); } }
有主方法的类叫测试类
package Test; public class StudentTest { 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 Test; public class Song { String song; String name; int date; public void show(){ System.out.println("歌曲名字:" + song + "\n歌手:" + name +"\n发布时间:" + date); } }
测试类
package Test; public class SongTest { public static void main(String[] args) { Song y1 = new Song(); y1.song = "《For You》"; y1.name = "严浩翔"; y1.date = 20200515; Song y2 = new Song(); y2.song = "《尾号6208》"; y2.name = "严浩翔"; y2.date = 20210816; Song y3 = new Song(); y3.song = "《Y》"; y3.name = "严浩翔"; y3.date = 20211214; y1.show(); y2.show(); y3.show(); } }
运行结果
二、对象内存图
1.单个对象内存图
2.两个对象内存图(方法共用内存图)
3.两个引用指向相同内存图
三、成员变量和局部变量
区别 | 成员变量 | 局部变量 |
---|---|---|
类中位置不同 | 方法外 | 方法中 |
初始化值不同 | 有默认初始化值 | 没有,使用之前需要完成赋值 |
内存位置不同 | 堆内存 | 栈内存 |
生命周期不同 | 随着对象的创建而存在,随着对象的消失而消失 | 随着方法的调用而存在,随着方法的运行结束而消失 |
作用域 | 在自己所归属的大括号中 | 在自己所归属的大括号中 |
四、this变量
1.介绍
当局部变量和成员变量出现了重名的情况,Java使用的是就近原则
this 代表当前类对象的引用(地址)---> 谁调用就创建谁 ---> 哪一个对象调用方法,那么方法中的this代表的就是哪个对象
如:stu1.print() ---> stu1调用print方法,this代表stu1的地址
例如:
package Test; public class Student { String name; int age; public void sayHello(String name) { System.out.println(name); } }
package Test; public class StudentTest { public static void main(String[] args) { Student stu = new Student(); stu.name = "钢门吹雪"; stu.age = 23; stu.sayHello("西域狂鸭"); } }
运行结果为:西域狂鸭
解决办法:this关键字区分
package Test; public class Student { String name; int age; public void sayHello(String name) { System.out.println(this.name); } }
package Test; public class StudentTest { public static void main(String[] args) { Student stu = new Student(); stu.name = "钢门吹雪"; stu.age = 23; stu.sayHello("西域狂鸭"); } }
运行结果为:钢门吹雪
2.作用
调用本类成员
-
this.本类成员变量;:如果不涉及变量重复, this.可以省略
-
this.本类成员方法();:没有前提条件this.可以直接省略
五、构造方法
1.概述
构造器:初始化一个新建的对象,构建、创造对象的时候所调用的方法
2.格式
-
方法名与类名相同,大小写也要一致
-
没有返回值类型,连void都没有
-
没有具体的返回值(不能由return带回结果数据)
3.执行时机
-
创建对象的时候调用,每创建一次对象,就会执行一次构造方法
-
不能手动调用构造方法
package construction; public class Student { //构造方法 public Student(){ System.out.println("我是Student类的构造方法"); } }
package construction; public class StudentTest { public static void main(String[] args) { //调用构造方法 Student stu1 = new Student(); Student stu2 = new Student(); Student stu3 = new Student(); } }
4.作用
本质作用:创建对象
结合构造方法执行时机:给对象中的属性(成员变量)进行初始化
package construction; public class Student { //成员变量 String name; int age; //构造方法 给对象中的变量初始化 //局部变量 public Student(String name, int age){ this.name = name; this.age = age; } }
package construction; public class StudentTest { public static void main(String[] args) { //调用构造方法 Student stu1 = new Student("小严",18); System.out.println(stu1.name + "---" + stu1.age); Student stu2 = new Student("小熊",16); System.out.println(stu2.name + "---" + stu2.age); } }
运行结果
5.注意事项
①构造方法的创建
-
如果没有定义构造方法,系统将给出一个默认的无参数构造方法
-
如果定义了构造方法,系统将不再提供默认的构造方法(建议:编写类的时候,不管是无参构造还是带参构造,全部手动给出)
②构造方法的重载
-
构造方法也是方法,允许重载关系出现(同一个类中,方法名相同,参数不同)
③构造方法不允许手动调用(对象名.方法名),只能在new对象时执行
6.执行流程
六、封装 --- 合理隐藏,合理暴露
1.介绍
使用类设计对象时,将需要处理的数据,以及处理这些数据的方法,设计到对象中
2.好处
-
更好地维护数据
-
使用者无需关心内部实现,只要知道如何使用即可8
3.权限修饰符
修饰符 | 类本身 | 同一个包的类 | 不同包的子类 | 任何类 |
---|---|---|---|---|
private | √ | |||
default(默认) | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
-
私有成员变量(为了保证数据的安全性)
-
针对私有的成员变量,提供对应的setXxx和getXxx方法(set设置 get获取)
4.案例
package encapsulation; public class Student { //使用者可能给出错误数据,所以要隐藏 private int age; //setAge和getAge方法让用户达到目的 public void setAge(int age){ //数据安全校验 if(age >= 1 && age <= 120){ this.age = age; }else{ System.out.println("年龄有误,请检查是否是1~120之间"); } } public int getAge(){ //访问成员变量的age 变量名不重复,"this."省略了 return age; } }
package encapsulation; public class StudentTest { public static void main(String[] args) { Student stu = new Student(); stu.setAge(18); int age = stu.getAge(); System.out.println(age); } }
输入错误数据的运行结果
输入正确数据的运行结果
七、标准JavaBean
1.介绍
即实体类:封装数据的类
实体类只负责数据存取,而对数据的处理交给其他类来完成,以实现数据和数据业务处理相分离
2.要求
-
这个类中的成员变量都要私有,并且要对外提供相应的getXxx和setXxx方法
-
类中提供无参、带参构造方法
3.案例
package domain; public class Student { //1.成员变量私有化 private String name; private int age; //2.空参、带参方法 public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } //3.对私有的成员变量,对外提供相应的getXxx和setXxx方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
①生成空参、带参方法的快捷键:
-
右键-Generate-Constructor-Select None
-
右键-Generate-Constructor-Ctrl+A(全选)-OK
②生成getXxx和setXxx方法的快捷键
-
右键-Generate-Getter and Setter-Ctrl+A(全选)-OK
③一键生成(只需要对成员变量私有化)
-
右键-Ptg To JavaBean
八、面向对象综合案例
需求:
-
展示系统中的全部电影(每部电影展示:名称、评分)
-
允许用户根据电影编号(id)查询出某个电影的详细信息 <u></u>
“Ctrl+Alt+T”可以将代码用循环包住
Movie.java ---> 封装数据
package 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.java ---> 负责管理业务
package test2; import domain.Movie; import java.util.Scanner; //负责管理业务 public class MovieService { //定义成员变量 隐藏 private Movie[] movies; private Scanner sc = new Scanner(System.in); //构造方法 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; } } } /** * 此方法允许用户根据电影编号(id)查询出某个电影的详细信息 */ 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]; //System.out.println(movie);打印对象名,看到的是内存地址 //2.通过电影对象,调用内部getXxx方法,获取信息并打印 System.out.println(movie.getTitle() + "---" + movie.getScore()); } } }
Test.java ---> 测试类
package test2; import 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}; //该如何将一个类中的数据,传递给另一个类? //1.将数组作为参数传到类MovieService中 //2.选中类中的 movies Alt+回车:创建构造方法 MovieService movieService = new MovieService(movies); movieService.start(); } }