2 今日内容
1、内部类(重点)
2、lambda表达式(重点)
3 内部类
3.1 内部类入门
概述
概述:就是把一个类定义到了另外一个类的内部,那么这个类就被称之为内部类。比如: 把A定义到了B中,那么A就是内部类,B被称之为外部类
示例代码:
public class B { // 外部类
class A { // 内部类
}
}
编译完毕以后的字节码文件:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VWuyvy9a-1619333391481)(images/image-20210421095139804.png)]
访问特点
- 内部类和外部类之间:内部类可以直接去使用外部类的成员,包含私有的。但是外部类要想访问内部类的成员就需要创建对象。
- 其他的类访问内部类:创建内部类的对象
创建格式:
外部类名.内部类名 对象名 = new 外部类名().new 内部类名();
内部类的分类
按照定义位置的不同可以分为两种:
1、局部内部类:就是把这个内部类定义在外部类的局部位置(方法中)
2、成员内部类:就是把这个内部类定义在外部类的成员位置(类中访问外)
3.2 成员内部类
常见的修饰符:
1、private:其他类无法进行访问
2、static:其他类是可以进行访问的,但是创建的对象格式和之前不同
示例代码:
public class Outer { // 外部类
static class Inner { // 被static修饰的内部类
}
}
// 其他类
public class OuterDemo {
public static void main(String[] args) {
// 创建Inner的对象
Outer.Inner oi = new Outer.Inner() ;
}
}
创建对象的格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
3.3 局部内部类
概述:就是把一个类定义在了另外一个类的方法中
特点:只能在这个方法中去使用这个内部类
示例代码:
public class Outer {
public void show() {
// 局部内部类
class Inner {
public void method() {
System.out.println("Inner....method......") ;
}
}
// 创建Inner对象
Inner i = new Inner();
i.method();
}
}
3.4 面试题
public class Outer {
int number = 45 ;
class Inner {
int number = 10 ;
public void show(){
int number = 23 ;
System.out.println(number); // 在这里输出23
System.out.println(this.number); // 这里输出10
// System.out.println(new Outer().number); // 这里输出45
System.out.println(Outer.this.number);
}
}
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner() ;
oi.show();
}
}
3.5 匿名内部类(重点)
概述:是一种特殊的内部类
前提: 存在一个类或者接口
格式:
new 类名/接口名() {
重写方法
};
本质:是继承某一个类或者实现了某一个接口的子类对象
示例代码:
public interface Inter {
public abstract void show();
}
// 实现了Inter接口的子类对象
new Inter(){
public void show() {
System.out.println("Inter...show.....");
}
};
// 使用匿名内部类调用方法
new Inter(){
public void show() {
System.out.println("Inter...show.....");
}
}.show();
// 把匿名内部类赋值给一个Inter类型的变量
Inter inter = new Inter(){
public void show() {
System.out.println("Inter...show.....");
}
};
inter.show();
使用场景:就是把匿名内部类作为方法参数传递
示例代码:
public class InterDemo01 {
/*
new 类名/接口名() {
重写方法
};
*/
public static void main(String[] args) {
// 传递一个Inter的实现类对象
method(new InterImpl());
System.out.println("---------------------------------------");
// 传递一个Inter的匿名内部类
method(new Inter(){
@Override
public void show() {
System.out.println("匿名内部类作为方法参数传递");
}
});
}
// method方法需要一个Inter类型的参数
public static void method(Inter inter) {
inter.show();
}
}
4 lambda表达式
4.1 函数式编程思想
为什么要存在lambda表达式?
使用匿名内部类作为方法参数传递的时候,代码看起来还是相对比较繁琐的!为了简化我们开发,JDK1.8以后就提供了一种匿名内部类的简化格式就是lambda表达式。
匿名内部类和lambda表达式到底有什么样的区别?
1、语法不同
2、编程思想不同
- 匿名内部类使用的思想: 面向对象思想
- lambda表达式的编程思想:函数式编程思想
3、前提不同
- 匿名内部类:前提是存在一个接口或者类(可以是抽象类也可以非抽象类),并且接口中可以存在多个抽象方法
- lambda表达式:必须存在一个接口,并且这个接口中除了Object类中的方法的抽象表示形式以外,有且仅有一个抽象方法。
4、原理不同
- 匿名内部类: 编译完毕以后可以生成一个.class文件
- lambda表达式: 编译完毕以后不存在对应的.class文件
面向对象思想:关注点是谁来做某一件事情,做某一件事情之前,首先需要找到做这件事情的人(对象)。
函数式编程思想:关注点是做什么,关注的是结果,直接谁来做这件事情无所谓。
初体验
public class InterDemo01 {
public static void main(String[] args) {
// 传递一个Inter的匿名内部类
method(new Inter(){
@Override
public void show() {
System.out.println("匿名内部类作为方法参数传递");
}
});
System.out.println("---------------------------------------");
// 通过lambda表达式进行调用
method( () -> { System.out.println("匿名内部类作为方法参数传递"); });
}
// method方法需要一个Inter类型的参数
public static void method(Inter inter) {
inter.show();
}
}
4.2 语法规则
Lambda表达式是Jdk1.8提出了一种新的表达式语法。Lambda表达式的格式如下所示:
(参数类型 参数名称) -> { 方法体代码 }
格式由3个部分组成:
组成部分 | 说明信息 |
---|---|
(参数类型 参数名称) | 小括号内的语法与接口中所定义的方法参数列表一致:如果接口方法无参数则留空;多个参数则用","分隔 |
-> | 是新引入的语法格式,代表指向动作 |
{ } | 大括号内的语法与传统方法体要求基本一致 |
前提:必须存在一个接口,并且这个接口中除了Object类中的方法的抽象表示形式以外,有且仅有一个抽象方法。这样的接口,我们常常将其称之为函数式接口。
代码演示:
public interface Inter { // 接口
public abstract void show(); // 自定义的抽象方法
public abstract boolean equals(Object obj) ; // Object类中equals方法的抽象表示形式
}
public class InterDemo01 {
public static void main(String[] args) {
show(() -> { System.out.println("haha....."); }); // 调用show方法传递了一个lambda表达式
}
public static void show(Inter inter) {
inter.show();
}
}
4.3 练习题
lambda表达式是站在函数式编程的角度而言,关注的就是做什么。做什么的实现是通过方法进行实现,也就说关注点就是方法。
方法的分类:
1、无参数无返回值
2、无参数有返回值
案例说明:
-
首先存在一个接口(RandomNumHandler)
-
在该接口中存在一个抽象方法(getNumber),该方法是无参数但是有返回值
-
在测试类(RandomNumHandlerDemo)中存在一个方法(useRandomNumHandler),方法的的参数是RandomNumHandler类型的,
在方法内部调用了RandomNumHandler的getNumber方法
代码演示:
// 接口
public interface RandomNumHandler {
// 无参数但是有返回值的方法
public abstract int getNumber() ;
}
// 测试类
public class RandomNumHandlerDemo {
public static void main(String[] args) {
// 调用useRandomNumHandler方法获取一个int类的随机数[0-100]
// 匿名内部类
useRandomNumHandler(new RandomNumHandler() {
@Override
public int getNumber() {
// 随机数(0-100)
Random random = new Random();
int nextInt = random.nextInt(101);
return nextInt;
}
});
System.out.println("-------------------------------------------");
// lambda表达式
useRandomNumHandler(() -> {
// 随机数(0-100)
Random random = new Random();
int nextInt = random.nextInt(101);
return nextInt;
});
}
// 使用RandomNumHandler
public static void useRandomNumHandler(RandomNumHandler randomNumHandler) {
int number = randomNumHandler.getNumber(); // 调用RandomNumHandler中的getNumber方法
System.out.println(number); // 把结果输入到控制台
}
}
3、有参数无返回值
代码演示:
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);
}
});
// Lambda实现
useStringHandler((String msg) -> { System.out.println("我是匿名内部类" + msg);});
}
// 使用接口的方式
public static void useStringHandler(StringHandler stringHandler){
stringHandler.printMessage("itheima");
}
}
// 接口
interface StringHandler {
void printMessage(String msg);
}
4、有参数有返回值
案例说明:
- 首先存在一个接口(Calculator)
- 在该接口中存在一个抽象方法(calc),该方法是有参数也有返回值
- 在测试类(CalculatorDemo)中存在一个方法(useCalculator),方法的的参数是Calculator类型的,在方法内部调用了Calculator的calc方法
代码演示:
// 接口定义
public interface Calculator {
// 有参数有返回值的方法
public abstract int calc(int a , int b) ;
}
// 测试类
public class CalculatorDemo {
public static void main(String[] args) {
// 在main方法中去调用useCalculator这个方法
// 1、匿名内部类的方式
useCalculator(new Calculator() {
@Override
public int calc(int a, int b) { // 做加法运算
return a + b ;
}
}) ;
System.out.println("--------------------------------------------");
// 2、lambda表达式的方式
useCalculator((int a , int b) -> {
return a + b ;
});
}
public static void useCalculator(Calculator calculator) {
int result = calculator.calc(1, 1);
System.out.println(result);
}
}
4.4 省略的语法规则
Lambda表达式在使用的时候,也存在省略格式。它的省略规则如下所示:
- 参数类型可以省略,但是有多个参数的情况下,不能只省略一个
- 如果参数有且仅有一个,那么小括号可以省略
- 如果代码块的语句只有一条,可以省略大括号和分号,甚至是return