1. 继承
1.1 继承的实现(掌握)
-
继承的概念
-
继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及追加属性和方法
-
-
实现继承的格式
-
继承通过extends实现 public class 子类名 extends 父类名{ }
-
格式:class 子类 extends 父类 { }
-
举例:class Dog extends Animal { }
- Fu:是父类,也被称为基类,超类
- Zi:是子类,也被称为派生类
-
-
-
继承带来的好处
-
继承可以让类与类之间产生关系,子父类关系,产生子父类后,子类则可以使用父类中非私有的成员。
- 提高了代码的复用性
- 提高了代码的维护性
- 让类与类之间产生了关系,是多态的前提
- 继承的弊端:
继承是侵入性的
降低了代码的灵活性
继承关系,导致子类必须拥有父类非私有属性和方法,让子类自由的世界中多了些约束
增强了代码的耦合性
代码与代码之间存在关联都可以将其称之为“耦合”
- 耦合性:代码与代码之间存在关联都可以将其称之为“耦合”
什么时候使用继承?
当类与类之间,存在相同(共性)的内容,并且产生了ia a的关系,就可以考虑使用继承,来优化代码
继承的特点:
Java只支持单继承,不支持多继承,但支持多层继承
单继承:子类只能继承一个父类
多层继承:子类A继承父类B,父类B可以继承父类C
问题:为什么不支持多继承?
为了避免逻辑冲突问题,所以不支持多继承
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(); } }
继承的特点代码
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方法 }
2. 继承中的成员访问特点
2.1 继承中变量的访问特点(掌握)
在子类方法中访问一个变量,采用的是就近原则。
-
子类局部范围找
-
子类成员范围找
-
父类成员范围找
-
如果都没有就报错(不考虑父亲的父亲…
注意:如果子父类中,出现了重名的成员变量,通过就近原则,会优先使用子类的,如果一定要使用父类的,可以通过super关键字,进行区分。
-
示例代码
public class Fu { int a=10; } public class Zi extends Fu{ //子父类当中,出现了重名的成员变量 int a=20; public void method(){ int a=30; System.out.println(a);//30 //需求1:在控制台打印本类成员变量20 System.out.println(this.a);//20 //需求2:在控制台打印父类成员变量10 System.out.println(super.a);//10 } } public class Test { public static void main(String[] args) { Zi z=new Zi(); z.method(); } }
结果打印 30 20 10
2.2 super(掌握)
- super关键字的用法和this关键字的用法相似
-
this&super关键字:
-
this:代表本类对象的引用
-
super:代表父类存储空间的标识(可以理解为父类对象引用)
-
-
this和super的使用分别
-
成员变量:
-
this.成员变量 - 访问本类成员变量
-
super.成员变量 - 访问父类成员变量
-
-
成员方法:
-
this.成员方法 - 访问本类成员方法
-
super.成员方法 - 访问父类成员方法
-
-
构造方法:
-
this(…) - 访问本类构造方法
-
super(…) - 访问父类构造方法
-
-
2.4 继承中成员方法的访问特点(掌握)
通过子类对象访问一个方法
-
子类成员范围找
-
父类成员范围找
-
如果都没有就报错(不考虑父亲的父亲…)
2.6 方法重写(掌握)
-
1、方法重写概念
-
在继承体系中,子类出现了和父类中一模一样的方法声明(方法名一样,参数列表也必须一样,返回值类型也是)
-
-
2、方法重写的应用场景
-
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容
- 练习:手机类和新手机类
-
注意:
方法重写: 在继承体系中, 子类出现了和父类一模一样的方法声明 (方法名, 参数列表, 返回值类型)
方法重载: 在同一个类中, 方法名相同, 参数列表不同, 与返回值无关. -
3、Override注解
-
用来检测当前的方法,是否是重写的方法,起到【校验】的作用
-
public class iPearV1 { /* 1. 定义手机类 iPearV1 call(String name) : 打电话方法 smallBlack() : 语音助手 (speak english...) */ public void call(String name){ System.out.println("给"+name+"打电话"); } public void smallBlack(){ System.out.println("speak english..."); } } public class iPearV2 extends iPearV1{ /* 2. 定义新手机类 iPearV2 call(String name) : 打电话方法 smallBlack() : 语音助手 (speak english... 说中文) 方法重写的应用场景: 当子类需要父类的功能,而功能主体子类有自己特有内容 可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容 */ @Override public void smallBlack(){ super.smallBlack();//父类功能保留 System.out.println("说中文"); } } public class TestOverride { /* 需求: 1. 定义手机类 iPearV1 call(String name) : 打电话方法 smallBlack() : 语音助手 (speak english...) 2. 定义新手机类 iPearV2 call(String name) : 打电话方法 smallBlack() : 语音助手 (speak english... 说中文) 方法重写的应用场景: 当子类需要父类的功能,而功能主体子类有自己特有内容 可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容 注意: 方法重写: 在继承体系中, 子类出现了和父类一模一样的方法声明 (方法名, 参数列表, 返回值类型) 方法重载: 在同一个类中, 方法名相同, 参数列表不同, 与返回值无关. */ public static void main(String[] args) { iPearV2 i=new iPearV2(); i.smallBlack(); } }
2.7 方法重写的注意事项(掌握)
-
方法重写的注意事项
-
私有方法不能被重写(父类私有成员子类是不能继承的)
-
子类重写父类方法时,访问权限必须大于等于父类 (public > protected> 默认 > 私有)
-
父类静态方法,子类必须通过静态方法进行重写,父类非静态方法,子类也必须通过非静态方法进行重写
注意:静态方法不能被重写!!!如果子类中,也存在一个方法声明一模一样的方法
可以理解为,子类将父类中同名的方法,隐藏了起来,并非是方法重写!现象是重写,本质上并不是
-
示例代码
public class Fu { public static void show(){ System.out.println("Fu..."); } void method(){ System.out.println("Fu...method"); } } public class Zi extends Fu{ //@Override //注解:检查当前的方法是否是一个正确的重写方法 public static void show() { System.out.println("Zi..."); } @Override public void method() { } } public class Test { public static void main(String[] args) { Zi z=new Zi(); z.show(); } }
权限修饰符可以修饰的内容是成员 (成员变量,成员方法,构造方法)
2.3 继承中构造方法的访问特点(理解)
注意:子类中所有的构造方法默认都会访问父类中无参的构造方法
为什么?
子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据
所以,子类初始化之前,一定要先完成父类数据的初始化。
怎样初始化?
每一个子类构造方法的第一条语句默认都是:super()
注意:如果我们编写的类,没有手动指定父类,系统也会自动继承Object(Java继承体系中的最顶层父类)
问题:如果父类中没有空参构造方法,只有带参构造方法,会出现什么现象呢?
- 子类通过super,手动调用父类的带参构造方法
- 子类通过this去调用本类的其他构造方法,本类其他构造方法再通过super去手动调用父类的带参构造方法
注意:this(...)super(...)必须放在构造方法的第一行有效语句,并且二者不能共存
//如果一个类被public 修饰了类名必须和文件名一致 public class Test2 { public static void main(String[] args) { Zi z=new Zi(); } } class Fu{ int age; //空参数构造方法 public Fu(){ System.out.println("父类空参构造方法"); } //带参数构造方法 public Fu(int age){ this.age=age; } } class Zi extends Fu{ public Zi(){ this(10); // this(),super()都必须放在构造方法第一条语句,二者不能共存 //super(); } public Zi(int age){ super(age); } }
2.5 super内存图(理解)
-
对象在堆内存中,会单独存在一块super区域,用来存放父类的数据
总结:
子类当中所有的构造方法,默认都会通过super()访问父类中无参的构造方法
每一个子类构造方法的第一条语句默认都是:super()
this(...)super(...)必须放在构造方法的第一行有效语句,并且二者不能共存
黑马信息管理系统改进
思路:把学生类和老师类共性的内容向上抽取,抽取到一个Person父类,让学生类老师类继承Person类
步骤1:抽取Person类。
步骤2:优化StudentController类中,inputStudentInfo方法。将setXxx赋值方式,改进为构造方法初始化
注意:直接修改这种操作方式,不符合我们开发当中的一个原则
开闭原则(队扩展开放对修改关闭)
解决:重新创建一个OtherStudentController类
便写新的inputStudentInfo方法
步骤3:根据StudentController类,OtherStudentController类,向上抽取出BaseStudentController类
再让StudentController类,OtherStudentController类,继承BaseStudentController类
该三个部分
controller类
BaseStudentController:
package com.itheima.edu.info.manager.controller; import com.itheima.edu.info.manager.domain.Student; import com.itheima.edu.info.manager.service.StudentService; import java.util.Scanner; public class BaseStudentController { // 3. 将学生对象,传递给StudentService(业务员)中的addStudent方法 private StudentService studentService=new StudentService(); private Scanner sc=new Scanner(System.in); //开启学生管理系统,并展示学生管理系统菜单 public void start() { 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(); //调用业务员中的deleteStudentById根据id,删除学生 studentService.deleteStudentById(delId); //提示:删除成功 System.out.println("删除成功"); } //查看学生方法 public void findAllStudent() { //1.调用业务员中的获取方法,得到学生的对象数组 Student[] stus=studentService.findAllStudent(); //2.判断数组的内存地址,是否为null if(stus==null){ System.out.println("查无信息,请添加后重试"); return; } //3.遍历数组,获取学生的信息,并打印在控制台 System.out.println("学号 姓名 年龄 生日"); for (int i = 0; i < stus.length; i++) { Student stu=stus[i]; if(stu!=null){ System.out.println(stu.getId()+" "+stu.getName()+" "+stu.getAge()+" "+stu.getBirthday()); } } } //添加学生方法 public void addStudent() { 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); 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; } }
BaseTeacherController:
package com.itheima.edu.info.manager.controller; import com.itheima.edu.info.manager.domain.Teacher; import com.itheima.edu.info.manager.service.TeacherService; import java.util.Scanner; public class BaseTeacherController { 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 updateId = inputTeacherId(); Teacher newTeacher = inputTeacherInfo(updateId); //调用业务员的修改方法 teacherService.updateTeacher(updateId,newTeacher); System.out.println("修改成功"); } //删除老师 public void deleteTeacherById() { String delId = inputTeacherId(); //调用业务员中的deleteStudentById根据i //,删除老师 teacherService.deleteTeacherById(delId); //提示:删除成功 System.out.println("删除成功"); } //查询老师 public void findAllTeacher() { //1.从业务员中获取老师对象数组 Teacher[] teachers=teacherService.findAllTeacher(); //判断数组中是否有元素 if (teachers == null) { System.out.println("查无信息,请添加后重试"); return; } //3.遍历数组,获取学生信息,并打印在控制台 System.out.println("学号 姓名 年龄 生日"); for (int i = 0; i < teachers.length; i++) { Teacher t=teachers[i]; if (t != null) { System.out.println(t.getId()+" "+t.getName()+" "+t.getAge()+" "+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){ //键盘接收要删除的老师id 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){ return null; } }
OtherStudentController:
package com.itheima.edu.info.manager.controller; import com.itheima.edu.info.manager.domain.Student; import com.itheima.edu.info.manager.service.StudentService; import java.util.Scanner; 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(); //2.将学生信息封装为学生对象 Student stu=new Student(id,name,age,birthday); return stu; } }
OtherTeacherController:
package com.itheima.edu.info.manager.controller; import com.itheima.edu.info.manager.domain.Teacher; import com.itheima.edu.info.manager.service.TeacherService; import java.util.Scanner; public class OtherTeacherController extends BaseTeacherController{ private Scanner sc = new Scanner(System.in); //录入老师信息,封装为老师对象类型 public Teacher inputTeacherInfo(String id){ //3.接受老师的其他信息 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(id,name,age,birthday); return t; } }
StudentController:
package com.itheima.edu.info.manager.controller; import com.itheima.edu.info.manager.domain.Student; import com.itheima.edu.info.manager.service.StudentService; import java.util.Scanner; 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(); //2.将学生信息封装为学生对象 Student stu=new Student(); stu.setId(id); stu.setName(name); stu.setAge(age); stu.setBirthday(birthday); return stu; } }
TeacherController:
package com.itheima.edu.info.manager.controller; import com.itheima.edu.info.manager.domain.Student; import com.itheima.edu.info.manager.domain.Teacher; import com.itheima.edu.info.manager.service.TeacherService; import java.util.Scanner; public class TeacherController extends BaseTeacherController{ private Scanner sc = new Scanner(System.in); //录入老师信息,封装为老师对象类型 public Teacher inputTeacherInfo(String id){ //3.接受老师的其他信息 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; } }
domain:
Person:
package com.itheima.edu.info.manager.domain; 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:
package com.itheima.edu.info.manager.domain; public class Student extends Person{ public Student() { } public Student(String id, String name, String age, String birthday) { super(id, name, age, birthday); } }
Teacher:
package com.itheima.edu.info.manager.domain; public class Teacher extends Person{ public Teacher() { } public Teacher(String id, String name, String age, String birthday) { super(id, name, age, birthday); } }
InfoManagerEntry
package com.itheima.edu.info.manager.entry; import com.itheima.edu.info.manager.controller.OtherStudentController; import com.itheima.edu.info.manager.controller.OtherTeacherController; import com.itheima.edu.info.manager.controller.StudentController; import com.itheima.edu.info.manager.controller.TeacherController; import java.util.Scanner; 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("学生管理"); //开启学生管理系统 OtherStudentController studentController=new OtherStudentController(); studentController.start(); break; case "2": //System.out.println("老师管理"); OtherTeacherController teacherController=new OtherTeacherController(); teacherController.start(); break; case "3": System.out.println("感谢您的使用"); //退出当前正在运行的JVM虚拟机 System.exit(0); break; default: System.out.println("您的输入有误,请重新输入"); break; } } } }
3.抽象类
抽象方法:将共性的行为(方法)抽取到父类之后,发现该方法的实现逻辑无法在父类中给出具体明确,该方法就可以定义为抽象方法
抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类
抽象方法的定义格式:
public abstract 返回值类型 方法名(参数列表)
抽象类的定义格式:
public abstract class 类名{
}
-
案例需求
定义猫类(Cat)和狗类(Dog)
猫类成员方法:eat(猫吃鱼)drink(喝水…)
狗类成员方法:eat(狗吃肉)drink(喝水…)
-
实现步骤
-
猫类和狗类中存在共性内容,应向上抽取出一个动物类(Animal)
-
父类Animal中,无法将 eat 方法具体实现描述清楚,所以定义为抽象方法
-
抽象方法需要存活在抽象类中,将Animal定义为抽象类
-
让 Cat 和 Dog 分别继承 Animal,重写eat方法
-
测试类中创建 Cat 和 Dog 对象,调用方法测试
-
-
代码实现
TestAnimal:
package com.itheima.test1; public class TestAnimal { /* 需求:定义猫类(Cat)和狗类(Dog) 猫类成员方法:eat(猫吃鱼)drink(喝水…) 狗类成员方法:eat(狗吃肉)drink(喝水…) 步骤: 1. 猫类和狗类中存在共性内容,应向上抽取出一个动物类(Animal) 2. 父类Animal中,无法将 eat 方法具体实现描述清楚,所以定义为抽象方法 3. 抽象方法需要存活在抽象类中,将Animal定义为抽象类 4. 让 Cat 和 Dog 分别继承 Animal,重写eat方法 5. 测试类中创建 Cat 和 Dog 对象,调用方法测试 */ public static void main(String[] args) { Dog d=new Dog(); d.eat(); d.drink(); Cat c=new Cat(); c.eat(); c.drink(); } }
Animal:
package com.itheima.test1; public abstract class Animal { public void drink(){ System.out.println("喝水"); } public abstract void eat(); }
Dog:
package com.itheima.test1; public class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃肉"); } }
Cat:
package com.itheima.test1; public class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼"); } }
抽象类的注意事项
1.抽象类不能创建对象
2.抽象类中有构造方法
3.抽象类的子类
A:必须要重写父类中所有的抽象方法
B:可以将自己也变成一个抽象类
4.抽象类中的方法
抽象类中可以没有抽象方法,但是由抽象方法的类一定是抽象类
-
设计模式
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。 使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。是一套良好的编码风格,并非是一个技术点。
-
把抽象类整体就可以看做成一个模板,模板中不能决定的东西定义成抽象方法 让使用模板的类(继承抽象类的类)去重写抽象方法实现需求
-
模板设计模式的优势
模板已经定义了通用结构,使用者只需要关心自己需要实现的功能即可
-
示例代码
CompositionTemplate类
package com.itheima.test2;
/*
* 作文模板类
* */
public abstract class CompositionTemplate {
public void write(){
System.out.println("<<我的爸爸>>");
body();
System.out.println("啊,这就是我的爸爸");
}
public abstract void body();
}
Test类
package com.itheima.test2; public class Test { public static void main(String[] args) { Tom t=new Tom(); t.write(); } }
Tom类
package com.itheima.test2; public class Tom extends CompositionTemplate{ @Override public void body() { System.out.println("那是一个秋天, 风儿那么缠绵,记忆中, " + "那天爸爸骑车接我放学回家,我的脚卡在了自行车链当中, 爸爸蹬不动,他就站起来蹬..."); } }
-
fianl关键字的作用
-
final代表最终的意思,可以修饰成员方法,成员变量,类
-
-
final修饰类、方法、变量的效果
-
fianl修饰类:该类不能被继承(不能有子类,但是可以有父类)
-
final修饰方法:该方法不能被重写
-
final修饰变量:表明该变量是一个常量,不能再次赋值
-
变量是基本类型,不能改变的是值
-
变量是引用类型,不能改变的是地址值,但地址里面的内容是可以改变的
-
-
package com.itheima.mfinal; public class TestFinal { /* final修饰变量: 基本数据类型变量: 其值不能被更改 引用数据类型变量: 地址值不能被更改, 但是可以修改对象的属性值 */ public static void main(String[] args) { //常量的命名规范.如果是一个单词,所有字母大写,如果是多个单词,所有字母大写,但是中间是用下划线进行分隔 final int A=10; //a=10; final int MAX=10; final int MAX_VALUE=20; final Student stu=new Student(); stu.setName("张三"); stu.setName("李四"); // stu=new Student(); } } /* class Fu{ } class Zi extends Fu{ }*/ class Student{ private String name; //final修饰成员变量,初始化时机 //1.在创建的时候,直接给值 //2.在构造方法结束之前,完成赋值 final int a=10; public String getName() { return name; } /* public Student(){ a=10; }*/ public void setName(String name) { this.name = name; } }
4.1代码块概述 (理解)
当程序启动完毕之后,程序就初始化一部分的学生数据
代码块:静态代码块
在Java中,使用 { } 括起来的代码被称为代码块
分类:
局部代码块
构造代码块
静态代码块
4.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关键字修饰,随着类的加载而加载,并且只执行一次
作用: 在类加载的时候做一些数据初始化的操作
示例代码
package com.itheima.block.mstatic; 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类的带参数构造方法>>>>"); } }
我是静态代码块,我执行了
我是Person类的空参数构造方法
我是Person类的带参数构造方法>>>>
-
需求:使用静态代码块,初始化一些学生数据
-
实现步骤
-
在StudentDao类中定义一个静态代码块,用来初始化一些学生数据
-
将初始化好的学生数据存储到学生数组中
-
-
示例代码
-
TeacherDao类
static{ Teacher teacher1=new Teacher("heima001","张三","23","1999-11-11"); Teacher teacher2=new Teacher("heima002","李四","24","2000-11-11"); teachers[0]=teacher1; teachers[1]=teacher2; }
StudentDao类
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; }
1.1黑马信息管理系统集合改进 (应用)
-
使用数组容器的弊端
-
容器长度是固定的,不能根据添加功能自动增长
-
没有提供用于赠删改查的方法
-
-
优化步骤
-
创建新的StudentDao类,OtherStudentDao
-
创建ArrayList集合容器对象
-
OtherStudentDao中的方法声明,需要跟StudentDao保持一致
注意:如果不一致,StudentService中的代码就需要进行修改
-
完善方法(添加、删除、修改、查看)
-
替换StudentService中的Dao对象
-
-
package com.itheima.edu.info.manager.dao; import com.itheima.edu.info.manager.domain.Student; import java.util.ArrayList; public class OtherStudentDao extends BaseStudentDao{ // 集合容器 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) { // 添加学生方法 思路:将对象存入到数组中null元素对应的索引位置 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); //2.将该索引位置,使用null元素进行覆盖 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(); // 其他方法没有变化,此处省略... }
-
优化步骤
-
将方法向上抽取,抽取出一个父类 ( 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 { // 其他内容不变,此处省略 }
1.3接口的概述(理解)
场景:一个类中,所有的方法都是抽象方法。 制定规则
-
当一个类中的所有方法都是抽象方法的时候,我们就可以将其定义为接口
- 接口也是也是一种引用数据类型,它比抽象类还要抽象
-
Java中接口存在的两个重要意义
-
规则的定义
-
程序的扩展性
-
1.4接口的定义和特点(记忆)
-
接口用关键字interface修饰
- public interface 接口名{}
- 接口不能实例化
- 接口和类之间是实现关系,通过implements关键字表示
- public class 类名 implements 接口名{}
- 接口的子类(实现类)
要么重写接口中的所有抽象方法
要么是抽象类
注意:接口和类的实现关系,可以单实现,也可以多实现
public class 类名 implements 接口名1,接口名2{}
Inter接口类
package com.itheima.test1; public interface Inter { public abstract void study(); }
InterA接口类
package com.itheima.test1; public interface InterA { public abstract void print1(); public abstract void print2(); public abstract void study(); }
InterImpl实现类
package com.itheima.test1; public class InterImpl implements Inter,InterA{ @Override public void study() { System.out.println("我是实现类中的study方法"); } @Override public void print1() { } @Override public void print2() { } }
Test1Interface测试类
package com.itheima.test1; public class Test1Interface { /* 接口的定义格式: public interface 接口名 {} 类实现接口的格式: public class 类名 implements 接口名 {} */ public static void main(String[] args) { //Inter i=new Inter() InterImpl ii=new InterImpl(); ii.study(); } }
-
成员特点
-
成员变量
只能是常量 默认修饰符: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); } }
JDK8版本后,Java只对接口的成员方法就行了改进
允许接口定义带有方法体的方法(非抽象方法),但是需要使用关键字default修饰,这些方法就是默认方法。作用:解决接口升级问题
接口中允许static静态方法
接口中默认方法的定义格式:
格式:public default 返回值类型 方法名(参数列表){ }
举例:public default void show(){ }
接口中默认方法的注意事项:
- 默认方法不是抽象方法,所以不强制被重写,但是可以被重写,重写的时候去掉default关键字
- public可以省略,default不能省略
- 如果实现了多个接口,多个接口中存在相同的方法声明,子类就必须队该方法进行重写
接口中静态方法的定义格式
格式:public static 返回值类型 方法名(参数列表){ }
范例:public static void show(){ }
接口中静态方法的注意事项:
静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
public可以省略,static不能省略
JDK9版本接口成员的特点
接口中私有方法的定义格式:
格式1:private 返回值类型 方法名(参数列表){ }
范例1:private void show(){ }
格式2:private static 返回值类型 方法名(参数列表){ }
范例2:private static void method(){ }
接口的使用思路
如果发现一个类中所有的方法都是抽象方法,那么就可以将该类,改进为一个接口
涉及到了接口大面积更新方法,而不想去修改每一个实现类,就可以将更新的方法,定义为带有方法体的默认方法
希望默认方法的调用更加简洁,可以考虑设计为static静态方法(需要去掉default关键字)静态方法只能通过接口名进行调用
默认方法中出现了重复的代码,可以考虑抽取出一个私有方法(需要去掉default关键字)
-
类与类的关系
继承关系,只能单继承,但是可以多层继承
-
类与接口的关系
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
-
接口与接口的关系
InterA
public interface InterA { public abstract void showA(); public default void method(){ System.out.println("InterA...method方法"); } }
InterB
public interface InterB { public abstract void showB(); public default void method(){ System.out.println("InterB...method方法"); } }
InterC
public interface InterC extends InterA,InterB{ @Override public default void method() { System.out.println("InterC接口,解决代码逻辑冲突问题, 重写method方法"); } }
InterImpl
public class InterImpl implements InterC{ @Override public void showA() { } @Override public void showB() { } }
TestInterface
public class TestInterface { public static void main(String[] args) { InterImpl ii=new InterImpl(); ii.method(); } }
1.7黑马信息管理系统使用接口改进 (应用)
-
实现步骤
-
将 BaseStudentDao 改进为一个接口
-
-
-
代码实现
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 { // 其他内容不变,此处省略 }
1.8黑马信息管理系统解耦合改进 (应用)
-
实现步骤
-
创建factory包,创建 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(); }
3.多态
3.1多态的概述(记忆)
-
什么是多态
同一个对象,在不同时刻表现出来的不同形态
- 举例:猫
- 我们可以说是猫:猫 cat=new 猫(); 我们也可以说猫是动物:动物animal=new 猫();这里猫在不同的时刻表现出来了不同的形态,这就是多态
-
多态的前提
-
要有继承或实现关系
-
要有方法的重写
-
要有父类引用指向子类对象
-
-
代码演示
package com.itheima.test1; public class Test1Polymorphic { /* 多态的前提 1.要有继承或实现关系 2.要有方法的重写 3.要有父类引用指向子类对象 */ public static void main(String[] args) { //当前事物,是一只动物 Animal a=new Cat(); a.eat(); //当前事物,是一只猫 Cat c=new Cat(); } } class Animal{ public void eat(){ System.out.println("动物吃饭"); } } class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼"); } }
3.2多态中的成员访问特点(记忆)
-
成员访问特点
- 构造方法:同继承一样,子类会通过super访问父类构造方法
- 成员变量:编译看左边(父类),执行看左边(父类)
- 成员方法:编译看左边(父类),执行看右边(子类)
-
代码演示
package com.itheima.test2; public class Test2Polymorpic { /* 多态的成员访问特点: 成员变量: 编译看左边 (父类), 运行看左边 (父类) 成员方法: 编译看左边 (父类), 运行看右边 (子类) */ public static void main(String[] args) { //多态的形式创建对象 Fu fu=new Zi(); System.out.println(fu.num); fu.method(); } } class Fu{ int num=10; public void method(){ System.out.println("Fu...method"); } } class Zi extends Fu{ @Override public void method() { int num=20; System.out.println("Zi...method"); } }
为什么成员变量和成员方法的访问不一样呢?
因为成员方法有重写,而成员变量没有
3.3多态的好处和弊端(记忆)
-
好处
提高程序的扩展性。定义方法时候,使用父类型作为参数,在使用的时候,该方法就可以接收这父类的任意子类对象
-
弊端
不能使用子类的特有功能
package com.itheima.test3; public class Test3Polymorpic { public static void main(String[] args) { useAnimal(new Dog()); useAnimal(new Cat()); } public static void useAnimal(Animal a){ //Animal a=new Dog(); a.eat(); //Animal a=new Cat(); //a.watchHome(); } } abstract class Animal{ public abstract void eat(); } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃肉"); } public void watchHome(){ System.out.println("看家"); } } class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼"); } }
3.4多态中的转型(应用)
-
向上转型
父类引用指向子类对象就是向上转型 从子到父
-
向下转型 从父到子 父亲引用转为子类对象
格式:子类型 对象名 = (子类型)父类引用;
-
代码演示
package com.itheima.test4; public class Test4Polymorpic { public static void main(String[] args) { //1.向上转型:父类引用指向子类对象 Fu f=new Zi(); f.show(); //多态的弊端,不能调用子类特有的成员 //f.method; //A:直接创建子类对象 //B:向下转型:从父类类型转换为子类类型 Zi z=(Zi)f;//强制转换 z.method(); } } 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"); } }
3.5多态中转型存在的风险和解决方案 (应用)
-
风险
如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException
-
解决方案
-
关键字
instanceof
-
使用格式
变量名 instanceof 类型
通俗的理解:判断关键字左边的变量,是否是右边的类型,返回boolean类型结果
-
-
代码演示
package com.itheima.test3; public class Test3Polymorpic { public static void main(String[] args) { useAnimal(new Dog()); useAnimal(new Cat()); } public static void useAnimal(Animal a){ //Animal a=new Dog(); a.eat(); //Animal a=new Cat(); //a.watchHome(); if(a instanceof Dog){ Dog dog=(Dog) a; dog.watchHome();//ClassCastException 类型转换异常 } // Dog dog=(Dog) a; // dog.watchHome();//ClassCastException 类型转换异常 } } abstract class Animal{ public abstract void eat(); } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃肉"); } public void watchHome(){ System.out.println("看家"); } } class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼"); } }
3.6黑马信息管理系统多态改进 (应用)
-
实现步骤
-
StudentDaoFactory类中方法的返回值定义成父类类型BaseStudentDao
-
StudentService中接收方法返回值的类型定义成父类类型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(); }
4.内部类
4.1 内部类的基本使用(理解)
-
内部类概念
-
在一个类中定义一个类。举例:在一个类A的内部定义一个类B,类B就被称为内部类
-
-
内部类定义格式
-
格式&举例:
/* 格式: class 外部类名{ 修饰符 class 内部类名{ } } */ class Outer { public class Inner { } }
-
内部类可以直接访问外部类的成员,包括私有
-
-
-
按照内部类在类中定义的位置不同,可以分为如下两种形式
在类的成员位置:成员内部类
在类的局部位置:局部内部类
成员内部类,外界如何创建对象使用呢?
格式:
外部类名.内部类名 对象名=new 外部类对象().new 内部类对象();
package com.itheima.test1; public class TestInner { public static void main(String[] args) { /* * 创建内部类对象的格式 * 外部类名.内部类名 对象名=new 外部类对象().new 内部类对象(); * */ Outher.Inner i=new Outher().new Inner(); System.out.println(i.num); i.show(); } } class Outher{ private int a=10; class Inner{ int num=10; public void show(){ System.out.println("Inner..show"); //内部类访问外部类成员,可以直接访问,包括私有 System.out.println(a); } } }
2.2 成员内部类(理解)
成员内部类,也属于(成员),既然是成员就可以被一些修饰符所修饰
private
私有成员内部类访问:在自己所在的外部类中创建对象访问。
static
静态成员内部类访问格式:外部类名.内部类名 对象名=new 外部类名.内部类名();
静态成员内部类中的静态方法:外部类名.内部类名.方法名();
私有的成员内部类:
package com.itheima.test2; public class Test2Innerclass { //私有的成员内部类 public static void main(String[] args) { //Outer.Inner oi=new Outer().new Inner(); Outer outer=new Outer(); outer.method(); } } class Outer{ private class Inner{ public void show(){ System.out.println("inner...show"); } } public void method(){ Inner i=new Inner(); i.show(); } }
静态的成员内部类
package com.itheima.test3; public class Test3Innerclass { //静态的成员内部类 public static void main(String[] args) { //外部类名.内部类名 对象名=new 外部类名.内部类名(); Outer.Inner oi=new Outer.Inner(); oi.show(); Outer.Inner.method(); } } class Outer{ static class Inner{ public void show(){ System.out.println("inner...show"); } public static void method(){ System.out.println("inner...method"); } } }
2.3 局部内部类(理解) 平时很少编写
-
局部内部类定义位置
-
局部内部类是在方法中定义的类
-
-
局部内部类方式方式
-
局部内部类,外界是无法直接使用,需要在方法内部创建对象并使用
-
该类可以直接访问外部类的成员,也可以访问方法内的局部变量
-
-
示例代码
package com.itheima.test4; public class Test4Innerclass { /* * 局部内部类 * 访问方式:之恩那个在方法中,创建对象并访问 * */ public static void main(String[] args) { Outer o= new Outer(); o.method(); } } class Outer{ int a=10; public void method(){ int b=20; class Inner{ public void show(){ System.out.println("show..."); System.out.println(a); System.out.println(b); } } Inner i=new Inner(); i.show(); } }
2.4 匿名内部类(应用)
概述:匿名内部类本质上是一个特殊的局部内部类(定义在方法内部)
-
匿名内部类的前提
-
存在一个类或者接口,这里的类可以是具体类也可以是抽象类
-
-
匿名内部类的格式
-
格式:new 类名 ( ) { 重写方法 } new 接口名 ( ) { 重写方法 }
- 理解:匿名内部类是将(继承/实现)(方法重写)(创建对象)三个步骤,放在了一步进行
- 本质:是一个继承了该类或者实现了该接口的子类匿名对象
- 匿名内部类的细节
-
举例:
-
package com.itheima.test5; public class Test5Innerclass { /* * 1.创建实现类,通过implements关键字去实现接口 * 2.重写方法 * 3.创建类对象 * 4.调用重写后的方法 * * 匿名内部类:需要存在类/接口 * 格式: * new 类名/接口名(){ * 重写方法 * } * */ public static void main(String[] args) { InterImpl ii=new InterImpl(); ii.show(); //匿名内部类的理解:将继承/实现,方法重写,创建对象,放在了一部进行. //实现了Inter 接口的,一个实现类对象 new Inter(){ @Override public void show() { System.out.println("我是匿名内部类中的show方法"); } }.show(); //接口中存在多个方法 Inter2 i=new Inter2(){ @Override public void show1() { System.out.println("show1"); } @Override public void show2() { System.out.println("show2"); } }; i.show1(); i.show2(); } } interface Inter{ void show(); } interface Inter2{ void show1(); void show2(); } class InterImpl implements Inter{ @Override public void show() { System.out.println("InterImpl 重写的show方法"); } }
2.4 匿名内部类在开发中的使用(应用)
-
匿名内部类在开发中的使用
-
当方法的形式参数是接口或者抽象类时,可以将匿名内部类作为实际参数进行传递
-
-
示例代码:
package com.itheima.test6; 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(); } } /* * 使用接口方法 * * */ /* * 游泳接口 * */ interface Swimming{ void swim(); }
5.Lambda表达式
5.1体验Lambda表达式【理解】
代码更少,关注点更明确了
1.方法要一个接口,我得给个实现类对象
2.创建匿名内部类对象,重写方法
3.方法要干嘛呢,打印一句话吧
面向对象思想:更多关注怎么做,谁来(哪个对象去做)
更多关注做什么,函数式编程思想
在数学中,函数就是有输入量,输出量的一套计算方案,也就是“拿数据做计算”
面向对象思想强调“必须通过对象的形式来做事情”
函数式思想则尽量忽略面向对象的复杂算法:“强调做什么,而不是以什么形式去做”
而我们要学习的Lambda表达式就是函数式编程思想的体现
5.2Lambda表达式的标准格式【理解】
-
格式:
(形式参数) -> {代码块}
-
形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
-
->:由英文中画线和大于符号组成,固定写法。代表指向动作
-
代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
-
-
组成Lambda表达式的三要素:
-
形式参数,箭头,代码块
-
Lambda表达式的使用前提
有一个接口
接口中有且仅有一个抽象方法
练习1:
编写一个接口(ShowHandler)
在该接口中存在一个抽象方法(show),该方法是无参数无返回值
在测试类(ShowHandlerDemo)中存在一个方法(useShowHandler),方法的参数是ShowHandler类型的,在方法的内部调用了ShowHandler的show方法
package com.itheima.test2; public class TestLambda { /* Lambda表达式的使用前提 1. 一个接口 2. 接口中有且仅有一个抽象方法 练习1: 1. 编写一个接口(ShowHandler) 2. 在该接口中存在一个抽象方法(show),该方法是无参数无返回值 3. 在测试类(ShowHandlerDemo)中存在一个方法(useShowHandler) 方法的的参数是ShowHandler类型的 在方法内部调用了ShowHandler的show方法 */ public static void main(String[] args) { useShowHandler(new ShowHandler() { @Override public void show() { System.out.println("我是匿名内部类当中的show方法"); } }); //Lambda实现 useShowHandler(()->{ System.out.println("我是Lambda当中的show方法"); }); } public static void useShowHandler(ShowHandler showHandler){ showHandler.show(); } } interface ShowHandler{ void show(); }
Lambda表达式的练习2
1.首先存在一个接口(StringHandler)
2.在该接口中存在一个抽象方法(PrintMessage),该方法是有参数无返回值
3.在测试类(StringHandlerDemo)中存在一个方法(useStringHandler),方法的参数是StringHandler类型的,在方法的内部调用了StringHandler的printMessage方法
package com.itheima.test3; public class StringHandlerDemo { /* 1.首先存在一个接口(StringHandler) 2.在该接口中存在一个抽象方法(printMessage),该方法是有参数无返回值 3.在测试类(StringHandlerDemo)中存在一个方法(useStringHandler) 方法的的参数是StringHandler类型的 在方法内部调用了StringHandler的printMessage方法 */ public static void main(String[] args) { useStringHandler(new StringHandler() { @Override public void printMessage(String msg) { System.out.println("我是匿名内部类"+msg); } }); useStringHandler((String msg)->{ System.out.println("我是Lambda表达式 "+msg); }); } public static void useStringHandler(StringHandler stringHandler){ stringHandler.printMessage("itheima"); } } interface StringHandler{ void printMessage(String msg); }
Lambda表达式练习3
1. 首先存在一个接口(RandomNumHandler)
2. 在该接口中存在一个抽象方法(getNumber),该方法是无参数但是有返回值
3. 在测试类(RandomNumHandlerDemo)中存在一个方法(useRandomNumHandler)
方法的的参数是RandomNumHandler类型的
在方法内部调用了RandomNumHandler的getNumber方法
package com.itheima.test4; import java.util.Random; public class RandomNumHandlerDemo { /* 1. 首先存在一个接口(RandomNumHandler) 2. 在该接口中存在一个抽象方法(getNumber),该方法是无参数但是有返回值 3. 在测试类(RandomNumHandlerDemo)中存在一个方法(useRandomNumHandler) 方法的的参数是RandomNumHandler类型的 在方法内部调用了RandomNumHandler的getNumber方法*/ public static void main(String[] args) { useRandomNumHandler(new RandomNumHandler() { @Override public int getNumber() { Random r=new Random(); int num=r.nextInt(10)+1; return num; } }); useRandomNumHandler(()->{ Random r=new Random(); int num=r.nextInt(10)+1; return num; //注意:如果Lambda所操作的接口中的方法,有返回值,一定要通过return语句,将结果返回,否则会出现编译错误 }); } public static void useRandomNumHandler(RandomNumHandler randomNumHandler){ int result=randomNumHandler.getNumber(); System.out.println(result); } } interface RandomNumHandler{ int getNumber(); }
Lambda表达式的练习4
1. 首先存在一个接口(Calculator)
2. 在该接口中存在一个抽象方法(calc),该方法是有参数也有返回值
3. 在测试类(CalculatorDemo)中存在一个方法(useCalculator)
方法的的参数是Calculator类型的
在方法内部调用了Calculator的calc方法
package com.itheima.test5; import com.sun.source.tree.BreakTree; public class CalculatorDemo { /* 1. 首先存在一个接口(Calculator) 2. 在该接口中存在一个抽象方法(calc),该方法是有参数也有返回值 3. 在测试类(CalculatorDemo)中存在一个方法(useCalculator) 方法的的参数是Calculator类型的 在方法内部调用了Calculator的calc方法 */ public static void main(String[] args) { useCalculator(new Calculator() { @Override public int calc(int a, int b) { return a+b; } }); useCalculator((int a,int b)->{ return a+b; }); } public static void useCalculator(Calculator calculator){ int result=calculator.calc(10,20); System.out.println(result); } } interface Calculator{ int calc(int a,int b); }
-
参数类型可以省略。但是有多个参数的情况下,不能只省略一个
-
如果参数有且仅有一个,那么小括号可以省略
-
package com.itheima.Test6; public class Test6 { public static void main(String[] args) { useInter((a,b) -> a + b ); } public static void useInter(Inter i) { double a = i.method(12.3, 22.3); System.out.println(a); } } interface Inter { //用于计算a+b的结果并返回 double method(double a, double b); }
5.8Lambda表达式和匿名内部类的区别【理解】
-
所需类型不同
-
匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
-
Lambda表达式:只能是接口
-
-
使用限制不同
-
如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类
-
如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
-
-
实现原理不同
-
匿名内部类:编译之后,产生一个单独的.class字节码文件
-
Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成
-