内部类
1、概念
在一个类中 定义一个类
2、访问特点
内部类可以直接访问外部类成员,包括私有的
外部类要访问内部类的成员,必须要创建对象
3、定义位置:
局部内部类:位于局部位置(也就是成员方法内部)
成员内部类:位于成员位置,也就是跟成员变量一个位置
格式: 外部类名.内部类名 对象名 = 外部类对象.内部类对象;
4、定义格式
public class Outer {
class Inner {
}
}
4、创建内部类对象的格式
外部类名.内部类名 对象名 = new 外部类名().new 内部类名();
私有成员内部类
1、定义格式
public class Outer {
private class Inner {
}
}
2、访问
在自己所在的外部类中创建对象进行访问
静态成员内部类
1、定义格式
public class Outer {
static class Inner {
}
}
2、访问格式
外部类名.内部类名 对象名 = new 外部类.内部类();
局部内部类
1、定义位置
方法中定义的类
2、访问方式特点
(1)外界无法直接使用,需要方法内部创建对象并使用
(2)可以直接访问外部类的成员,也可以访问方法内的局部变量
示例
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();
}
}
匿名内部类
1、使用前提
存在一个类或者接口,这里的类可以是具体类也可以是抽象类
2、格式
new 类名(){ 重写方法}
new 接口名(){ 重写方法}
// Inter是一个接口
new Inter() {
@Override
public void method(){
}
}
3、本质
是一个继承了该类或者实现了该接口的子类匿名对象
4、匿名内部类可以通过多态的形式接受
Inter i = new Inter(){
@Override
public void method(){
}
}
5、匿名内部类可以直接调用方法
interface Inter{
void method();
}
class Test{
public static void main(String[] args){
new Inter(){
@Override
public void method(){
System.out.println("我是匿名内部类");
}
}.method(); // 直接调用方法
}
}
Lambda表达式
1、组成三要素
形式参数 箭头 代码块
示例:(形式参数) -> { 代码块 }
形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
->:由英文中画线和大于符号组成,固定写法。代表指向动作
代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
2、使用前提
(1)必须是接口所对应的匿名内部类
(2)接口必须只有一个抽象方法,也就是必须是函数式接口,如果要省略大括号,那么抽象方法的实现只有一句话(如果一个接口里面只有一个抽象方法,就叫做函数式接口)
示例:
public interface Inter {
void show();
}
public class Test {
public static void main(String[] args) {
Inter inter = new Inter() {
@Override
public void show() {
System.out.println("匿名类");
}
};
inter.show();
// 使用lambda表达式,代码块有多行代码
Inter inter1 =() -> {
System.out.println("匿名类");
System.out.println("匿名类");
};
inter1.show();
// 使用lambda表达式,代码块只有一行代码
Inter inter2 =() -> System.out.println("匿名类");
inter2.show();
}
3、使用
(1)无参无返回值
()->{ 重写方法代码 }
案例:
//接口
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();
}
}
(2)有参无返回值
(参数列表)->{ 重写方法代码 }
案例:
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("风和日丽,晴空万里");
}
}
(3)无参有返回值
()->{ 重写方法代码,带return语句 }
(4)有参有返回值
(参数列表)->{ 重写方法代码,带return语句 }
案例:
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);
}
}
4、表达式省略模式
(1)参数的类型可以省略。但是参数列表里面是多个参数,那么不能只省略一个,要么所有参数类型都省略,要么都不省略(例如:(a,b)->{重写代码})
(2)如果只有一个参数,那么小括号也可以省略(例如:a->{重写代码})
(3)如果代码块的语句只有一条,那么可以省略左边的大括号和分号以及return关键字(例如:(a,b)-> a+b)
案例:
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));
//如果代码块的语句只有一条,可以省略大括号和分号,如果有return,return也要省略掉
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);
}
}
5、Lambda表达式和匿名内部类的区别
(1)、 所需类型不同
匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
Lambda表达式:只能是接口
(2)、 使用限制不同
如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类
如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
(3)、 实现原理不同
匿名内部类:编译之后,产生一个单独的.class字节码文件
Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成