面向对象进阶与ES应用,面向对象术语
墨初 知识笔记 48阅读
这篇主要包括分类和 Static、继承、接口和内部类相关知识
黑马信息管理系统我改成了师生管理系统已上传。
分工协作,专人干专事

Student类 标准学生类,封装键盘录入的学生信息(id , name , age , birthday)
StudentDao类 Dao : (Data Access Object 缩写) 用于访问存储数据的数组或集合

StudentService类 用来进行业务逻辑的处理(例如: 判断录入的id是否存在)
StudentController类 和用户打交道(接收用户需求,采集用户信息,打印数据到控制台)
2.分包思想 2.1分包思想概述 (理解)如果将所有的类文件都放在同一个包下,不利于管理和后期维护,所以,对于不同功能的类文件,可以放在不同的包下进行管理
2.2包的概述 (记忆)包
本质上就是文件夹
创建包
多级包之间使用 . 进行分割
多级包的定义规范公司的网站地址翻转(去掉www)比如黑马程序员的网站址为www.itheima.com
后期我们所定义的包的结构就是com.itheima.其他的包名
包的命名规则
字母都是小写
2.3包的注意事项 (理解) package语句必须是程序的第一条可执行的代码package语句在一个java文件中只能有一个如果没有package,默认表示无包名 2.4类与类之间的访问 (理解)同一个包下的访问
不需要导包直接使用即可
不同包下的访问
1.import 导包后访问
2.通过全类名包名 类名访问
注意import 、package 、class 三个关键字的摆放位置存在顺序关系
package 必须是程序的第一条可执行的代码
import 需要写在 package 下面
class 需要在 import 下面
3.黑马信息管理系统 3.1系统介绍 (理解) 3.2学生管理系统 (应用) 3.2.1需求说明添加学生: 键盘录入学生信息(idnameagebirthday)
使用数组存储学生信息,要求学生的id不能重复
删除学生: 键盘录入要删除学生的id值,将该学生从数组中移除,如果录入的id在数组中不存在,需要重新录入
修改学生: 键盘录入要修改学生的id值和修改后的学生信息
将数组中该学生的信息修改,如果录入的id在数组中不存在,需要重新录入
查询学生: 将数组中存储的所有学生的信息输出到控制台
3.2.2实现步骤 环境搭建实现步骤业务的逻辑处理
和用户打交道
菜单搭建实现步骤 需求 黑马管理系统菜单搭建学生管理系统菜单搭建 实现步骤 展示欢迎页面,用输出语句完成主界面的编写获取用户的选择,用Scanner实现键盘录入数据根据用户的选择执行对应的操作,用switch语句完成操作的选择 添加功能实现步骤 添加功能优化:判断id是否存在 查询功能实现步骤 删除功能实现步骤 修改功能实现步骤系统优化
把updateStudent和deleteStudentById中录入学生id代码抽取到一个方法(inputStudentId)中
该方法的主要作用就是录入学生的id方法的返回值为String类型
把addStudent和updateStudent中录入学生信息的代码抽取到一个方法(inputStudentInfo)中
该方法的主要作用就是录入学生的信息并封装为学生对象方法的返回值为Student类型
学生类
public class Student { private String id; private String name; private String age; private String birthday; String address; public Student() { } public Student(String id, String name, String age, String birthday) { this.id id; this.name name; this.age age; this.birthday birthday; } public String getId() { return id; } public void setId(String id) { this.id id; } public String getName() { return name; } public void setName(String name) { this.name name; } public String getAge() { return age; } public void setAge(String age) { this.age age; } public String getBirthday() { return birthday; } public void setBirthday(String birthday) { this.birthday birthday; }}
程序入口InfoManagerEntry类
public class InfoManagerEntry { public static void main(String[] args) { Scanner sc new Scanner(System.in); while (true) { // 主菜单搭建 System.out.println(--------欢迎来到黑马信息管理系统--------); System.out.println(请输入您的选择: 1.学生管理 2.老师管理 3.退出); String choice sc.next(); switch (choice) { case 1: // System.out.println(学生管理); // 开启学生管理系统 StudentController studentController new StudentController(); studentController.start(); break; case 2: System.out.println(老师管理); TeacherController teacherController new TeacherController(); teacherController.start(); break; case 3: System.out.println(感谢您的使用); // 退出当前正在运行的JVM虚拟机 System.exit(0); break; default: System.out.println(您的输入有误, 请重新输入); break; } } }}
StudentController类
public class StudentController { // 业务员对象 private StudentService studentService new StudentService(); private Scanner sc new Scanner(System.in); // 开启学生管理系统, 并展示学生管理系统菜单 public void start() { //Scanner sc new Scanner(System.in); studentLoop: while (true) { System.out.println(--------欢迎来到 <学生> 管理系统--------); System.out.println(请输入您的选择: 1.添加学生 2.删除学生 3.修改学生 4.查看学生 5.退出); String choice sc.next(); switch (choice) { case 1: // System.out.println(添加); addStudent(); break; case 2: // System.out.println(删除); deleteStudentById(); break; case 3: // System.out.println(修改); updateStudent(); break; case 4: // System.out.println(查询); findAllStudent(); break; case 5: System.out.println(感谢您使用学生管理系统, 再见!); break studentLoop; default: System.out.println(您的输入有误, 请重新输入); break; } } } // 修改学生方法 public void updateStudent() { String updateId inputStudentId(); Student newStu inputStudentInfo(updateId); studentService.updateStudent(updateId, newStu); System.out.println(修改成功!); } // 删除学生方法 public void deleteStudentById() { String delId inputStudentId(); // 3. 调用业务员中的deleteStudentById根据id, 删除学生 studentService.deleteStudentById(delId); // 4. 提示删除成功 System.out.println(删除成功!); } // 查看学生方法 public void findAllStudent() { // 1. 调用业务员中的获取方法, 得到学生的对象数组 Student[] stus studentService.findAllStudent(); // 2. 判断数组的内存地址, 是否为null if (stus null) { System.out.println(查无信息, 请添加后重试); return; } // 3. 遍历数组, 获取学生信息并打印在控制台 System.out.println(学号\t\t姓名\t年龄\t生日); for (int i 0; i < stus.length; i) { Student stu stus[i]; if (stu ! null) { System.out.println(stu.getId() \t stu.getName() \t stu.getAge() \t\t stu.getBirthday()); } } } // 添加学生方法 public void addStudent() { // StudentService studentService new StudentService(); // 1. 键盘接收学生信息 String id; while (true) { System.out.println(请输入学生id:); id sc.next(); boolean flag studentService.isExists(id); if (flag) { System.out.println(学号已被占用, 请重新输入); } else { break; } } Student stu inputStudentInfo(id); // 3. 将学生对象,传递给StudentService(业务员)中的addStudent方法 boolean result studentService.addStudent(stu); // 4. 根据返回的boolean类型结果, 在控制台打印成功\失败 if (result) { System.out.println(添加成功); } else { System.out.println(添加失败); } } // 键盘录入学生id public String inputStudentId() { String id; while (true) { System.out.println(请输入学生id:); id sc.next(); boolean exists studentService.isExists(id); if (!exists) { System.out.println(您输入的id不存在, 请重新输入:); } else { break; } } return id; } // 键盘录入学生信息 public Student inputStudentInfo(String id) { System.out.println(请输入学生姓名:); String name sc.next(); System.out.println(请输入学生年龄:); String age sc.next(); System.out.println(请输入学生生日:); String birthday sc.next(); Student stu new Student(); stu.setId(id); stu.setName(name); stu.setAge(age); stu.setBirthday(birthday); return stu; }}
StudentService类
public class StudentService { // 创建StudentDao (库管) private StudentDao studentDao new StudentDao(); // 添加学生方法 public boolean addStudent(Student stu) { // 2. 将学生对象, 传递给StudentDao 库管中的addStudent方法 // 3. 将返回的boolean类型结果, 返还给StudentController return studentDao.addStudent(stu); } // 判断学号是否存在方法 public boolean isExists(String id) { Student[] stus studentDao.findAllStudent(); // 假设id在数组中不存在 boolean exists false; // 遍历数组, 获取每一个学生对象, 准备进行判断 for (int i 0; i < stus.length; i) { Student student stus[i]; if(student ! null && student.getId().equals(id)){ exists true; break; } } return exists; } // 查看学生方法 public Student[] findAllStudent() { // 1. 调用库管对象的findAllStudent获取学生对象数组 Student[] allStudent studentDao.findAllStudent(); // 2. 判断数组中是否有学生信息 (有: 返回地址, 没有: 返回null) // 思路: 数组中只要存在一个不是null的元素, 那就代表有学生信息 boolean flag false; for (int i 0; i < allStudent.length; i) { Student stu allStudent[i]; if(stu ! null){ flag true; break; } } if(flag){ // 有信息 return allStudent; }else{ // 没有信息 return null; } } public void deleteStudentById(String delId) { studentDao.deleteStudentById(delId); } public void updateStudent(String updateId, Student newStu) { studentDao.updateStudent(updateId, newStu); }}
StudentDao类
public class StudentDao { // 创建学生对象数组 private static Student[] stus new Student[5]; // 添加学生方法 public boolean addStudent(Student stu) { // 2. 添加学生到数组 //2.1 定义变量index为-1假设数组已经全部存满没有null的元素 int index -1; //2.2 遍历数组取出每一个元素判断是否是null for (int i 0; i < stus.length; i) { Student student stus[i]; if(student null){ index i; //2.3 如果为null让index变量记录当前索引位置并使用break结束循环遍历 break; } } // 3. 返回是否添加成功的boolean类型状态 if(index -1){ // 装满了 return false; }else{ // 没有装满, 正常添加, 返回true stus[index] stu; return true; } } // 查看学生方法 public Student[] findAllStudent() { return stus; } public void deleteStudentById(String delId) { // 1. 查找id在容器中所在的索引位置 int index getIndex(delId); // 2. 将该索引位置,使用null元素进行覆盖 stus[index] null; } public int getIndex(String id){ int index -1; for (int i 0; i < stus.length; i) { Student stu stus[i]; if(stu ! null && stu.getId().equals(id)){ index i; break; } } return index; } public void updateStudent(String updateId, Student newStu) { // 1. 查找updateId, 在容器中的索引位置 int index getIndex(updateId); // 2. 将该索引位置, 使用新的学生对象替换 stus[index] newStu; }}
3.3老师管理系统 (应用) 3.3.1需求说明 添加老师: 通过键盘录入老师信息(idnameagebirthday)
使用数组存储老师信息,要求老师的id不能重复
删除老师: 通过键盘录入要删除老师的id值,将该老师从数组中移除,如果录入的id在数组中不存在,需要重新录入
修改老师: 通过键盘录入要修改老师的id值和修改后的老师信息
将数组中该老师的信息修改,如果录入的id在数组中不存在,需要重新录入
查询老师: 将数组中存储的所有老师的信息输出到控制台
3.3.2实现步骤环境搭建实现步骤
菜单搭建实现步骤
展示欢迎页面,用输出语句完成主界面的编写获取用户的选择,用Scanner实现键盘录入数据根据用户的选择执行对应的操作,用switch语句完成操作的选择添加功能实现步骤
查询功能实现步骤
删除功能实现步骤
修改功能实现步骤
系统优化
把updateTeacher和deleteTeacherById中录入老师id代码抽取到一个方法(inputTeacherId)中该方法的主要作用就是录入老师的id,方法的返回值为String类型把addTeacher和updateTeacher中录入老师信息的代码抽取到一个方法(inputTeacherInfo)中
该方法的主要作用就是录入老师的信息,并封装为老师对象,方法的返回值为Teacher类型 3.3.3代码实现
老师类
public class Teacher extends Person{private String id; private String name; private String age; private String birthday; String address; public Teacher() { } public Teacher(String id, String name, String age, String birthday) { this.id id; this.name name; this.age age; this.birthday birthday; } public String getId() { return id; } public void setId(String id) { this.id id; } public String getName() { return name; } public void setName(String name) { this.name name; } public String getAge() { return age; } public void setAge(String age) { this.age age; } public String getBirthday() { return birthday; } public void setBirthday(String birthday) { this.birthday birthday; }}
TeacherController类
public class TeacherController { private Scanner sc new Scanner(System.in); private TeacherService teacherService new TeacherService(); public void start() { teacherLoop: while (true) { System.out.println(--------欢迎来到 <老师> 管理系统--------); System.out.println(请输入您的选择: 1.添加老师 2.删除老师 3.修改老师 4.查看老师 5.退出); String choice sc.next(); switch (choice) { case 1: // System.out.println(添加老师); addTeacher(); break; case 2: // System.out.println(删除老师); deleteTeacherById(); break; case 3: // System.out.println(修改老师); updateTeacher(); break; case 4: // System.out.println(查看老师); findAllTeacher(); break; case 5: System.out.println(感谢您使用老师管理系统, 再见!); break teacherLoop; default: System.out.println(您的输入有误, 请重新输入); break; } } } public void updateTeacher() { String id inputTeacherId(); Teacher newTeacher inputTeacherInfo(id); // 调用业务员的修改方法 teacherService.updateTeacher(id,newTeacher); System.out.println(修改成功); } public void deleteTeacherById() { String id inputTeacherId(); // 2. 调用业务员中的删除方法, 根据id, 删除老师 teacherService.deleteTeacherById(id); // 3. 提示删除成功 System.out.println(删除成功); } public void findAllTeacher() { // 1. 从业务员中, 获取老师对象数组 Teacher[] teachers teacherService.findAllTeacher(); // 2. 判断数组中是否有元素 if (teachers null) { System.out.println(查无信息, 请添加后重试); return; } // 3. 遍历数组, 取出元素, 并打印在控制台 System.out.println(学号\t\t姓名\t年龄\t生日); for (int i 0; i < teachers.length; i) { Teacher t teachers[i]; if (t ! null) { System.out.println(t.getId() \t t.getName() \t t.getAge() \t\t t.getBirthday()); } } } public void addTeacher() { String id; while (true) { // 1. 接收不存在的老师id System.out.println(请输入老师id:); id sc.next(); // 2. 判断id是否存在 boolean exists teacherService.isExists(id); if (exists) { System.out.println(id已被占用, 请重新输入:); } else { break; } } Teacher t inputTeacherInfo(id); // 5. 将封装好的老师对象, 传递给TeacherService继续完成添加操作 boolean result teacherService.addTeacher(t); if (result) { System.out.println(添加成功); } else { System.out.println(添加失败); } } // 录入老师id public String inputTeacherId(){ String id; while(true){ System.out.println(请输入id); id sc.next(); boolean exists teacherService.isExists(id); if(!exists){ System.out.println(您输入的id不存在, 请重新输入:); }else{ break; } } return id; } // 录入老师信息, 封装为老师对象 public Teacher inputTeacherInfo(String id){ System.out.println(请输入老师姓名:); String name sc.next(); System.out.println(请输入老师年龄:); String age sc.next(); System.out.println(请输入老师生日:); String birthday sc.next(); Teacher t new Teacher(); t.setId(id); t.setName(name); t.setAge(age); t.setBirthday(birthday); return t; }}
TeacherService类
public class TeacherService { private TeacherDao teacherDao new TeacherDao(); public boolean addTeacher(Teacher t) { return teacherDao.addTeacher(t); } public boolean isExists(String id) { // 1. 获取库管对象中的数组 Teacher[] teachers teacherDao.findAllTeacher(); boolean exists false; // 2. 遍历数组, 取出每一个元素, 进行判断 for (int i 0; i < teachers.length; i) { Teacher teacher teachers[i]; if(teacher ! null && teacher.getId().equals(id)){ exists true; break; } } return exists; } public Teacher[] findAllTeacher() { Teacher[] allTeacher teacherDao.findAllTeacher(); boolean flag false; for (int i 0; i < allTeacher.length; i) { Teacher t allTeacher[i]; if(t ! null){ flag true; break; } } if(flag){ return allTeacher; }else{ return null; } } public void deleteTeacherById(String id) { teacherDao.deleteTeacherById(id); } public void updateTeacher(String id, Teacher newTeacher) { teacherDao.updateTeacher(id,newTeacher); }}
TeacherDao类
public class TeacherDao { private static Teacher[] teachers new Teacher[5]; public boolean addTeacher(Teacher t) { int index -1; for (int i 0; i < teachers.length; i) { Teacher teacher teachers[i]; if(teacher null){ index i; break; } } if(index -1){ return false; }else{ teachers[index] t; return true; } } public Teacher[] findAllTeacher() { return teachers; } public void deleteTeacherById(String id) { // 1. 查询id在数组中的索引位置 int index getIndex(id); // 2. 将该索引位置的元素, 使用null进行替换 teachers[index] null; } public int getIndex(String id){ int index -1; for (int i 0; i < teachers.length; i) { Teacher t teachers[i]; if(t ! null && t.getId().equals(id)){ index i; break; } } return index; } public void updateTeacher(String id, Teacher newTeacher) { int index getIndex(id); teachers[index] newTeacher; }}
4.static关键字 4.1static关键字概述 (理解) static 关键字是静态的意思,是Java中的一个修饰符,可以修饰成员方法,成员变量
4.2static修饰的特点 (记忆)被类的所有对象共享
是我们判断是否使用静态关键字的条件
随着类的加载而加载优先于对象存在
对象需要类被加载后才能创建
可以通过类名调用
也可以通过对象名调用
4.3static关键字注意事项 (理解) 静态方法只能访问静态的成员非静态方法可以访问静态的成员也可以访问非静态的成员静态方法中是没有this关键字 5. 继承 5.1 继承的实现掌握继承的概念
继承是面向对象三大特征之一可以使得子类具有父类的属性和方法还可以在子类中重新定义以及追加属性和方法实现继承的格式
继承通过extends实现格式class 子类 extends 父类 { } 举例class Dog extends Animal { }继承带来的好处
继承可以让类与类之间产生关系子父类关系产生子父类后子类则可以使用父类中非私有的成员。示例代码
public class Fu { public void show() { System.out.println(show方法被调用); }}public class Zi extends Fu { public void method() { System.out.println(method方法被调用); }}public class Demo { public static void main(String[] args) { //创建对象调用方法 Fu f new Fu(); f.show(); Zi z new Zi(); z.method(); z.show(); }}
5.2 继承的好处和弊端理解 继承好处 提高了代码的复用性(多个类相同的成员可以放到同一个类中)提高了代码的维护性(如果方法的代码需要修改修改一处即可) 继承弊端 继承让类与类之间产生了关系类的耦合性增强了当父类发生变化时子类实现也不得不跟着变化削弱了子类的独立性 继承的应用场景 使用继承需要考虑类与类之间是否存在is…a的关系不能盲目使用继承 is…a的关系谁是谁的一种例如老师和学生是人的一种那人就是父类学生和老师就是子类 5.3. Java中继承的特点掌握 Java中继承的特点
Java中类只支持单继承不支持多继承 错误范例class A extends B, C { } Java中类支持多层继承多层继承示例代码
public class Granddad { public void drink() { System.out.println(爷爷爱喝酒); }}public class Father extends Granddad { public void smoke() { System.out.println(爸爸爱抽烟); }}public class Mother { public void dance() { System.out.println(妈妈爱跳舞); }}public class Son extends Father {// 此时Son类中就同时拥有drink方法以及smoke方法}
6. 继承中的成员访问特点 6.1 继承中变量的访问特点掌握 在子类方法中访问一个变量采用的是就近原则。
子类局部范围找子类成员范围找父类成员范围找如果都没有就报错(不考虑父亲的父亲…)示例代码
class Fu { int num 10;}class Zi { int num 20; public void show(){ int num 30; System.out.println(num); }}public class Demo1 { public static void main(String[] args) { Zi z new Zi(); z.show();// 输出show方法中的局部变量30 }}
6.2 super掌握 this&super关键字 this代表本类对象的引用super代表父类存储空间的标识(可以理解为父类对象引用) this和super的使用分别 成员变量 this.成员变量 - 访问本类成员变量super.成员变量 - 访问父类成员变量 成员方法 this.成员方法 - 访问本类成员方法super.成员方法 - 访问父类成员方法 构造方法 this(…) - 访问本类构造方法super(…) - 访问父类构造方法 6.3 继承中构造方法的访问特点理解 注意子类中所有的构造方法默认都会访问父类中无参的构造方法
子类会继承父类中的数据可能还会使用父类的数据。所以子类初始化之前一定要先完成父类数据的初始化原因在于每一个子类构造方法的第一条语句默认都是super()
问题如果父类中没有无参构造方法只有带参构造方法该怎么办呢
1. 通过使用super关键字去显示的调用父类的带参构造方法2. 子类通过this去调用本类的其他构造方法,本类其他构造方法再通过super去手动调用父类的带参的构造方法注意: this(…)super(…) 必须放在构造方法的第一行有效语句并且二者不能共存
6.4 继承中成员方法的访问特点掌握 通过子类对象访问一个方法
子类成员范围找父类成员范围找如果都没有就报错(不考虑父亲的父亲…) 6.5 super内存图理解对象在堆内存中会单独存在一块super区域用来存放父类的数据
6.6 方法重写掌握 1、方法重写概念 子类出现了和父类中一模一样的方法声明方法名一样参数列表也必须一样 2、方法重写的应用场景 当子类需要父类的功能而功能主体子类有自己特有内容时可以重写父类中的方法这样即沿袭了父类的功能又定义了子类特有的内容 3、Override注解 用来检测当前的方法是否是重写的方法起到【校验】的作用 6.7 方法重写的注意事项掌握 方法重写的注意事项 私有方法不能被重写(父类私有成员子类是不能继承的)子类方法访问权限不能更低(public > 默认 > 私有)静态方法不能被重写,如果子类也有相同的方法,并不是重写的父类的方法 示例代码public class Fu { private void show() { System.out.println(Fu中show()方法被调用); } void method() { System.out.println(Fu中method()方法被调用); }}public class Zi extends Fu { /* 编译【出错】子类不能重写父类私有的方法*/ Override private void show() { System.out.println(Zi中show()方法被调用); } /* 编译【出错】子类重写父类方法的时候访问权限需要大于等于父类 */ Override private void method() { System.out.println(Zi中method()方法被调用); } /* 编译【通过】子类重写父类方法的时候访问权限需要大于等于父类 */ Override public void method() { System.out.println(Zi中method()方法被调用); }}
6.8 权限修饰符 (理解) 6.9 黑马信息管理系统使用继承改进 (掌握) 需求
把学生类和老师类共性的内容向上抽取,抽取到出一个 Person 父类,让学生类和老师类继承 Person 类
实现步骤
抽取Person类
优化StudentController类中inputStudentInfo方法将setXxx赋值方式改进为构造方法初始化
注意直接修改这种操作方式不符合我们开发中的一个原则
开闭原则 ( 对扩展开放对修改关闭 ) : 尽量在不更改原有代码的前提下以完成需求
解决重新创建一个OtherStudentController类
编写新的inputStudentInfo方法
根据StudentController类、OtherStudentController类向上抽取出BaseStudentController类
再让StudentController类、OtherStudentController类继承BaseStudentController类
代码实现
Person类及学生类和老师类
public class Person { private String id; private String name; private String age; private String birthday; public Person() { } public Person(String id, String name, String age, String birthday) { this.id id; this.name name; this.age age; this.birthday birthday; } public String getId() { return id; } public void setId(String id) { this.id id; } public String getName() { return name; } public void setName(String name) { this.name name; } public String getAge() { return age; } public void setAge(String age) { this.age age; } public String getBirthday() { return birthday; } public void setBirthday(String birthday) { this.birthday birthday; }}// Student类public class Student extends Person { public Student() { } public Student(String id, String name, String age, String birthday) { super(id, name, age, birthday); }}// Teacher类public class Teacher extends Person { public Teacher() { } public Teacher(String id, String name, String age, String birthday) { super(id, name, age, birthday); }}
BaseStudentController类
public abstract class BaseStudentController { // 业务员对象 private StudentService studentService new StudentService(); private Scanner sc new Scanner(System.in); // 开启学生管理系统, 并展示学生管理系统菜单 public void start() { //Scanner sc new Scanner(System.in); studentLoop: while (true) { System.out.println(--------欢迎来到 <学生> 管理系统--------); System.out.println(请输入您的选择: 1.添加学生 2.删除学生 3.修改学生 4.查看学生 5.退出); String choice sc.next(); switch (choice) { case 1: // System.out.println(添加); addStudent(); break; case 2: // System.out.println(删除); deleteStudentById(); break; case 3: // System.out.println(修改); updateStudent(); break; case 4: // System.out.println(查询); findAllStudent(); break; case 5: System.out.println(感谢您使用学生管理系统, 再见!); break studentLoop; default: System.out.println(您的输入有误, 请重新输入); break; } } } // 修改学生方法 public void updateStudent() { String updateId inputStudentId(); Student newStu inputStudentInfo(updateId); studentService.updateStudent(updateId, newStu); System.out.println(修改成功!); } // 删除学生方法 public void deleteStudentById() { String delId inputStudentId(); // 3. 调用业务员中的deleteStudentById根据id, 删除学生 studentService.deleteStudentById(delId); // 4. 提示删除成功 System.out.println(删除成功!); } // 查看学生方法 public void findAllStudent() { // 1. 调用业务员中的获取方法, 得到学生的对象数组 Student[] stus studentService.findAllStudent(); // 2. 判断数组的内存地址, 是否为null if (stus null) { System.out.println(查无信息, 请添加后重试); return; } // 3. 遍历数组, 获取学生信息并打印在控制台 System.out.println(学号\t\t姓名\t年龄\t生日); for (int i 0; i < stus.length; i) { Student stu stus[i]; if (stu ! null) { System.out.println(stu.getId() \t stu.getName() \t stu.getAge() \t\t stu.getBirthday()); } } } // 添加学生方法 public void addStudent() { // StudentService studentService new StudentService(); // 1. 键盘接收学生信息 String id; while (true) { System.out.println(请输入学生id:); id sc.next(); boolean flag studentService.isExists(id); if (flag) { System.out.println(学号已被占用, 请重新输入); } else { break; } } Student stu inputStudentInfo(id); // 3. 将学生对象,传递给StudentService(业务员)中的addStudent方法 boolean result studentService.addStudent(stu); // 4. 根据返回的boolean类型结果, 在控制台打印成功\失败 if (result) { System.out.println(添加成功); } else { System.out.println(添加失败); } } // 键盘录入学生id public String inputStudentId() { String id; while (true) { System.out.println(请输入学生id:); id sc.next(); boolean exists studentService.isExists(id); if (!exists) { System.out.println(您输入的id不存在, 请重新输入:); } else { break; } } return id; } // 键盘录入学生信息 // 开闭原则: 对扩展内容开放, 对修改内容关闭 public Student inputStudentInfo(String id){ return null; }}
StudentController类
public class StudentController extends BaseStudentController { private Scanner sc new Scanner(System.in); // 键盘录入学生信息 // 开闭原则: 对扩展内容开放, 对修改内容关闭 Override public Student inputStudentInfo(String id) { System.out.println(请输入学生姓名:); String name sc.next(); System.out.println(请输入学生年龄:); String age sc.next(); System.out.println(请输入学生生日:); String birthday sc.next(); Student stu new Student(); stu.setId(id); stu.setName(name); stu.setAge(age); stu.setBirthday(birthday); return stu; }}
OtherStudentController类
public class OtherStudentController extends BaseStudentController { private Scanner sc new Scanner(System.in); // 键盘录入学生信息 // 开闭原则: 对扩展内容开放, 对修改内容关闭 Override public Student inputStudentInfo(String id) { System.out.println(请输入学生姓名:); String name sc.next(); System.out.println(请输入学生年龄:); String age sc.next(); System.out.println(请输入学生生日:); String birthday sc.next(); Student stu new Student(id,name,age,birthday); return stu; }}
7.抽象类 7.1抽象类的概述理解 当我们在做子类共性功能抽取时有些方法在父类中并没有具体的体现这个时候就需要抽象类了
在Java中一个没有方法体的方法应该定义为抽象方法而类中如果有抽象方法该类必须定义为抽象类
7.2抽象类的特点记忆抽象类和抽象方法必须使用 abstract 关键字修饰
//抽象类的定义public abstract class 类名 {}//抽象方法的定义public abstract void eat();
抽象类中不一定有抽象方法有抽象方法的类一定是抽象类
抽象类不能实例化
抽象类可以有构造方法
抽象类的子类
要么重写抽象类中的所有抽象方法
要么是抽象类
7.3抽象类的案例应用案例需求
定义猫类(Cat)和狗类(Dog)
猫类成员方法eat猫吃鱼drink喝水…
狗类成员方法eat狗吃肉drink喝水…
实现步骤
猫类和狗类中存在共性内容应向上抽取出一个动物类Animal父类Animal中无法将 eat 方法具体实现描述清楚所以定义为抽象方法抽象方法需要存活在抽象类中将Animal定义为抽象类让 Cat 和 Dog 分别继承 Animal重写eat方法测试类中创建 Cat 和 Dog 对象调用方法测试代码实现
动物类public abstract class Animal { public void drink(){ System.out.println(喝水); } public Animal(){ } public abstract void eat();}
猫类 public class Cat extends Animal { Override public void eat() { System.out.println(猫吃鱼); }}
狗类 public class Dog extends Animal { Override public void eat() { System.out.println(狗吃肉); }}
测试类 public static void main(String[] args) { Dog d new Dog(); d.eat(); d.drink(); Cat c new Cat(); c.drink(); c.eat(); //Animal a new Animal(); //a.eat(); }
7.4模板设计模式 设计模式
设计模式Design pattern是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。
模板设计模式
把抽象类整体就可以看做成一个模板模板中不能决定的东西定义成抽象方法
让使用模板的类继承抽象类的类去重写抽象方法实现需求
模板设计模式的优势
模板已经定义了通用结构使用者只需要关心自己需要实现的功能即可
示例代码
模板类
/* 作文模板类 */public abstract class CompositionTemplate { public final void write(){ System.out.println(<<我的爸爸>>); body(); System.out.println(啊~ 这就是我的爸爸); } public abstract void body();}
实现类A
public class Tom extends CompositionTemplate { Override public void body() { System.out.println(那是一个秋天, 风儿那么缠绵,记忆中, 那天爸爸骑车接我放学回家,我的脚卡在了自行车链当中, 爸爸蹬不动,他就站起来蹬...); }}
实现类B
public class Tony extends CompositionTemplate { Override public void body() { } /*public void write(){ }*/}
测试类
public class Test { public static void main(String[] args) { Tom t new Tom(); t.write(); }}
7.5final应用 fianl关键字的作用
final代表最终的意思可以修饰成员方法成员变量类final修饰类、方法、变量的效果
fianl修饰类该类不能被继承不能有子类但是可以有父类
final修饰方法该方法不能被重写
final修饰变量表明该变量是一个常量不能再次赋值
变量是基本类型,不能改变的是值
变量是引用类型,不能改变的是地址值,但地址里面的内容是可以改变的
举例
public static void main(String[] args){ final Student s new Student(23); s new Student(24); // 错误 s.setAge(24); // 正确}
7.6黑马信息管理系统使用抽象类改进 (应用) 需求
使用抽象类的思想将BaseStudentController 中的 inputStudentInfo 方法定义为抽象方法将不希望子类重写的方法使用 final 进行修饰代码实现
BaseStudentController类
public abstract class BaseStudentController { // 业务员对象 private StudentService studentService new StudentService(); private Scanner sc new Scanner(System.in); // 开启学生管理系统, 并展示学生管理系统菜单 public final void start() { //Scanner sc new Scanner(System.in); studentLoop: while (true) { System.out.println(--------欢迎来到 <学生> 管理系统--------); System.out.println(请输入您的选择: 1.添加学生 2.删除学生 3.修改学生 4.查看学生 5.退出); String choice sc.next(); switch (choice) { case 1: // System.out.println(添加); addStudent(); break; case 2: // System.out.println(删除); deleteStudentById(); break; case 3: // System.out.println(修改); updateStudent(); break; case 4: // System.out.println(查询); findAllStudent(); break; case 5: System.out.println(感谢您使用学生管理系统, 再见!); break studentLoop; default: System.out.println(您的输入有误, 请重新输入); break; } } } // 修改学生方法 public final void updateStudent() { String updateId inputStudentId(); Student newStu inputStudentInfo(updateId); studentService.updateStudent(updateId, newStu); System.out.println(修改成功!); } // 删除学生方法 public final void deleteStudentById() { String delId inputStudentId(); // 3. 调用业务员中的deleteStudentById根据id, 删除学生 studentService.deleteStudentById(delId); // 4. 提示删除成功 System.out.println(删除成功!); } // 查看学生方法 public final void findAllStudent() { // 1. 调用业务员中的获取方法, 得到学生的对象数组 Student[] stus studentService.findAllStudent(); // 2. 判断数组的内存地址, 是否为null if (stus null) { System.out.println(查无信息, 请添加后重试); return; } // 3. 遍历数组, 获取学生信息并打印在控制台 System.out.println(学号\t\t姓名\t年龄\t生日); for (int i 0; i < stus.length; i) { Student stu stus[i]; if (stu ! null) { System.out.println(stu.getId() \t stu.getName() \t stu.getAge() \t\t stu.getBirthday()); } } } // 添加学生方法 public final void addStudent() { // StudentService studentService new StudentService(); // 1. 键盘接收学生信息 String id; while (true) { System.out.println(请输入学生id:); id sc.next(); boolean flag studentService.isExists(id); if (flag) { System.out.println(学号已被占用, 请重新输入); } else { break; } } Student stu inputStudentInfo(id); // 3. 将学生对象,传递给StudentService(业务员)中的addStudent方法 boolean result studentService.addStudent(stu); // 4. 根据返回的boolean类型结果, 在控制台打印成功\失败 if (result) { System.out.println(添加成功); } else { System.out.println(添加失败); } } // 键盘录入学生id public String inputStudentId() { String id; while (true) { System.out.println(请输入学生id:); id sc.next(); boolean exists studentService.isExists(id); if (!exists) { System.out.println(您输入的id不存在, 请重新输入:); } else { break; } } return id; } // 键盘录入学生信息 // 开闭原则: 对扩展内容开放, 对修改内容关闭 public abstract Student inputStudentInfo(String id);}
8.代码块 8.1代码块概述 (理解) 在Java中使用 { } 括起来的代码被称为代码块
8.2代码块分类 (理解)局部代码块
位置: 方法中定义
作用: 限定变量的生命周期及早释放提高内存利用率
示例代码
public class Test { /* 局部代码块 位置方法中定义 作用限定变量的生命周期及早释放提高内存利用率 */ public static void main(String[] args) { { int a 10; System.out.println(a); } // System.out.println(a); }}
构造代码块
位置: 类中方法外定义
特点: 每次构造方法执行的时都会执行该代码块中的代码并且在构造方法执行前执行
作用: 将多个构造方法中相同的代码抽取到构造代码块中提高代码的复用性
示例代码
public class Test { /* 构造代码块: 位置类中方法外定义 特点每次构造方法执行的时都会执行该代码块中的代码并且在构造方法执行前执行 作用将多个构造方法中相同的代码抽取到构造代码块中提高代码的复用性 */ public static void main(String[] args) { Student stu1 new Student(); Student stu2 new Student(10); }}class Student { { System.out.println(好好学习); } public Student(){ System.out.println(空参数构造方法); } public Student(int a){ System.out.println(带参数构造方法...........); }}
静态代码块
位置: 类中方法外定义
特点: 需要通过static关键字修饰随着类的加载而加载并且只执行一次
作用: 在类加载的时候做一些数据初始化的操作
示例代码
public class Test { /* 静态代码块: 位置类中方法外定义 特点需要通过static关键字修饰随着类的加载而加载并且只执行一次 作用在类加载的时候做一些数据初始化的操作 */ public static void main(String[] args) { Person p1 new Person(); Person p2 new Person(10); }}class Person { static { System.out.println(我是静态代码块, 我执行了); } public Person(){ System.out.println(我是Person类的空参数构造方法); } public Person(int a){ System.out.println(我是Person类的带...........参数构造方法); }}
8.3黑马信息管理系统使用代码块改进 (应用) 需求
使用静态代码块初始化一些学生数据
实现步骤
在StudentDao类中定义一个静态代码块用来初始化一些学生数据将初始化好的学生数据存储到学生数组中示例代码
StudentDao类
public class StudentDao { // 创建学生对象数组 private static Student[] stus new Student[5]; static { Student stu1 new Student(heima001,张三,23,1999-11-11); Student stu2 new Student(heima002,李四,24,2000-11-11); stus[0] stu1; stus[1] stu2; } // 添加学生方法 public boolean addStudent(Student stu) { // 2. 添加学生到数组 //2.1 定义变量index为-1假设数组已经全部存满没有null的元素 int index -1; //2.2 遍历数组取出每一个元素判断是否是null for (int i 0; i < stus.length; i) { Student student stus[i]; if(student null){ index i; //2.3 如果为null让index变量记录当前索引位置并使用break结束循环遍历 break; } } // 3. 返回是否添加成功的boolean类型状态 if(index -1){ // 装满了 return false; }else{ // 没有装满, 正常添加, 返回true stus[index] stu; return true; } } // 查看学生方法 public Student[] findAllStudent() { return stus; } public void deleteStudentById(String delId) { // 1. 查找id在容器中所在的索引位置 int index getIndex(delId); // 2. 将该索引位置,使用null元素进行覆盖 stus[index] null; } public int getIndex(String id){ int index -1; for (int i 0; i < stus.length; i) { Student stu stus[i]; if(stu ! null && stu.getId().equals(id)){ index i; break; } } return index; } public void updateStudent(String updateId, Student newStu) { // 1. 查找updateId, 在容器中的索引位置 int index getIndex(updateId); // 2. 将该索引位置, 使用新的学生对象替换 stus[index] newStu; }}
9.接口 9.1黑马信息管理系统集合改进 (应用) 使用数组容器的弊端
容器长度是固定的不能根据添加功能自动增长没有提供用于赠删改查的方法优化步骤
创建新的StudentDao类OtherStudentDao
创建ArrayList集合容器对象
OtherStudentDao中的方法声明需要跟StudentDao保持一致
注意如果不一致StudentService中的代码就需要进行修改
完善方法添加、删除、修改、查看
替换StudentService中的Dao对象
代码实现
OtherStudentDao类
public class OtherStudentDao { // 集合容器 private static ArrayList<Student> stus new ArrayList<>(); static { Student stu1 new Student(heima001,张三,23,1999-11-11); Student stu2 new Student(heima002,李四,24,2000-11-11); stus.add(stu1); stus.add(stu2); } // 添加学生方法 public boolean addStudent(Student stu) { stus.add(stu); return true; } // 查看学生方法 public Student[] findAllStudent() { Student[] students new Student[stus.size()]; for (int i 0; i < students.length; i) { students[i] stus.get(i); } return students; } public void deleteStudentById(String delId) { // 1. 查找id在容器中所在的索引位置 int index getIndex(delId); stus.remove(index); } public int getIndex(String id){ int index -1; for (int i 0; i < stus.size(); i) { Student stu stus.get(i); if(stu ! null && stu.getId().equals(id)){ index i; break; } } return index; } public void updateStudent(String updateId, Student newStu) { // 1. 查找updateId, 在容器中的索引位置 int index getIndex(updateId); stus.set(index, newStu); }}
StudentService类
public class StudentService { // 创建StudentDao (库管) private OtherStudentDao studentDao new OtherStudentDao(); // 其他方法没有变化,此处省略...}
9.2黑马信息管理系统抽取Dao (应用) 优化步骤
将方法向上抽取抽取出一个父类 BaseStudentDao 方法的功能实现在父类中无法给出具体明确定义为抽象方法让两个类分别继承 BaseStudentDao 重写内部抽象方法代码实现
BaseStudentDao类
public abstract class BaseStudentDao { // 添加学生方法 public abstract boolean addStudent(Student stu); // 查看学生方法 public abstract Student[] findAllStudent(); // 删除学生方法 public abstract void deleteStudentById(String delId); // 根据id找索引方法 public abstract int getIndex(String id); // 修改学生方法 public abstract void updateStudent(String updateId, Student newStu);}
StudentDao类
public class StudentDao extends BaseStudentDao { // 其他内容不变,此处省略}
OtherStudentDao类
public class OtherStudentDao extends BaseStudentDao { // 其他内容不变,此处省略}
9.3接口的概述理解 接口就是一种公共的规范标准只要符合规范标准大家都可以通用。Java中接口存在的两个意义 用来定义规范用来做功能的拓展 9.4接口的特点记忆 接口用关键字interface修饰
public interface 接口名 {}
类实现接口用implements表示
public class 类名 implements 接口名 {}
接口不能实例化
我们可以创建接口的实现类对象使用
接口的子类
要么重写接口中的所有抽象方法
要么子类也是抽象类
9.5接口的成员特点记忆成员特点
成员变量
只能是常量
默认修饰符public static final
构造方法
没有因为接口主要是扩展功能的而没有具体存在
成员方法
只能是抽象方法
默认修饰符public abstract
关于接口中的方法JDK8和JDK9中有一些新特性后面再讲解
代码演示
接口public interface Inter { public static final int NUM 10; public abstract void show();}
实现类 class InterImpl implements Inter{ public void method(){ // NUM 20; System.out.println(NUM); } public void show(){ }}
测试类 public class TestInterface { /* 成员变量: 只能是常量 系统会默认加入三个关键字 public static final 构造方法: 没有 成员方法: 只能是抽象方法, 系统会默认加入两个关键字 public abstract */ public static void main(String[] args) { System.out.println(Inter.NUM); } }
9.6类和接口的关系记忆 类与类的关系
继承关系只能单继承但是可以多层继承
类与接口的关系
实现关系可以单实现也可以多实现还可以在继承一个类的同时实现多个接口
接口与接口的关系
继承关系可以单继承也可以多继承
9.7黑马信息管理系统使用接口改进 (应用)实现步骤
将 BaseStudentDao 改进为一个接口让 StudentDao 和 OtherStudentDao 去实现这个接口代码实现
BaseStudentDao接口
public interface BaseStudentDao { // 添加学生方法 public abstract boolean addStudent(Student stu); // 查看学生方法 public abstract Student[] findAllStudent(); // 删除学生方法 public abstract void deleteStudentById(String delId); // 根据id找索引方法 public abstract int getIndex(String id); // 修改学生方法 public abstract void updateStudent(String updateId, Student newStu);}
StudentDao类
public class StudentDao implements BaseStudentDao { // 其他内容不变,此处省略}
OtherStudentDao类
public class OtherStudentDao implements BaseStudentDao { // 其他内容不变,此处省略}
9.8黑马信息管理系统解耦合改进 (应用) 实现步骤
创建factory包创建 StudentDaoFactory工厂类提供 static 修改的 getStudentDao 方法该方法用于创建StudentDao对象并返回代码实现
StudentDaoFactory类
public class StudentDaoFactory { public static OtherStudentDao getStudentDao(){ return new OtherStudentDao(); }}
StudentService类
public class StudentService { // 创建StudentDao (库管) // private OtherStudentDao studentDao new OtherStudentDao(); // 通过学生库管工厂类, 获取库管对象 private OtherStudentDao studentDao StudentDaoFactory.getStudentDao();}
10.接口组成更新 10.1接口组成更新概述【理解】 常量
public static final
抽象方法
public abstract
默认方法(Java 8)
静态方法(Java 8)
私有方法(Java 9)
10.2接口中默认方法【应用】格式
public default 返回值类型 方法名(参数列表) { }
作用
解决接口升级的问题
范例
public default void show3() { }
注意事项
默认方法不是抽象方法所以不强制被重写。但是可以被重写重写的时候去掉default关键字public可以省略default不能省略如果实现了多个接口多个接口中存在相同的方法声明子类就必须对该方法进行重写 10.3接口中静态方法【应用】格式
public static 返回值类型 方法名(参数列表) { }
范例
public static void show() {}
注意事项
静态方法只能通过接口名调用不能通过实现类名或者对象名调用public可以省略static不能省略 10.4接口中私有方法【应用】私有方法产生原因
Java 9中新增了带方法体的私有方法这其实在Java 8中就埋下了伏笔Java 8允许在接口中定义带方法体的默认方法和静态方法。这样可能就会引发一个问题当两个默认方法或者静态方法中包含一段相同的代码实现时程序必然考虑将这段实现代码抽取成一个共性方法而这个共性方法是不需要让别人使用的因此用私有给隐藏起来这就是Java 9增加私有方法的必然性
定义格式
格式1
private 返回值类型 方法名(参数列表) { }
范例1
private void show() { }
格式2
private static 返回值类型 方法名(参数列表) { }
范例2
private static void method() { }
注意事项
默认方法可以调用私有的静态方法和非静态方法静态方法只能调用私有的静态方法 11.多态 11.1多态的概述记忆什么是多态
同一个对象在不同时刻表现出来的不同形态
多态的前提
要有继承或实现关系要有方法的重写要有父类引用指向子类对象代码演示
class Animal { public void eat(){ System.out.println(动物吃饭); }}class Cat extends Animal { Override public void eat() { System.out.println(猫吃鱼); }}public class Test1Polymorphic { /* 多态的前提: 1. 要有(继承 \ 实现)关系 2. 要有方法重写 3. 要有父类引用, 指向子类对象 */ public static void main(String[] args) { // 当前事物, 是一只猫 Cat c new Cat(); // 当前事物, 是一只动物 Animal a new Cat(); a.eat(); }}
11.2多态中的成员访问特点记忆 成员访问特点
成员变量
编译看父类运行看父类
成员方法
编译看父类运行看子类
代码演示
class Fu { int num 10; public void method(){ System.out.println(Fu.. method); }}class Zi extends Fu { int num 20; public void method(){ System.out.println(Zi.. method); }}public class Test2Polymorpic { /* 多态的成员访问特点: 成员变量: 编译看左边 (父类), 运行看左边 (父类) 成员方法: 编译看左边 (父类), 运行看右边 (子类) */ public static void main(String[] args) { Fu f new Zi(); System.out.println(f.num); f.method(); }}
11.3多态的好处和弊端记忆 好处
提高程序的扩展性。定义方法时候使用父类型作为参数在使用的时候使用具体的子类型参与操作
弊端
不能使用子类的特有成员
11.4多态中的转型应用向上转型
父类引用指向子类对象就是向上转型
向下转型
格式子类型 对象名 (子类型)父类引用;
代码演示
class Fu { public void show(){ System.out.println(Fu..show...); }}class Zi extends Fu { Override public void show() { System.out.println(Zi..show...); } public void method(){ System.out.println(我是子类特有的方法, method); }}public class Test3Polymorpic { public static void main(String[] args) { // 1. 向上转型 : 父类引用指向子类对象 Fu f new Zi(); f.show(); // 多态的弊端: 不能调用子类特有的成员 // f.method(); // A: 直接创建子类对象 // B: 向下转型 // 2. 向下转型 : 从父类类型, 转换回子类类型 Zi z (Zi) f; z.method(); }}
11.5多态中转型存在的风险和解决方案 (应用) 风险
如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException
解决方案
关键字
instanceof
使用格式
变量名 instanceof 类型
通俗的理解判断关键字左边的变量是否是右边的类型返回boolean类型结果
代码演示
abstract class Animal { public abstract void eat();}class Dog extends Animal { public void eat() { System.out.println(狗吃肉); } public void watchHome(){ System.out.println(看家); }}class Cat extends Animal { public void eat() { System.out.println(猫吃鱼); }}public class Test4Polymorpic { public static void main(String[] args) { useAnimal(new Dog()); useAnimal(new Cat()); } public static void useAnimal(Animal a){ // Animal a new Dog(); // Animal a new Cat(); a.eat(); //a.watchHome();// Dog dog (Dog) a;// dog.watchHome(); // ClassCastException 类型转换异常 // 判断a变量记录的类型, 是否是Dog if(a instanceof Dog){ Dog dog (Dog) a; dog.watchHome(); } }}
11.6黑马信息管理系统多态改进 (应用) 实现步骤
StudentDaoFactory类中方法的返回值定义成父类类型BaseStudentDaoStudentService中接收方法返回值的类型定义成父类类型BaseStudentDao代码实现
StudentDaoFactory类
public class StudentDaoFactory { public static BaseStudentDao getStudentDao(){ return new OtherStudentDao(); }}
StudentService类
public class StudentService { // 创建StudentDao (库管) // private OtherStudentDao studentDao new OtherStudentDao(); // 通过学生库管工厂类, 获取库管对象 private BaseStudentDao studentDao StudentDaoFactory.getStudentDao();}
12.内部类 12.1 内部类的基本使用理解 内部类概念
在一个类中定义一个类。举例在一个类A的内部定义一个类B类B就被称为内部类内部类定义格式
格式&举例
/*格式 class 外部类名{ 修饰符 class 内部类名{ } }*/class Outer { public class Inner { }}
内部类的访问特点
内部类可以直接访问外部类的成员包括私有外部类要访问内部类的成员必须创建对象示例代码
/* 内部类访问特点 内部类可以直接访问外部类的成员包括私有 外部类要访问内部类的成员必须创建对象 */public class Outer { private int num 10; public class Inner { public void show() { System.out.println(num); } } public void method() { Inner i new Inner(); i.show(); }}
12.2 成员内部类理解 成员内部类的定义位置
在类中方法跟成员变量是一个位置外界创建成员内部类格式
格式外部类名.内部类名 对象名 外部类对象.内部类对象;举例Outer.Inner oi new Outer().new Inner();私有成员内部类
将一个类设计为内部类的目的大多数都是不想让外界去访问所以内部类的定义应该私有化私有化之后再提供一个可以让外界调用的方法方法内部创建内部类对象并调用。
示例代码
class Outer { private int num 10; private class Inner { public void show() { System.out.println(num); } } public void method() { Inner i new Inner(); i.show(); }}public class InnerDemo { public static void main(String[] args) {//Outer.Inner oi new Outer().new Inner();//oi.show(); Outer o new Outer(); o.method(); }}
静态成员内部类
静态成员内部类访问格式外部类名.内部类名 对象名 new 外部类名.内部类名();
静态成员内部类中的静态方法外部类名.内部类名.方法名();
示例代码
class Outer { static class Inner { public void show(){ System.out.println(inner..show); } public static void method(){ System.out.println(inner..method); } }}public class Test3Innerclass { /* 静态成员内部类演示 */ public static void main(String[] args) { // 外部类名.内部类名 对象名 new 外部类名.内部类名(); Outer.Inner oi new Outer.Inner(); oi.show(); Outer.Inner.method(); }}
12.3 局部内部类理解 局部内部类定义位置
局部内部类是在方法中定义的类局部内部类方式方式
局部内部类外界是无法直接使用需要在方法内部创建对象并使用该类可以直接访问外部类的成员也可以访问方法内的局部变量示例代码
class Outer { private int num 10; public void method() { int num2 20; class Inner { public void show() { System.out.println(num); System.out.println(num2); } } Inner i new Inner(); i.show(); }}public class OuterDemo { public static void main(String[] args) { Outer o new Outer(); o.method(); }}
12.4 匿名内部类应用 匿名内部类的前提
存在一个类或者接口这里的类可以是具体类也可以是抽象类匿名内部类的格式
格式new 类名 ( ) { 重写方法 } new 接口名 ( ) { 重写方法 }
举例
new Inter(){ Override public void method(){}}
匿名内部类的本质
本质是一个继承了该类或者实现了该接口的子类匿名对象匿名内部类的细节
匿名内部类可以通过多态的形式接受
Inter i new Inter(){ Override public void method(){ }}
匿名内部类直接调用方法
interface Inter{ void method();}class Test{ public static void main(String[] args){ new Inter(){ Override public void method(){ System.out.println(我是匿名内部类); } }.method();// 直接调用方法 }}
12.5匿名内部类在开发中的使用应用 匿名内部类在开发中的使用
当发现某个方法需要接口或抽象类的子类对象我们就可以传递一个匿名内部类过去来简化传统的代码示例代码
/* 游泳接口 */interface Swimming { void swim();}public class TestSwimming { public static void main(String[] args) { goSwimming(new Swimming() { Override public void swim() { System.out.println(铁汁, 我们去游泳吧); } }); } /** * 使用接口的方法 */ public static void goSwimming(Swimming swimming){ /* Swimming swim new Swimming() { Override public void swim() { System.out.println(铁汁, 我们去游泳吧); } } */ swimming.swim(); }}
13.Lambda表达式 13.1体验Lambda表达式【理解】 代码演示
/* 游泳接口 */interface Swimming { void swim();}public class TestSwimming { public static void main(String[] args) { // 通过匿名内部类实现 goSwimming(new Swimming() { Override public void swim() { System.out.println(铁汁, 我们去游泳吧); } }); /* 通过Lambda表达式实现 理解: 对于Lambda表达式, 对匿名内部类进行了优化 */ goSwimming(() -> System.out.println(铁汁, 我们去游泳吧)); } /** * 使用接口的方法 */ public static void goSwimming(Swimming swimming) { swimming.swim(); }}
函数式编程思想概述
在数学中函数就是有输入量、输出量的一套计算方案也就是“拿数据做操作”
面向对象思想强调“必须通过对象的形式来做事情”
函数式思想则尽量忽略面向对象的复杂语法“强调做什么而不是以什么形式去做”
而我们要学习的Lambda表达式就是函数式思想的体现
13.2Lambda表达式的标准格式【理解】格式
(形式参数) -> {代码块}
形式参数如果有多个参数参数之间用逗号隔开如果没有参数留空即可->由英文中画线和大于符号组成固定写法。代表指向动作代码块是我们具体要做的事情也就是以前我们写的方法体内容组成Lambda表达式的三要素
形式参数箭头代码块 13.3Lambda表达式练习1【应用】Lambda表达式的使用前提
有一个接口接口中有且仅有一个抽象方法练习描述
无参无返回值抽象方法的练习
操作步骤
定义一个接口(Eatable)里面定义一个抽象方法void eat();定义一个测试类(EatableDemo)在测试类中提供两个方法 一个方法是useEatable(Eatable e)一个方法是主方法在主方法中调用useEatable方法示例代码
//接口public interface Eatable { void eat();}//实现类public class EatableImpl implements Eatable { Override public void eat() { System.out.println(一天一苹果医生远离我); }}//测试类public class EatableDemo { public static void main(String[] args) { //在主方法中调用useEatable方法 Eatable e new EatableImpl(); useEatable(e); //匿名内部类 useEatable(new Eatable() { Override public void eat() { System.out.println(一天一苹果医生远离我); } }); //Lambda表达式 useEatable(() -> { System.out.println(一天一苹果医生远离我); }); } private static void useEatable(Eatable e) { e.eat(); }}
13.4Lambda表达式练习2【应用】 练习描述
有参无返回值抽象方法的练习
操作步骤
定义一个接口(Flyable)里面定义一个抽象方法void fly(String s);定义一个测试类(FlyableDemo)在测试类中提供两个方法 一个方法是useFlyable(Flyable f)一个方法是主方法在主方法中调用useFlyable方法示例代码
public interface Flyable { void fly(String s);}public class FlyableDemo { public static void main(String[] args) { //在主方法中调用useFlyable方法 //匿名内部类 useFlyable(new Flyable() { Override public void fly(String s) { System.out.println(s); System.out.println(飞机自驾游); } }); System.out.println(--------); //Lambda useFlyable((String s) -> { System.out.println(s); System.out.println(飞机自驾游); }); } private static void useFlyable(Flyable f) { f.fly(风和日丽晴空万里); }}
13.5Lambda表达式练习3【应用】 练习描述
有参有返回值抽象方法的练习
操作步骤
定义一个接口(Addable)里面定义一个抽象方法int add(int x,int y);定义一个测试类(AddableDemo)在测试类中提供两个方法 一个方法是useAddable(Addable a)一个方法是主方法在主方法中调用useAddable方法示例代码
public interface Addable { int add(int x,int y);}public class AddableDemo { public static void main(String[] args) { //在主方法中调用useAddable方法 useAddable((int x,int y) -> { return x y; }); } private static void useAddable(Addable a) { int sum a.add(10, 20); System.out.println(sum); }}
13.6Lambda表达式的省略模式【应用】 省略的规则
参数类型可以省略。但是有多个参数的情况下不能只省略一个如果参数有且仅有一个那么小括号可以省略如果代码块的语句只有一条可以省略大括号和分号和return关键字代码演示
public interface Addable { int add(int x, int y);}public interface Flyable { void fly(String s);}public class LambdaDemo { public static void main(String[] args) {// useAddable((int x,int y) -> {// return x y;// }); //参数的类型可以省略 useAddable((x, y) -> { return x y; });// useFlyable((String s) -> {// System.out.println(s);// }); //如果参数有且仅有一个那么小括号可以省略// useFlyable(s -> {// System.out.println(s);// }); //如果代码块的语句只有一条可以省略大括号和分号 useFlyable(s -> System.out.println(s)); //如果代码块的语句只有一条可以省略大括号和分号如果有returnreturn也要省略掉 useAddable((x, y) -> x y); } private static void useFlyable(Flyable f) { f.fly(风和日丽晴空万里); } private static void useAddable(Addable a) { int sum a.add(10, 20); System.out.println(sum); }}
13.7Lambda表达式的使用前提【理解】 使用Lambda必须要有接口并且要求接口中有且仅有一个抽象方法 13.8Lambda表达式和匿名内部类的区别【理解】 所需类型不同 匿名内部类可以是接口也可以是抽象类还可以是具体类Lambda表达式只能是接口 使用限制不同 如果接口中有且仅有一个抽象方法可以使用Lambda表达式也可以使用匿名内部类如果接口中多于一个抽象方法只能使用匿名内部类而不能使用Lambda表达式 实现原理不同 匿名内部类编译之后产生一个单独的.class字节码文件Lambda表达式编译之后没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成 void fly(String s);
定义一个测试类(FlyableDemo)在测试类中提供两个方法
一个方法是useFlyable(Flyable f)一个方法是主方法在主方法中调用useFlyable方法示例代码
public interface Flyable { void fly(String s);}public class FlyableDemo { public static void main(String[] args) { //在主方法中调用useFlyable方法 //匿名内部类 useFlyable(new Flyable() { Override public void fly(String s) { System.out.println(s); System.out.println(飞机自驾游); } }); System.out.println(--------); //Lambda useFlyable((String s) -> { System.out.println(s); System.out.println(飞机自驾游); }); } private static void useFlyable(Flyable f) { f.fly(风和日丽晴空万里); }}
13.5Lambda表达式练习3【应用】 练习描述
有参有返回值抽象方法的练习
操作步骤
定义一个接口(Addable)里面定义一个抽象方法int add(int x,int y);定义一个测试类(AddableDemo)在测试类中提供两个方法 一个方法是useAddable(Addable a)一个方法是主方法在主方法中调用useAddable方法示例代码
public interface Addable { int add(int x,int y);}public class AddableDemo { public static void main(String[] args) { //在主方法中调用useAddable方法 useAddable((int x,int y) -> { return x y; }); } private static void useAddable(Addable a) { int sum a.add(10, 20); System.out.println(sum); }}
13.6Lambda表达式的省略模式【应用】 省略的规则
参数类型可以省略。但是有多个参数的情况下不能只省略一个如果参数有且仅有一个那么小括号可以省略如果代码块的语句只有一条可以省略大括号和分号和return关键字代码演示
public interface Addable { int add(int x, int y);}public interface Flyable { void fly(String s);}public class LambdaDemo { public static void main(String[] args) {// useAddable((int x,int y) -> {// return x y;// }); //参数的类型可以省略 useAddable((x, y) -> { return x y; });// useFlyable((String s) -> {// System.out.println(s);// }); //如果参数有且仅有一个那么小括号可以省略// useFlyable(s -> {// System.out.println(s);// }); //如果代码块的语句只有一条可以省略大括号和分号 useFlyable(s -> System.out.println(s)); //如果代码块的语句只有一条可以省略大括号和分号如果有returnreturn也要省略掉 useAddable((x, y) -> x y); } private static void useFlyable(Flyable f) { f.fly(风和日丽晴空万里); } private static void useAddable(Addable a) { int sum a.add(10, 20); System.out.println(sum); }}
13.7Lambda表达式的使用前提【理解】 使用Lambda必须要有接口并且要求接口中有且仅有一个抽象方法 13.8Lambda表达式和匿名内部类的区别【理解】 所需类型不同 匿名内部类可以是接口也可以是抽象类还可以是具体类Lambda表达式只能是接口 使用限制不同 如果接口中有且仅有一个抽象方法可以使用Lambda表达式也可以使用匿名内部类如果接口中多于一个抽象方法只能使用匿名内部类而不能使用Lambda表达式 实现原理不同 匿名内部类编译之后产生一个单独的.class字节码文件Lambda表达式编译之后没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成