1. 成员内部类
成员内部类:在一个类中再定义一个类,作为外部类的成员存在。
成员内部类访问特点:
- 可以直接访问外部类的成员,包括私有方法和变量
- 外部类访问内部类的成员,必须创建内部类对象(这样的条件,提供了更好的封装,提供了实现多继承的可能性)
- 内部类和外部类有相同的成员变量,内部类访问时采取就近原则,若想就访问外部类成员,可采用 外部类名.this.成员变量名
创建内部类对象的格式:外部类名.内部类名 对象名 = new 外部类名().new 内部类名()
public class OutInnerTest{
public static void main(String[] args){
//创建内部类对象
Outer.Inner in = new Outer().new Inner();
in.show();
}
}
class Outer{
int num = 1;
int num1 = 10;
private int num2=20;
public void method() {
System.out.println("外部类的普通方法");
}
public static void method1() {
System.out.println("外部类的静态方法");
}
private void method2() {
System.out.println("外部类的私有方法");
}
class Inner{
int num = 2;
public void show(){
System.out.println("Inner...show");
//内部类中可以访问外部类的成员变量,包括私有
System.out.println(num1 + "..." + num2);
//内部类中可以访问外部类的成员方法,包括私有和静态
method();
method1();
method2();
//内部类和外部类有相同的成员变量,内部类访问时采取就近原则
System.out.println(num);
//若想就访问外部类成员,可采用 外部类名.this.成员变量名
System.out.println(Outer.this.num);
}
}
}
私有成员内部类:只能在外部类的方法中创建内部类对象,使用对象进行访问内部类的成员
静态成员内部类:
静态成员内部类访问格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
静态成员内部类中的静态方法:外部类名.内部类名.方法名();
class Outer1 {
//私有成员内部类
private class Inner {
public void show() {
System.out.println("private...Inner...show");
}
}
public void method() {
//在外部类中创建私有内部类对象,调用其方法
Inner inner = new Inner();
inner.show();
}
//静态成员内部类
static class Inner1 {
public void show() {
System.out.println("static...Inner...show");
}
public static void method() {
System.out.println("static...Inner...static...method");
}
}
}
public class OutInnerTest1 {
public static void main(String[] args) {
// 常规创建内部类对象方式不适合私有成员内部类
// Outer1.Inner in=new Outer1().new Inner();//编译报错
Outer1 outer1 = new Outer1();
outer1.method();//调用外部类方法创建私有内部类对象
//静态成员内部类:外部类名.内部类名 对象名=new 外部类名.内部类名();
Outer1.Inner1 inner1 = new Outer1.Inner1();
//内部类对象调用静态内部类普通方法
inner1.show();
//内部类对象调用静态内部列静态方法两种方法
inner1.method();
//内部类名直接调用静态内部类静态方法
Outer1.Inner1.method();
}
}
2. 局部内部类和匿名内部类
局部内部类特点:
- 局部内部类是在方法中定义的类,所以外界是无法直接使用,需要在方法内部创建其对象并使用
- 该类可以直接访问外部类的成员,也可以访问方法内的局部变量
匿名内部类:
匿名内部类本质上是一个特殊的局部内部类(定义在方法内部)
使用前提:需要存在一个接口或类
实际作用:将实现\继承、方法重写、创建对象放在一步进行,简化创建实现类对象的步骤(就是一步创建一个实现类对象,或者继承类对象)
代码案例:
//接口
interface Inter{
void eat();
}
public class Test {
public static void main(String[] args) {
//接口的引用指向实现类对象,多态
Inter inter = new Inter() {
@Override
public void eat() {
System.out.println("和林黛玉一起吃晚餐");
}
};//匿名内部类
inter.eat();
}
}
匿名内部类的使用场景:当方法的形式参数是接口或抽象类型时,可以将匿名内部类作为实际参数进行传递
interface InterTest{
void poem();
}
public class Test05 {
public static void main(String[] args) {
//直接将匿名内部类传入方法
useInter(new InterTest() {
@Override
public void poem() {
System.out.println("落霞与孤鹜齐飞,秋水共长天一色");
}
});
}
public static void useInter(InterTest inter){
inter.poem();
}
}
3. Lambda表达式
lambda表达式采用的是函数编程思想,函数式编程思想会尽量忽略面向对象的语法,强调做什么(在大括号中直接重写抽象方法)
使用lambda表达式的前提条件:有一个接口、接口中有且仅有一个抽象方法
组成Lambda表达式的三要素:形式参数,箭头,代码块
- ():可以看成是抽象方法的形式参数
- ->:用箭头指向后面要做的事情
- {}:包含一段代码,称之为代码块,可以看成是重写方法中的内容
Lambda表达式案例:
interface Inter{
void eat();
}
public class Test04 {
public static void main(String[] args) {
//匿名内部类创建接口对象
Inter inter = new Inter() {
@Override
public void eat() {
System.out.println("和林黛玉一起吃晚餐");
}
};
inter.eat();
//lambda表达式创建接口对象
Inter inter2 = () -> { System.out.println("和薛宝钗一起吃早餐");};
}
}
接口中的抽象方法有参数和返回值:
interface Calculation{
int calc(int a, int b);
}
public class Test04 {
public static void main(String[] args) {
//lambda表达式一般形式
useCalc((int a, int b) -> {return a+b;});
//Lambda表达式的省略模式
useCalc( (a , b) -> a+b );
//匿名内部类形式
useCalc(new Calculation() {
@Override
public int calc(int a, int b) {
return a+b;
}
});
}
public static void useCalc(Calculation calc){
System.out.println(calc.calc(3, 4));
}
}
Lambda表达式的省略模式:
- 参数类型,可以省略,但是有多个参数的情况下,不能只省略一个参数类型
- 如果参数有且仅有一个,小括号可以省略
- 如果代码块的语句只有一条,可以省略大括号和分号,只有一条return语句,return也可以省略
4. Lambda表达式和匿名内部类的区别
使用限制不同:
- 匿名内部类可以实现接口、继承抽象类或者具体类。接口中的抽象方法数量没有限制
- Lambda表达式只能用于实现接口、而且接口之中只能有一个抽象方法
实现原理不同:
- 匿名内部类:编译之后,产生一个单独的.class字节码文件
- Lambda表达式:编译之后没有一个单独的.class字节码文件,对应的字节码文件会在运行的时候动态生成
如有错误欢迎留言评论,及时更正。 5月25日 羽露风