一、内部类
1.什么是内部类?
在一个类中定义一个类。
举例:在一个类A的内部定义一个类B,类B就被称为内部类
/*
格式:
class 外部类名{
修饰符 class 内部类名{
}
}
*/
class Outer {
public class Inner {
}
}
2.内部类
2.1 成员内部类
在类的成员位置就是成员内部类。
class Outer {
private int a = 10;
class Inner {
int num = 10;
public void show(){
System.out.println("Inner..show");
// 内部类, 访问外部类成员, 可以直接访问, 包括私有
System.out.println(a);
}
}
}
成员内部类创建对象的方法:
格式:外部类名.内部类名 对象名=new 外部对象().new 内部对象()
范例: Outer.Inner oi=new Outer().new Inter();
2.2 局部内部类
在方法中定义的类,外界是无法直接使用,需要在方法内部创建对象并使用;可以直接访问外部类的成员,也可以访问方法内的局部变量。
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.3 静态内部类
就是在成员内部类的前面加了一个static关键字。静态内部类属于外部类自己持有。
public class Outer {
private int age = 99;
public static String schoolName="清华";
// 静态内部类
public static class Inner{
//静态内部类访问外部类的静态变量,是可以的;
//静态内部类访问外部类的实例变量,是不行的
public void test(){
System.out.println(schoolName); //99
//System.out.println(age); //报错
}
}
}
静态内部类创建对象时,需要使用外部类的类名调用。
//格式:外部类.内部类 变量名 = new 外部类.内部类();
Outer.Inner in = new Outer.Inner();
in.test();
2.4 匿名内部类【重点】
匿名内部类是一种特殊的局部内部类;所谓匿名,指的是程序员不需要为这个类声明名字。
匿名内部类的格式:
new 父类/接口(参数值){
@Override
重写父类/接口的方法;
}
匿名内部类本质上是一个没有名字的子类对象、或者接口的实现类对象。
比如,先定义一个Animal抽象类,里面定义一个cry()方法,表示所有的动物有叫的行为,但是因为动物还不具体,cry()这个行为并不能具体化,所以写成抽象方法。
public abstract class Animal{
public abstract void cry();
}
接下来,我想要在不定义子类的情况下创建Animal的子类对象,就可以使用匿名内部类
public class Test{
public static void main(String[] args){
//这里后面new 的部分,其实就是一个Animal的子类对象
//这里隐含的有多态的特性: Animal a = Animal子类对象;
Animal a = new Animal(){
@Override
public void cry(){
System.out.println("猫喵喵喵的叫~~~");
}
}
a.eat(); //直线上面重写的cry()方法
}
}
匿名内部类的作用:简化了创建子类对象、实现类对象的书写格式。
匿名内部类的应用场景: 只有在调用方法时,当方法的形参是一个接口或者抽象类,为了简化代码书写,而直接传递匿名内部类对象给方法 。
二、Lambda表达式
Lambda表达式是JDK8新增的一种语法形式。
作用:用于简化匿名内部类代码的书写。
1.组成Lambda表达式的三要素:
形式参数,箭头,代码块
(形式参数) -> {代码块}
形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
->:由英文中画线和大于符号组成,固定写法。代表指向动作
代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
2.使用 Lambda表达式的前提条件:有一个接口,接口中只能有一个抽象方法(不能是抽象类,只能是接口 ),像这样的接口,我们称之为函数式接口,只有基于函数式接口的匿名内部类才能被Lambda表达式简化。
代码演示:
public interface Swimming{
void swim();
}
public class LambdaTest1 {
public static void main(String[] args) {
// 目标:认识Lambda表达式.
//1.创建一个Swimming接口的匿名内部类对象
Swimming s = new Swimming(){
@Override
public void swim() {
System.out.println("学生快乐的游泳~~~~");
}
};
s.swim();
//2.使用Lambda表达式对Swimming接口的匿名内部类进行简化
Swimming s1 = () -> {
System.out.println("学生快乐的游泳~~~~");
};
s1.swim();
}
}
3.Lambda表达式还可以简化,具体的简化规则如下:
1.Lambda的标准格式
(参数类型1 参数名1, 参数类型2 参数名2) -> {
...方法体的代码...
return 返回值;
}
2.在标准格式的基础上()中的参数类型可以直接省略
(参数名1, 参数名2) -> {
...方法体的代码...
return 返回值;
}
3.如果{}总的语句只有一条语句,则{}可以省略、return关键字、以及最后的“;”都可以省略
(参数名1, 参数名2) -> 结果
4.如果()里面只有一个参数,则()可以省略
参数名 -> 结果
4.Lambda表达式和匿名内部类的区别
-
所需类型不同
-
匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
-
Lambda表达式:只能是接口
-
-
使用限制不同
-
如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类
-
如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
-
-
实现原理不同
-
匿名内部类:编译之后,产生一个单独的.class字节码文件
-
Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成
-