Java 接口与内部类
Java 接口与内部类
接口(Interface)
接口的概念与设计哲学
抽象类是从多个类中抽象出来的模板,如果将这种抽象进行的更彻底,则可以提炼出一种更加特殊的"抽象类"——接口(interface)。接口是从多个相似类中抽象出的规范,体现“规范与实现分离”的设计思想。它不关心类的内部状态和方法实现细节,仅规定类必须提供的公共方法,是类与外部交流的通道。接口里不能包含普通方法,接口里所有的方法都是抽象方法。java8对接口进行了改进,允许在接口中定义默认方法及静态方法,默认方法可以提供方法实现,静态方法让接口具备一定功能。
接口的核心价值在于松耦合:软件组件面向接口耦合时,无需关注实现细节,只需遵守规范即可协同工作。例如主板的PCI插槽,只要显卡符合PCI接口规范,无论品牌和内部实现如何,都能正常使用。
接口的定义与语法
接口是与类相似的结构,Java 8及以后的接口可包含:
- 常量(默认
public static final) - 抽象方法(默认
public abstract) - 默认方法(
default修饰,提供方法实现,java 8之前不允许) - 静态方法(
static修饰,通过接口名调用,java 8之前不允许)
定义格式:
public interface 接口名 {
// 常量(可省略public static final)
数据类型 常量名 = 常量值;
// 抽象方法(可省略public abstract)
返回值类型 方法名(参数列表);
// 默认方法
default 返回值类型 方法名(参数列表) {
方法实现;
}
// 静态方法
static 返回值类型 方法名(参数列表) {
方法实现;
}
}
接口的实现与使用
类通过implements关键字实现接口,必须实现接口中所有抽象方法(默认方法可选择性重写)。一个类可实现多个接口,弥补Java单继承的限制。以下图为例:

可食用接口(Edible)与相关类实现
可食用接口定义
package com.inherit.implement;
/**
* 可食用接口
* 在jdk1.8以前,接口中只能包含常量和抽象方法。
* 定义的方法默认就是public abstract
* @author Jing61
*/
public interface Ediable {
/**
* 所有可食用的都具有怎么吃共同的行为
* 接口中的所有方法自动地属于public。因此public可以省略
*/
String howToEat();
}
抽象动物类(Animal)
package com.inherit.implement;
/**
* 抽象类
* @author Jing61
*/
public abstract class Animal {
private double weight;
public abstract String sound();
}
具体实现类
- 老虎类(不可食用,仅继承Animal)
package com.inherit.implement;
public class Tiger extends Animal{
@Override
public String sound() {
return "两只老虎跑的快,跑得快";
}
}
- 鸡类(可食用,继承Animal并实现Edible)
package com.inherit.implement;
public class Chicken extends Animal implements Edible{
@Override
public String howToEat() {
return "可乐鸡翅";
}
@Override
public String sound() {
return "叽叽叽。。。。";
}
}
- 抽象水果类(可食用,实现Edible但不实现抽象方法,需为abstract)
package com.inherit.implement;
public abstract class Fruit implements Edible {
}
- 橙子类(继承Fruit,实现howToEat)
package com.inherit.implement;
public class Orange extends Fruit{
@Override
public String howToEat() {
return "榨汁->橙汁";
}
}
- 苹果类(继承Fruit,实现howToEat)
package com.inherit.implement;
public class Apple extends Fruit{
@Override
public String howToEat() {
return "apple 削皮";
}
}
测试类(EdibleTest)
package com.inherit.implement;
public class EdibleTest {
public static void main(String[] args) {
Object[] instances = {new Tiger(),new Chicken(),new Orange()};
for(Object obj : instances) {
if(obj instanceof Edible)
System.out.println(((Edible)obj).howToEat());
if(obj instanceof Animal)
System.out.println(((Animal)obj).sound());
}
}
}
示例2:电脑组件接口与组装实战
需求:电脑由主板、CPU、内存组成,通过接口抽象各组件规范,支持灵活替换配件。
如图:





核心接口定义
- 电脑组件接口(PCComponent):所有电脑组件的基础规范
package com.inherit.computer;
/**
* 电脑组件接口
* @author Jing61
*/
public interface PCComponent {
String getName(); // 获取组件名称
double getPrice(); // 获取组件价格
String getCompany(); // 获取组件厂家
}
- CPU接口(继承PCComponent)
package com.inherit.computer;
/**
* CPU接口
* @author Jing61
*/
public interface CPU extends PCComponent{
int getSpeed(); // 获取CPU速度
void doInstr(); // 做指令运算
void outResult(); // 输出结果
}
- 内存接口(继承PCComponent)
package com.inherit.computer;
/**
* 内存接口
* @author Jing61
*/
public interface Ram extends PCComponent{
int getSize(); // 获取内存大小
void inData(); // 读数据
void outData(); // 取数据
}
- 主板接口(继承PCComponent)
package com.inherit.computer;
/**
* 主板接口
* @author Jing61
*/
public interface Mainboard extends PCComponent{
void setCpu(CPU cpu);//安装cpu
CPU getCpu();//得到主板上的CPU
void setRam(Ram ram);//安装内存
Ram getRam();//得到主板上的内存
boolean havePower();//是否有电源
void startPower();//开电源
void shutdownPower();//关电源
}
组件实现类
-
主板实现(抽象主板类+具体实现类),在现实中,有很多种类型的主板,只要这些主板符合我们的标准,就能接到我们的电脑中来用。本例提供了AUSUBoard及IntelBoard两种类别的主板。
- 抽象主板类(AbstractMainboard)
package com.inherit.computer; /** * 主板抽象类 * @author Jing61 */ public abstract class AbstractMainboard implements Mainboard { private CPU cpu; private Ram ram; private boolean power; public void setCpu(CPU cpu) { this.cpu=cpu; } public CPU getCpu() { return cpu; } public void setRam(Ram ram) { this.ram=ram; } public Ram getRam() { return ram; } public boolean havePower() { return power; } public void startPower() { power=true; } public void shutdownPower() { power=false; } }- Intel主板类(IntelBoard)
package com.inherit.computer; /** * Intel主板 * @author Jing61 */ public class IntelBoard extends AbstractMainboard { public String getName() { return "Intel主板"; } public double getPrice() { return 3500.00; } public String getCompany() { return "Intel公司"; } }- AUSU主板类(AUSUBoard)
package com.inherit.computer; /** * AUSU主板 * @author Jing61 */ public class AUSUBoard extends AbstractMainboard { public String getName() { return "AUSU主板"; } public double getPrice() { return 3000.00; } public String getCompany() { return "SUSU公司"; } } -
CPU实现类,在现实中,有很多种类型的CPU可供使用,只要这些CPU符合我们的标准,就能接到我们的电脑中来用。本例提供了AMDCpu及IntelCPU两种类别的主板。
- AMD CPU
package com.inherit.computer; /** * AMD CPU * @author Jing61 */ public class AMDCpu implements CPU { public int getSpeed() { return 1500; } public void doInstr() { System.out.println("做指令运算"); } public void outResult() { } public String getName() { return "AMD CPU"; } public double getPrice() { return 1800; } public String getCompany() { return "AMD公司"; } }- Intel CPU
package com.inherit.computer; /** * Intel CPU * @author Jing61 */ public class IntelCPU implements CPU { public int getSpeed() { return 1700; } public void doInstr() { System.out.println("做指令运算"); } public void outResult() { } public String getName() { return "IntelCPU"; } public double getPrice() { return 2500; } public String getCompany() { return "Intel公司"; } } -
内存实现类,本例我们也只提供两款可供选择的内存。分别是Kingmax的内存,以及Kingstone的内存。
- Kingmax内存
package com.inherit.computer; /** * Kingmax内存 * @author Jing61 */ public class KingmaxRam implements Ram { public int getSize() { return 512; } public void inData() { //读入数据 } public void outData() { //输出数据 } public String getName() { return "Kingmax内存"; } public double getPrice() { return 300; } public String getCompany() { return "Kingmax公司"; } }- Kingstone内存
package com.inherit.computer; /** * Kingmax内存 * @author Jing61 */ public class KingstoneRam implements Ram { public int getSize() { return 512; } public void inData() { //读入数据 } public void outData() { //输出数据 } public String getName() { return "Kingstone内存"; } public double getPrice() { return 200; } public String getCompany() { return "Kingstone公司"; } }
电脑类(Computer)设计
每台Computer需要一个主板,每个主板上需要插上CPU及内存条,电脑才能正常工作。
package com.inherit.computer;
/**
* 电脑类
* @author Jing61
*/
public class Computer {
private Mainboard mainboard;
public void setMainboard(Mainboard mainboard) {
this.mainboard = mainboard;
}
public void doWork() {
System.out.println("开始工作");
for (int i = 0; i < 10; i++) {
System.out.println("第" + i + "次工作");
}
System.out.println("工作结束");
}
public void start() {
mainboard.startPower();
}
public void shutdown() {
mainboard.shutdownPower();
}
public double getPrice() {
return mainboard.getPrice() + mainboard.getCpu().getPrice() + mainboard.getRam().getPrice();
}
public String getSetting() {
String ret = "电脑组成如下!主板:" + mainboard.getName() + ",CPU:" + mainboard.getCpu().getName() + ",内存:" + mainboard.getRam().getName() + "\n";
ret += "这个配置的价格为:"+getPrice();
return ret;
}
}
传统组装电脑方法(ClientOldDemo)
传统的情况下,要组装一台电脑,需要在代码中分别new出每一个电脑组件的实例,再把他们组装到电脑上面,再运行程序。
package com.inherit.computer;
/**
* @author Jing61
*/
public class ClientOldDemo {
public static void main(String[] args) {
CPU cpu = new IntelCPU();
Ram ram = new KingmaxRam();
Mainboard myMainboard = new IntelBoard();
myMainboard.setCpu(cpu);
myMainboard.setRam(ram);
Computer computer = new Computer();
computer.setMainboard(myMainboard);
//执行computer的doWork方法,使得commputer开始工作
computer.doWork();
//输出电脑的配置信息
System.out.println(computer.getSetting());
}
}
常用系统接口
Comparable接口
用于定义对象的比较规则,实现该接口的类可通过Arrays.sort()排序。需实现compareTo()方法,定义比较逻辑。
示例:Circle类实现Comparable接口(按半径比较)
package com.inherit.implement;
public class Circle implements Comparable<Circle> {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double getArea() {
return Math.PI * radius * radius;
}
@Override
public String toString() {
return "Circle [radius=" + radius + ",area: " + getArea() + "]";
}
/**
* 比较规则:如果当前对象比circle小,返回小于0的整数,如果相等,返回0,如果大于circle,返回一个大于0的整数
*/
@Override
public int compareTo(Circle circle) {
if(this.radius == circle.radius) return 0;
return this.radius < circle.radius ? -1 : 1;
}
}
Cloneable接口
用于实现对象克隆,当拷贝一个变量时,原始变量和拷贝变量引用同一个对象,也就是说,改变一个变量所引用的对象将会对另一个变量产生影响;如果创建一个对象的新copy,它的初始状态和原始对象一样,但以后将可以各自改变各自的状态,那就需要使用clone方法:
Circle copy = circle.clone();
copy.getArea();
不过,事情并没有这么简单。clone()方法是Object类的protected方法,也就是说,在用户编写的代码中不能直接调用它。

由于这个类对具体的类对象一无所知,所以只能将各个域进行对应的拷贝。如果对象中的所有数据域都属于数值或基本类型,这样拷贝域没有任何问题。但是,如果在对象中包含了子对象的引用,拷贝的结果会使得两个域引用同一个子对象,因此原始对象与克隆对象共享这部分信息。
默认的克隆操作是浅拷贝,它并没有克隆包含在对象中的内部对象。如果进行浅拷贝会发生什么呢?这要根据具体情况而定。如果原始对象与浅克隆对象共享的子对象是不可变的,将不会产生任何问题。也确实存在这种情形。例如,子对象属于像String类这样的不允许改变的类,也有可能子对象在其生命周期内不会发生变化,既没有更改它们的方法,也没有创建对它引用的方法。然而,更常见的情况是子对象可变,因此必须重新定义clone方法,以便实现克隆子对象的深拷贝。
需满足以下条件才能使用:
- 类实现Cloneable接口(标记接口,无抽象方法);
- 重写
clone()方法并改为public访问权限。
克隆分为:
- 浅拷贝:仅拷贝对象本身,子对象引用不变(默认克隆行为);
- 深拷贝:拷贝对象及所有子对象,需重写
clone()方法实现。
使用格式:
Circle copy = (Circle)circle.clone();
接口与抽象类
| 接口 | 抽象类 |
|---|---|
| 不考虑java8中default方法的情况下,接口中是没有实现代码的实现 | 抽象类中可以有普通成员方法 ,并且可以定义变量 |
| 接口中的方法修饰符号 只能是public | 抽象类中的抽象方法可以有public,protected,default |
| 接口中没有构造方法 | 可以有构造方法 |
选择:
1、当我们需要一组规范的方法的时候,我们就可以用接口,在具体的业务中,来对接口进行实现,能达到以不变应对万变,多变的需求的情况我们只需要改变对应的实现类 。
2、如果多个实现类中有者相同可以复用的代码 这个时候就可以在实现类和接口之间,添加一个抽象类,把公共的代码抽出在抽象类中。然后要求不同实现过程的子类可以重写抽象类中的方法,来完成各自的业务。
Java 8接口改进
Java 8对接口的升级解决了接口扩展的兼容性问题:
- 默认方法(
default):提供方法实现,实现类可选择性重写,避免接口新增方法导致所有实现类编译报错; - 静态方法(
static):接口可直接调用,无需实现类,增强接口功能。
示例:带默认方法和静态方法的接口
public interface MyInterface {
// 抽象方法
void abstractMethod();
// 默认方法
default void defaultMethod() {
System.out.println("默认方法实现");
}
// 静态方法
static void staticMethod() {
System.out.println("静态方法实现");
}
}
接口与回调(Callback)
回调是一种程序设计模式,指特定事件发生时执行预设动作。接口常作为回调的载体,要求事件触发者调用接口定义的方法。
示例:定时器回调(每1秒打印时间并发出提示音)
package com.inherit.implement;
import javax.swing.JOptionPane;
import javax.swing.Timer;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.LocalDateTime;
/**
* @author Jing61
*/
public class BeepDemo {
public static void main(String[] args) {
/**
* 创建一个定时器
* 每1000毫秒触发定时器,定时器就会调用该事件里的回调方法
*/
Timer timer = new Timer(1000, new BeepActionListner());
//启动定时器
timer.start();
// 系统提示框
JOptionPane.showMessageDialog(null, "退出定时器");
// 退出程序
System.exit(0);
}
}
class BeepActionListner implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("At the tone,the time is " + LocalDateTime.now());
Toolkit.getDefaultToolkit().beep();
}
}
内部类(Inner Class)
内部类的概念与优势
内部类是在一个类内部定义的类,核心优势:
- 可直接访问外部类的所有成员(包括私有属性和方法);
- 对外部包隐藏,提高代码封装性;
- 匿名内部类简化回调和事件驱动程序编写;
- 丰富类的设计层次,解决复杂场景下的逻辑组织问题。
内部类的分类与语法
成员内部类
定义在类内部、方法外部,作为外部类的成员。
特点
- 可使用
public、protected、private、默认权限修饰; - 可被
abstract、final修饰,有构造器,可定义属性和方法; - 分为非静态和静态成员内部类。
非静态成员内部类
- 创建对象:需先创建外部类对象,通过
外部类对象.new 内部类()创建; - 访问规则:
- 直接访问外部类非同名属性/方法;
- 访问外部类同名属性:
外部类名.this.属性名; - 访问自身属性:
this.属性名。
示例:
package com.inherit.implement;
/**
* @author Jing61
*/
public class Outer {
private int value = 100;
private String name = "Outer";
public void show() {
System.out.println("Outer class value: " + value + " name: " + name);
}
public class Inner {
private String name = "Inner";
public void show() {
// 内部类可以直接访问外部类的成员数据
System.out.println("Inner class value: " + value + " name: " + name);
System.out.println("Inner class value: " + value + " Outer name: " + Outer.this.name);
}
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.show();
Outer.Inner inner = outer.new Inner();
inner.show();
}
}
静态成员内部类
- 定义:用
static修饰的成员内部类; - 创建对象:
外部类名.内部类名 对象名 = new 外部类名.内部类名(); - 访问规则:仅能访问外部类的静态属性和方法,不能访问非静态成员。
示例:数组工具类(静态内部类存储最值)
package com.inherit.implement;
/**
* 只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外围对象,可以把内部类声明为static的,以便取消产生的引用
* 查找数字中的最大值和最小值
* @author Jing61
*/
public class ArrayAlg {
public static Pair getMinAndMax(int[] list) {
int min = list[0], max = list[0];
for(int i = 1; i < list.length; i++) {
if(min > list[i]) min = list[i];
if(max < list[i])max = list[i];
}
return new Pair(min, max);
}
public static class Pair{
private int min;
private int max;
public Pair(int min,int max) {
this.min = min;
this.max = max;
}
public int getMin() {
return min;
}
public int getMax() {
return max;
}
}
public static void main(String[] args) {
int[] list = {11, 2, 32, 4, 53, 61, 7, 82, 91, 10};
Pair pair = ArrayAlg.getMinAndMax(list);
System.out.println("min: " + pair.getMin() + " max: " + pair.getMax());
}
}
局部内部类
定义在方法或代码块内部,仅在当前方法内有效。
优势
方便获取接口实现类对象,无需单独定义外部类。
示例:定时器局部内部类实现
package com.inherit.implement;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.LocalDateTime;
import javax.swing.Timer;
/**
* 局部内部类
* 发现:前面的TimerPrintActionListener类只是在Talking类的start()方法内部使用,可以使用局部内部类
* @author Jing61
*/
public class LocalInnerClassTalking {
private boolean beep;
private int interval = 1000;
public LocalInnerClassTalking(boolean beep, int interval) {
this.beep = beep;
this.interval = interval;
}
public void start() {
class TimerPrintActionListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("注意,当前时间:" + LocalDateTime.now());
//内部类可以直接访问外部类的数据
if(beep) Toolkit.getDefaultToolkit().beep();
}
}
TimerPrintActionListener listener = new TimerPrintActionListener();
Timer timer = new Timer(interval, listener);
timer.start();
}
}
匿名内部类
没有类名的局部内部类,通过new 接口/抽象类(){} 隐含实现接口或抽象类,实现逻辑写在大括号内。
适用场景
仅需使用一次的接口/抽象类实现,简化代码。
示例:匿名内部类实现定时器
package com.inherit.implement;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.LocalDateTime;
import javax.swing.Timer;
/**
* @author Jing61
*/
public class AnonymousInnerClassTalking {
private int interval;
private boolean beep;
public AnonymousInnerClassTalking(int interval, boolean beep) {
this.interval = interval;
this.beep = beep;
}
public void start() {
//匿名内部类:new的是实现了ActionListener接口类的实例,该类没有名字
Timer timer = new Timer(interval, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("注意,当前时间:" + LocalDateTime.now());
//内部类可以直接访问外部类的数据
if(beep) Toolkit.getDefaultToolkit().beep();
}
});
timer.start();
}
}
内部类的特殊语法规则
- 外部类引用:内部类中通过
OuterClass.this获取外部类当前对象; - 内部类对象创建:非静态内部类需通过外部类对象创建,静态内部类直接通过外部类名创建;
- 访问权限:内部类可访问外部类成员,外部类需通过内部类对象访问内部类成员。
函数式接口(Functional Interface)
函数式接口的定义
有且仅有一个抽象方法的接口,可使用@FunctionalInterface注解校验(编译时检查是否符合规范)。函数式接口是Lambda表达式的载体。
Lambda表达式
语法格式
(参数列表) -> { 方法体 }
简化规则
- 若参数列表仅有一个参数,括号可省略;
- 若方法体仅有一条语句,大括号和
return可省略; - 参数类型可省略(编译器自动推断)。
方法引用
当Lambda表达式仅调用一个已存在的方法时,可通过方法引用简化,格式:类名/对象::方法名。
分类
- 静态方法引用:
类名::静态方法名; - 对象方法引用:
对象::实例方法名; - 任意对象的实例方法引用:
类名::实例方法名; - 构造方法引用:
类名::new。
常见函数式接口
| 接口名 | 核心方法 | 功能描述 |
|---|---|---|
Function<T, R> |
R apply(T t) |
接收T类型参数,返回R类型结果 |
BiFunction<T, U, R> |
R apply(T t, U u) |
接收T、U类型参数,返回R类型结果 |
Consumer<T> |
void accept(T t) |
接收T类型参数,无返回值 |
BiConsumer<T, U> |
void accept(T t, U u) |
接收T、U类型参数,无返回值 |
Supplier<T> |
T get() |
无参数,返回T类型结果 |
Predicate<T> |
boolean test(T t) |
接收T类型参数,返回布尔值 |
实战示例
以下示例结合常见函数式接口,实现“学生数据处理”场景,涵盖Lambda简化、方法引用用法:
package com.inherit.implement;
import java.util.Arrays;
import java.util.function.*;
/**
* @author Jing61
*/
// 学生实体类(用于数据处理)
class Student {
private String name;
private int score;
// 构造方法
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public Student() {
}
// getter/setter
public String getName() { return name; }
public int getScore() { return score; }
public void setScore(int score) { this.score = score; }
// 静态方法:分数翻倍(用于静态方法引用)
public static int doubleScore(int score) {
return score * 2;
}
// 实例方法:打印学生信息(用于对象方法引用)
public void printInfo() {
System.out.println("姓名:" + name + ",分数:" + score);
}
@Override
public String toString() {
return name + "(" + score + ")";
}
}
// 测试类
public class FunctionalInterfaceDemo {
public static void main(String[] args) {
// 初始化学生数组
Student[] students = {
new Student("张三", 85),
new Student("李四", 60),
new Student("王五", 92),
new Student("赵六", 78)
};
// 一、Function<T, R>:接收T类型,返回R类型(分数处理)
System.out.println("=== 1. Function:分数翻倍 ===");
// Lambda表达式:接收Student,返回翻倍后的分数
Function<Student, Integer> scoreDoubler = s -> Student.doubleScore(s.getScore());
for (Student s : students) {
int newScore = scoreDoubler.apply(s);
System.out.println(s.getName() + "原分数:" + s.getScore() + ",翻倍后:" + newScore);
}
// 简化:方法引用(静态方法引用)
Function<Student, Integer> scoreDoublerRef = s -> Student.doubleScore(s.getScore());
System.out.println("方法引用实现:" + scoreDoublerRef.apply(students[0]));
// 二、Predicate<T>:接收T类型,返回布尔值(条件筛选)
System.out.println("\n=== 2. Predicate:筛选及格学生(≥60分) ===");
// Lambda表达式:判断分数是否及格
Predicate<Student> isPass = s -> s.getScore() >= 60;
for (Student s : students) {
if (isPass.test(s)) {
System.out.println(s.getName() + ":及格");
} else {
System.out.println(s.getName() + ":不及格");
}
}
// 三、Consumer<T>:接收T类型,无返回值(数据消费)
System.out.println("\n=== 3. Consumer:打印所有学生信息 ===");
// Lambda表达式:打印学生信息
Consumer<Student> printStudent = s -> s.printInfo();
Arrays.stream(students).forEach(printStudent);
// 简化:方法引用(对象方法引用)
Consumer<Student> printStudentRef = Student::printInfo;
System.out.println("方法引用实现:");
Arrays.stream(students).forEach(printStudentRef);
// 四、BiFunction<T, U, R>:接收两个参数,返回R类型(修改分数)
System.out.println("\n=== 4. BiFunction:给学生加分 ===");
// Lambda表达式:接收Student和加分值,返回加分后的学生
BiFunction<Student, Integer, Student> addScore = (s, num) -> {
s.setScore(s.getScore() + num);
return s;
};
Student updatedStudent = addScore.apply(students[1], 10);
System.out.println(updatedStudent.getName() + "加分后:" + updatedStudent.getScore());
// 五、Supplier<T>:无参数,返回T类型(创建对象)
System.out.println("\n=== 5. Supplier:创建新学生 ===");
// Lambda表达式:无参数,返回新的Student对象
Supplier<Student> studentCreator = () -> new Student("孙七", 88);
Student newStudent = studentCreator.get();
newStudent.printInfo();
// 简化:方法引用(构造方法引用)
Supplier<Student> studentCreatorRef = Student::new; // 对应无参构造(需补全无参构造)
// 若用带参构造,需用BiFunction(因为两个参数)
BiFunction<String, Integer, Student> studentCreatorWithParams = Student::new;
Student newStudent2 = studentCreatorWithParams.apply("周八", 95);
newStudent2.printInfo();
// 六、BiConsumer<T, U>:接收两个参数,无返回值(批量修改+打印)
System.out.println("\n=== 6. BiConsumer:批量加分并打印 ===");
BiConsumer<Student, Integer> addAndPrint = (s, num) -> {
s.setScore(s.getScore() + num);
s.printInfo();
};
addAndPrint.accept(students[2], 5);
}
}
关键用法说明
-
Lambda简化对比:
- 完整Lambda:
(s, num) -> { s.setScore(s.getScore() + num); return s; } - 简化后(单语句):
s -> Student.doubleScore(s.getScore())(省略大括号和return)
- 完整Lambda:
-
方法引用场景:
- 静态方法引用:
Student::doubleScore(对应Student.doubleScore(score)) - 对象方法引用:
Student::printInfo(对应student.printInfo()) - 构造方法引用:
Student::new(对应new Student()或new Student(name, score))
- 静态方法引用:
-
运行结果:
会依次输出分数翻倍、及格筛选、学生信息打印、加分修改、对象创建等结果,直观体现各函数式接口的核心作用。
类设计原则(SOLID)
- 单一职责原则(SRP):一个类仅负责一个功能,仅有一个引起变化的原因;
- 开放封闭原则(OCP):一个软件实体如类、模块和函数应该对外外扩展开放,对修改关闭;
- 里氏替换原则(LSP):子类必须能够替换掉父类,且不会改变程序的正确性;
- 接口隔离原则(ISP):客户端不应依赖不需要的接口,接口应细化;
- 依赖倒置原则(DIP):抽象不依赖细节,细节依赖抽象;高层模块与低层模块均依赖抽象。

浙公网安备 33010602011771号