从零开始学java--内部类

目录

内部类

成员内部类

定义:

 使用成员内部类:

同名变量的使用:

静态内部类

局部内部类

匿名内部类

Lambda表达式

表达式的语法:

匿名内部类和Lambda的变量捕获:

优缺点:

方法引用


内部类

成员内部类

我们可以直接在类的内部定义 成员内部类:

定义:

内部类也是类,所以说里面也可以有成员变量、方法等,甚至可以继续套娃一个成员内部类:

public class Test {
    
    class Inner{
        public void test(){
            System.out.println("我是成员内部类");
        }
    }
}

 使用成员内部类:

 成员内部类就像成员变量和成员方法一样,都是属于对象的,而不是类所有的。

不能直接new

    public static void main(String[] args){
        Test test=new Test(); //先创建对象
        Test.Inner inner=test.new Inner(); //成员内部类的类型名称就是 外层.内部类名称
        inner.test(); //可以使用成员内部类中的方法
    }

成员内部类也可以使用访问权限控制,如果我们将其权限改为private,那么就像我们把成员变量访问权限变成私有一样,外部是无法访问到这个内部类的。

在成员内部类中,是可以访问到外层的变量的;

外部不能访问内部类里面的成员变量。

同名变量的使用:

public class Test {
    private final String name;
    
    public Test(String name){
        this.name=name;
    }
    
    public class Inner{
        
        String name;
        
        public void test(String name){
            System.out.println("方法参数的name="+name);//就近原则,最近的是参数
            System.out.println("内部成员的name="+this.name);//在内部类中使用this关键字,只能表示内部对象
            System.out.println("外部的name="+Test.this.name);
            //如果需要指定为外部的对象,那么需要在前面添加外部类型名称
        }
    }
}

对方法的调用和super关键字的使用也是一样的:

    public class Inner{

        String name;

        public void test(String name){
            this.toString();  //内部类自己的toString方法
            super.toString();  //内部类父类的toString方法
            Test.this.toString();  //外部类的toString方法
            Test.super.toString();  //外部类父类的toString方法
        }
    }


静态内部类

静态内部类就像静态方法和静态变量一样,是属于类的。

public class Test {
    private final String name;

    public Test(String name){
        this.name=name;
    }

    public static class Inner{

        public void test(){
            System.out.println("我是静态内部类");
        }
    }
}

不需要依附任何对象,我们可以直接创建静态内部类的对象:

可以直接new

    public static void main(String[] args){
        Test.Inner inner=new Test.Inner();
        inner.test();
    }

 静态内部类无法访问到外部的非静态内容,内部不受影响。


局部内部类

局部内部类就像局部变量一样,可以在方法中定义。

public class Test {
    private final String name;

    public Test(String name){
        this.name=name;
    }

    public void hello(){
        class Inner{   //局部内部类
            
        }
        
        Inner inner=new Inner();  //局部内部类直接使用类名
    }
}

既然是在方法中声明的类,那作用范围也只在方法中。

匿名内部类

使用频率高,局部内部类的简化版。

正常情况下,要创建一个抽象类的实例对象,只能对其进行继承,先实现未实现的方法,然后创建子类对象。

而我们可以在方法中使用匿名内部类,将其中的抽象方法实现,并直接创建实例对象。

public abstract class Student {
    public abstract void test();
}
import com.test.entity.Student;

public class Main {
    public static void main(String[] args){
        Student student=new Student() { //在new的时候后面加上{},把未实现的方法实现
            @Override
            public void test() {
                System.out.println("我是匿名内部类的实现");
            }
        };
        student.test();
    }
}

匿名内部类同样可以使用类中的属性(因为它本质上就相当于是对应类型的子类)。

接口也是一样的。

普通的类也可以这样创建匿名内部类,一般情况下只是为了进行一些额外的初始化工作。


Lambda表达式

前面介绍了匿名内部类,我们可以通过这种方法创建一种临时的实现子类。

如果一个接口中只有一个待实现的抽象方法,那么可以将匿名内部类简写为Lambda表达式。

    public static void main(String[] args){
        Study study= () ->System.out.println("我是学习方法");
        study.study();
    }

表达式的语法:

  • ([参数类型 参数名称,]...)->{代码语句,包括返回值}
  • 和匿名内部类不同,Lambda仅支持接口,不支持抽象类
  • 接口内部必须有且仅有一个抽象方法(可以有多个方法,但是必须保证其他方法有默认实现,必须留一个抽象方法出来)
    public static void main(String[] args){
        Study study= new Study() {
            @Override
            public String study(int a) {
                return "今天学会了"+a;
            }
        };
        System.out.println(study.study(10));
    }

改为Lambda表达式:

    public static void main(String[] args){
        Study study= (int a)-> {
            return "今天学会了"+a;
        };
        System.out.println(study.study(10));
    }

再简写:

    public static void main(String[] args){
        Study study= a-> "今天学会了"+a;
        System.out.println(study.study(10));
    }

匿名内部类和Lambda的变量捕获:

变量a就是,捕获的变量。这个变量要么是被final修饰,如果不是被final修饰的,要保证在使用 之前没有修改(a是final或有效final)

    public static void main(String[] args){
        int a=10;
        Study study= ()-> {
            System.out.println(a);
        };
        study.study();
    }
//复制一个a
        int a=10;
        a=20;
        int finalA = a;
        Study study= ()-> System.out.println(finalA);

优缺点:

Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。

优点:

  • 代码简洁,开发迅速
  • 方便函数式编程
  • 非常容易进行并行计算
  • Java 引入 Lambda,改善了集合操作

缺点:

  • 代码可读性变差
  • 在非并行计算中,很多计算未必有传统的 for 性能要高
  • 不容易进行调试


方法引用

方法引用就是将一个已实现的方法,直接作为接口中抽象方法的实现(当然前提是方法定义得一样才行)

public interface Study {
    int sum(int a,int b);  //待实现的求和方法
}
//Lambda表达式
    public static void main(String[] args){
        Study study=(a,b)->a+b;
    }

//Integer类中对应的实现
        Study study=(a,b)->Integer.sum(a,b);

我们发现,Integer.sum的参数和返回值,跟我们在Study中定义的完全一样,所以说我们可以直接使用方法引用:

    public static void main(String[] args){
        Study study=Integer::sum;
    }

使用双冒号来进行方法引用,静态方法使用 类名::方法名 的形式。

方法引用本质上就相当于将其他方法的实现,直接作为接口中抽象方法的实现,任何方法都可以通过方法引用作为实现:

public interface Study {
    String study();
}
public class Main {
    public static void main(String[] args){
        Main main =new Main();
        Study study=main::xxx;
        System.out.println(study.study());
    }

    public String xxx(){
        return "hhhhh";
    }
}
//输出 hhhhh

成员方法通过具体的对象调用,所以只能使用 对象::方法名 的形式。

因为现在只需要一个String类型的返回值,由于String的构造方法在创建对象时也会得到一个String类型的结果,所以:

    public static void main(String[] args){
        Study study=String::new; //构造方法也可以被引用,使用new表示
    }

只要符合接口中方法的定义的,都可以直接进行方法引用。

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值