Java中的内部类(超详细)

内部类

概念:

在一个类的类中定义一个类,在一个A类的内部定义一个内部类B,B叫做内部类,A叫做外部类。

内部类的作用:

  • 可以无条件的访问外部类的所有元素

  • 可以吧内部类通过private将内部类的信息隐藏

  • 可以实现多继承(当一个类里面于存在多个内部类的时候,可以让内部类继承别的类,这样就变向的实现了多继承)

访问特点:

内部类访问外部类的内容,直接可以访问,包括私有的。外部类要想访问内部类的内容,必须创建内部类的对象,通过对象来访问。

代码:

public class OtherText {//外部类
    int a=10;
    private int age=12;
    class Inter{//内部类
        int a=12;
        public void show(){
            System.out.println(age);
        }
        public void method(){
            int a=15;
            System.out.println(a);
            System.out.println(age);
            System.out.println(this.a);
            System.out.println(OtherText.this.a);
           // System.out.println(this.age);
        }
    }
    public void show1(){//成员方法
        Inter inter=new Inter();
//        inter.xixi;//inter对象里没有xixi变量
    }
    public void function(){//成员方法
        int xixi=15;
    }
classText{
      public static void main(String[] args) {
         OtherText.Inter inter=new OtherText().new Inter();
         inter.show();
     }
}
}

成员内部类(在类的成员位置)

1,内部类创建对象的理解
public class OtherText {//外部类
    int a=10;
    private int age=12;
    class Inter{//内部类
        int a=12;
        public void show(){
            System.out.println(age);
        }
      
    }
}
classText{
      public static void main(String[] args) {
          OtherText.Inter inter=new OtherText().new Inter();
      }
}
//这里这样创建对象是因为直接写Inner找不到Inner在哪里。Inter是在OtheText里面的,所以你的通过OtherText找到Inner,而这里new OtherText().new Inter();因为Inner是OtherText的成员,你想有Inner对象,就要先new Outer的对象。因为Inner本身也是一个类,所以也要通过new 。
2,静态成员内部类
public class Outer {
    int a = 10;
    public static class Inner{
        public void method(){
            System.out.println("内部类的method方法");
        }
    }
}
class Test {
    public static void main(String[] args) {
       Outer.Inner inner=new Outer.Inner();
                  /*
                  Inner 是属于 Outer的静态内容。
                  静态的随着类的存在而存在的, 所以可以用类名调用。
                   */
    }
}
3,成员内部类访问当前外部类对象的内容
public class Outer {
    int a = 10;

    public class Inner{
        int a = 20;
        public void method(){
            int a = 30;
            System.out.println(a); // 30
            System.out.println(this.a); // 20
            //System.out.println(super.a);  //编译报错
            //System.out.println(Outer.a);  //编译报错
            System.out.println(Outer.this.a); // 5  这里表示当前内部对象所在的外部对象。
            System.out.println(new Outer().a); //10
        }
    }

    int b = 40;
}

局部内部类(在类的局部位置)

1,局部内部类如何把对象扔到外界使用:

思路:如何才能将一个局部内部类扔到外面,让外部可以直接访问呢,我们就可以通过方法的返回值吧对象扔到外界使用,但是Inner是内部的东西,不能直接写,这时候我们就可以利用多态的思想,创建一个接口,让Inner实现这个接口。然后返回值为父类。

interface Face{
    void method();
}
class OuterText {
    private int num=10;
    //成员方法
    public Face show(){
        class Inner implements Face{
            public void method(){
                System.out.println(num);
            }
        }
        return new Inner();
    }

}
class Test {
    public static void main(String[] args) {
        //把Inner 扔到这里来用
        OuterText o=new OuterText();
        Face f = o.show();
        f.method();
    }
}
2,局部内部类面试题

局部内部类访问局部变量, 局部变量前面必须有final修饰, 在jdk1.8的时候,这个final可以省略,但其实并不是真正的省略,而是 前面默认有一个 final ,只是你看不到而已。

interface Digests{
    void diges();
}
public class Person {
    public Digests digestion(){
        int a = 10;
        //a = 20;
        class Tract implements  Digests{
            public void diges(){
                System.out.println(a); 
            }
        }
        Tract t = new Tract();
        return t;
    }
}

我们通过画图来了解带fianl的好处:

不带final

在这里插入图片描述

带final

在这里插入图片描述

通过内存图可以看出,final关键字延长了局部变量的生命周期

匿名内部类

匿名内部类的由来————>

interface Digests{
    void diges();
}
class Text{
	public static void main(String[] args){
	//如何才能调用diges方法
	
	}
}

通过上述代码,我们如何调用diges()方法呢?

  • 方案1:创建一个Digests接口的实现类,重写diges()方法,这样有点麻烦
  • 方案2:让测试类实现Digests接口,在测试类里重写diges()方法,这样也有点麻烦。
  • 方案3:通过匿名内部类,这个类没有名字.
看代码
interface Digests{
    void diges();
}
class Text {
    public static void main(String[] args){
        //如何才能调用diges方法
        Digests d=new Digests() {
            @Override
            public void diges() {
                System.out.println("匿名内部类......");
            }
        };
        d.diges();
    }
}
匿名内部类的格式:
new 接口名(){
	   重写方法;
};
匿名内部类的应用:

匿名内部类一般 会作为方法的实参去传递 ,返回值去返回。

interface Digests{
    void diges();
}
class ImplDigests {
    public Digests show(){
        return new Digests() {
            @Override
            public void diges() {
                System.out.println("内部类。。。。。。。");
            }
        };
    }
    public static void main(String[] args) {
    }
}
匿名内部类的使用场景:

当一个接口只有一个抽象方法的时候,用匿名内部比较方便,当一个接口中有多个抽象方法的时候,还不如去额外创建一个实现类

interface Digests{
    void diges();
}
class ImplDigests {
    public static void main(String[] args) {
       show(new Digests() {
           @Override
           public void diges() {
               System.out.println("蜀道之难,难于上秦天");
           }
       });
    }
    public static void show(Digests d){
        d.diges();
    }
}

Lambda表达式

目的:

就是为了优化匿名内部类的写法

格式说明和前提条件:
格式:()-> {重写内容}

():代表的是接口中抽象方法的参数

-> 这是一个固定的格式,意思是()里的参数可以给后面的{}使用

{}这里就是你需要重写的那个方法体

前提条件

1,Lanbda表达式必须有上下文的推导,必须根据逻辑让Jvm虚拟机推导出Lanbda实现的是哪个接口

2,Lanbda表达式只针对接口。

3,Lanbda表达式实现的接口必须只能有一个抽象方法

通过案例来找到前提条件

案例1;

interface Digests{
    void diges();
}
class ImplDigests {
    public static void main(String[] args) {
       show(()->{
           System.out.println("Digests接口中的diges方法....");
       });
    }
    public static void show(Digests d){
        d.diges();
    }
}

案例2:

interface Digests{
    void diges();
    void method();
}
class ImplDigests {
    public static void main(String[] args) {
       show(()->{//这里编译报错
           System.out.println("Digests接口中的diges方法....");
       });
    }
    public static void show(Digests d){
        d.diges();
    }
}

解析:根据()格式的定义 我们就能推断出 接口只能有一个抽象方法。因为Lamdba只能重写接口中的一个方法。

案例3
interface Digests{
   // void diges();
    void method(int a);
}
class ImplDigests {
    public static void main(String[] args) {
       show((int s)->{
           System.out.println(s);
           System.out.println("Digests接口中的diges方法....");
       });
    }
    public static void show(Digests d){
        d.method(12);
    }
}

如果抽象方法中有参数,在Lambda表达式中也要有参数

案例4:
interface Digests{
    void method(int a);
}
class ImplDigests {
    public static void main(String[] args) {
       show((int s)->{
           System.out.println(s);
           System.out.println("Digests接口中的diges方法....");
       });
    }
    public static void show(Digests d){
        d.method(12);
    }
}
案例5:
interface Digest{
    void diges();
}
interface Digests{
    void method();
}
class ImplDigests {
    public static void main(String[] args) {
       ()->{//编译报错
           System.out.println();
           System.out.println("Digests接口中的diges方法....");
       };
    }
}

解析:因为Lambda表达式的格式只能表现出重写方法,而没有表达出重写的哪个接口中的方法。案例中有两个接口。所以我们要通过上下文来进行推导。

案例6
interface Digest{
    void diges();
}
interface Digests{
    void method();
}
class ImplDigests {
    public static void main(String[] args) {
       Digest digest=()->{//通过前年的引用来推导
           System.out.println();
           System.out.println("Digests接口中的diges方法....");
       };
    }
}
案例7
}
interface Digests{
    void method();
}
class ImplDigests {
    public static void main(String[] args) {
       show(()->{//通过show方法的参数推导
           System.out.println("秋天不回来");
       });
    }
    public static void show(Digest digest){
        digest.diges();
    }
}
案例8
interface Digests{
    void method();
    void method1();
}
class ImplDigests {
    public static void main(String[] args) {
       Digests digests=()->{//编译报错
           System.out.println("秋天不回来");
       };
    }
    public static void show(Digest digest){
        digest.diges();
    }
}

解析:因为接口中存在两个抽象方法。

lambda优化:

  • ​ ()内如果只有一个参数 可以省略数据类型和小括号本身。

  • ​ ()内多个参数的 只能省略参数的数据类型不能省略小括号本身

  • ​ {}内如果只有一句话 可以省略分号 还有return 还有大括号本身

lambda和匿名内部类的区别:

  • ​ 匿名内部类 可以对 普通类 抽象类 接口 都可以使用但是lambda必须对接口使用
  • ​ 匿名内部类 可以要求 普通类 抽象类 接口 里面有多少抽象方法,lambda 要求接口中只能有一个抽象方法
  • ​ 匿名内部类会生成class文件,而lambda不生成class文件
  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值