IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java基础学习十四——内部类详细知识点归纳(匿名内部类、静态内部类、Lambda表达式详细) -> 正文阅读

[Java知识库]Java基础学习十四——内部类详细知识点归纳(匿名内部类、静态内部类、Lambda表达式详细)

一、什么叫内部类

1.定义

内部类就是在一个类的内部定义的类,包含内部类的类被称作外部类。

2.内部类种类

  • 可按照定义的位置区分:方法里定义的内部类称为局部内部类,在方法外的叫成员内部类
  • 也可按照种类区分:非静态内部类(无static修饰)、静态内部类(有static修饰)、匿名内部类。
  • 大部分时候,内部类都被作为成员内部类定义,而不是作为局部内部类。成员内部类是一种与成员变量、方法相似的类成员,成员内部类分为两种(非静态内部类、静态内部类),局部内部类和匿名内部类则不是类成员。
  • 下图为这几种内部类关系

在这里插入图片描述

3.使用格式

class 外部类{
    class 内部类{}
}

编译后会产生两个类文件:外部类.class内部类.class

4.作用

内部的作用如下

  • 内部类提供了更好的封装性,内部类可以只在外部类中有用
  • 内部类也是外部类的成员,所以内部类可以直接访问外部类的私有成员
  • 匿名内部类用来创建那些仅需要一次使用的类

5.内部类与外部类的区别

  • 内部类需定义在外部内的内部
  • 内部类可以使用privateprotectedstatic进行修饰,外部类不可以
  • 非静态内部类不能有静态成员

二、 非静态内部类

1.定义

非静态内部类是没有用static修饰的成员内部类,写在外部类方法体外,外部类里。

2.举例


class Outer {
    private String name;

    //定义一个没有用static修饰的非静态内部类
    public class Inner {
         void print() {
            System.out.println("Inner");
            System.out.println(name);   //直接调用外部类的私有变量
        }
    }

    //外部内定义一个方法,对外提供访问内部内信息的接口
    public void innerPrint() {
        Inner inner = new Inner();
        inner.print();//直接访问外部类的私有成员变量
    }
}

public class TestInner {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.innerPrint();
    }
}

上述的代码中定义了一个内部类Inner,外部类Outer里面包含了一个innerPrint方法,在该方法中创建了一个Inner对象,同时调用该对象的print方法。可以看到,在外部类中使用非静态内部类时与使用普通类没有太大区别。

3.内部类访问外部内成员变量需要注意

  • 当在非静态内部类的方法内访问某个变量时,若有同名的变量,系统查找的优先级为:非静态内部类的该方法的局部变量>非静态内部类的成员变量>内部类所在的外部类
  • 当在非静态内部类的方法内访问某个变量时,如果外部类成员变量、内部类成员变量、内部类方法里的局部变量同名,则可以通过this外部类类名.this来进行区分
  • 非静态内部类的成员只在该非静态内部类内有效,不能被外部类直接使用。如果外部类要访问非静态内部类的成员,则必须显式的创建非静态内部类对象来访问其成员
  • 外部类的静态成员不能直接使用非静态内部类
  • 非静态内部类中不能定义静态成员,即非静态内部类中不能有static修饰的变量、方法、初始化代码块

如下:

class Outer {
    private static String a = "a";
    private String b = "b";


    //定义一个非静态内部类
    public class Inner {
        static String c = "c";//错误,非静态内部类不能有static成员
        private String d = "d";
        void print() {
            System.out.println(a);
            System.out.println(b);
            System.out.println(d);//非静态内部类能直接访问内部类的私有实例对象,也能直接访问外部类的私有实例成员和私有类对象
            System.out.println("Inner");
        }
    }

    //外部内定义一个方法,对外提供访问内部内信息的接口
    void innerPrint() {
        Inner inner = new Inner();
        inner.print();
    }
}

三、静态内部类

1.定义

静态内部类是static修饰的成员内部类,写在外部类方法体外,外部类里,相当于外部类的其他静态成员,没有外部类对象也可以直接访问静态内部类。

2.举例

静态内部类可以包含静态成员和非静态成员,静态内部类不能访问外部类的实例成员,只能够访问外部类的静态成员。


class OutClass {
    private int a = 6;
    private static int b = 7;

    static class InClass {   //定义内部类
        private static int c = 8;
        private int d = 9;

        void show() {
        }

        static void show2() {
        }
    }
}

3.使用规则如下

  • 静态内部类的非静态方法能访问外部类静态成员,静态内部类的非静态方法不能直接访问外部类实例成员,需要通过外部类对象访问外部实例成员
  • 静态内部类的非静态方法能访问内部类静态成员和内部类的实例成员
  • 静态内部类的静态方法能访问外部类静态成员,静态内部类的静态方法不能直接访问外部类的实例成员,需要通过外部类对象访问外部实例成员
  • 静态内部类的静态方法能访问内部类静态成员,不能直接访问内部类的实例成员,需要通过内部类对象访问内部类的实例成员
  • 外部类方法可通过内部类直接调用内部类静态方法,不可通过内部类直接调用内部类非静态方法,需要通过内部类对象调用内部类非静态方法

class OutClass {
    private int a = 6;
    private static int b = 7;

    static class InClass {   //定义内部类
        private static int c = 8;
        private int d = 9;

        void show() {
            System.out.println(a);//错误,静态内部类不能访问外部实例成员
            OutClass outClass = new OutClass();
            System.out.println(outClass.a);//正确,静态内部类能通过外部类对象访问外部实例成员
            System.out.println(b);
            System.out.println(c);
            System.out.println(d);//正确,静态内部类普通方法能访问内部实例成员
        }

        static void show2() {
            System.out.println(a);//错误,静态内部类不能访问外部实例成员
            OutClass outClass = new OutClass();
            System.out.println(outClass.a);//正确,静态内部类可通过对象访问外部实例成员
            System.out.println(b);
            System.out.println(c);
            System.out.println(d);//错误,静态内部类的静态方法不能直接访问内部类的实例成员
            InClass inClass = new InClass();
            System.out.println(inClass.d);//正确,静态内部类静态方法可通过对象访问内部类的实例成员
        }
    }

    void A() {
        InClass.show();//错误,外部类方法不可通过内部类直接调用内部类非静态方法
        InClass.show2();//正确,外部类方法可通过内部类直接调用内部类静态方法
        InClass inClass = new InClass();
        inClass.show();//正确,外部类方法可通过内部类对象调用内部类非静态方法
        System.out.println(InClass.c);//正确,可通过内部类名访问内部类的静态变量
        System.out.println(inClass.d);//正确,可通过内部类对象访问内部类的实例成员
    }
}

四、匿名内部类

先举个例子:

abstract class Fruit{
    public abstract void eat();
}

class Apple extends  Fruit{
    @Override
    public void eat() {
        System.out.println("吃苹果补充维生素");
    }
}

public class Example5_3 {
    public static void main(String[] args) {
        Fruit fruit = new Apple();
        fruit.eat();
    }
}

Apple继承Fruit类,实现了eat方法,然后创建Apple子类的一个实例,将其向上转型为Fruit类,然后创建了Apple子类的一个实例,将其向上转型为Fruit类的引用。但是,如果此处的Apple类只使用一次,那么将其编写为一个独立的类会麻烦很多,此时就可以引入匿名内部类来简化代码的编写。

匿名内部类就是一个没有显式定义名字的内部类。

创建匿名内部类时会立即创建一个该类的实例,匿名内部类适合创建只需要使用一次的类,这个类定义后立即消失。

1.格式

new 接口名()/父类构造器([参数列表]){
...
}

2.种类

从上面的格式中可以看出,创建匿名内部可实现接口或引用普通类。

(1)继承式匿名内部类

abstract class Fruit {
    public abstract void eat();
}


public class Example5_4 {

    public void test() {
        Fruit fruit = new Fruit() {
            @Override
            public void eat() {
                System.out.println("吃苹果补充维生素");
            }
        };
        fruit.eat();
    }

    public static void main(String[] args) {
        Example5_4 example5_4 = new Example5_4();
        example5_4.test();
    }
}

(2)接口式匿名内部类

interface Flyable {
    void fly();
}


public class Example5_5 {

    public void test() {
        Flyable flyable = new Flyable() {
            @Override
            public void fly() {
                System.out.println("飞机能飞,实现了Flyable的接口");
            }
        };
        flyable.fly();
    }

    public static void main(String[] args) {
        Example5_5 example5_5 = new Example5_5();
        example5_5.test();
    }
}

(3)参数式匿名内部类

interface Flyable {
    void fly();
}

public class Example5_6 {
    public void test(Flyable flyable) {
        flyable.fly();
    }

    public static void main(String[] args) {
        Example5_6 example5_6 = new Example5_6();
        example5_6.test(new Flyable() {
            @Override
            public void fly() {
                System.out.println("天鹅会飞");
            }
        });
    }
}

3.使用规则

  • 匿名内部类不能有构造方法,只能有一个实例
  • 匿名内部类不能定义任何静态成员
  • 匿名内部类不能用publicprotectedprivatestatic修饰
  • 匿名内部类不能重复使用,且一定在new后面,隐式的继承一个类或实现一个接口

五、Lambda表达式

1.定义

匿名内部类允许随用随建。JDK8后引入Lambda表达式,能更简洁的传递代码,主要作用就是代替匿名内部类的繁琐语法。

2.Lambda表达式说明

  • 该词来自学术界开发出来的一套用来计算λ的演算法
  • Lambda表达式是一种没有声明名称的匿名方法,但有参数列表、主体、返回类型,还可能有可以抛出异常的列表
  • Lambda表达式可以作为参数传递给方法或存储在变量中

3.Lambda表达式的使用语法

有两种语法格式

(parameters)->(expression) 

或者

parameters)->{statements}
  • parameters:根据情况可以无参数或多个参数
  • ->:将参数列表与主体分开
  • expression/statements:Lambda主体,表达式或语句构成的代码块

λ表达式本质上是一个匿名方法。让我们来看下面这个例子:

public int add(int x, int y) {
	return x + y;
}

转成λ表达式后是这个样子:

(int x, int y) -> x + y;

参数类型也可以省略,Java编译器会根据上下文推断出来:

(x, y) -> x + y; //返回两数之和

或者

(x, y) -> { return x + y; } //显式指明返回值

4.Lambda表达式使用场景

  • Lambda表达式在函数式接口上使用
  • 函数式接口是指只定义一个抽象方法的接口,此接口可以包含多个默认、静态方法,但是只有一个抽象方法详细
     
    举个例子
interface Flyable {
    void fly();
}


public class Example5_5 {

    public void test(Flyable flyable) {
        flyable.fly();
    }

    public static void main(String[] args) {
        Example5_5 example5_5 = new Example5_5();
        Flyable flyable = () -> {
            System.out.println("鸟会飞");
        };
        example5_5.test(flyable);

//等于 example5_5.test(()->{
            System.out.println("鸟会飞");});


    }
}

5.Lambda表达式与匿名内部类区别

  • 匿名内部类可以为抽象类或普通类创建实例,可为任何接口创建实例;Lambda表达式只能为函数式接口创建实例
  • 匿名内部类实现的抽象方法的方法体允许调用接口中定义的默认方法,Lambda表达式不允许调用接口中定义的默认方法
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-18 12:34:18  更:2021-08-18 12:35:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 4:15:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码