内部类(Nested Classes)

目录

一、内部类

二、内部类的分类

1、成员内部类

2、静态内部类

3、局部内部类

4、匿名内部类

三、Lambda表达式

1、Lambda表达式

2、Lambda表达式的省略写法

3、Lambda表达式和匿名内部类的区别


一、内部类

1、定义在类中定义的另一个类或是在类的方法中定义的另外一个类

创建对象的格式:

class Outer{
    class Inner{
        
    }
}
外部类.内部类 内部类对象名 = new 外部类对象().new内部类对象() 
Outer.Inner in = new Outer().new Inner();

二、内部类的分类

一般有四种类:成员内部类、局部内部类、匿名内部类和静态内部类

1、成员内部类

成员访问特点

(1)内部类中,访问外部类成员:直接访问,包括私有

下面是代码示例:

/**
 * @author Tweek
 */
public class NestedClasses {
    public static void main(String[] args) {
       Outer.Inner in = new Outer().new Inner();
       in.show();
​
    }
}
​
class Outer{
    /**
     * 内部类访问外部类成员
     */
    private int num = 30;
    public void method(){
        System.out.println("I'm a method of Outttter!");
    }
    class Inner{
​
        public void show(){
​
            System.out.println(num);  //直接访问外部类的私有成员变量
            method();    //直接访问外部类的成员方法
​
        }
    }
}
​
控制台输出:
30
I'm a method of Outttter!

(2)外部类中,访问内部类成员:需要创建对象访问

下面是代码示例:

/**
 * @author Tweek
 */
public class NestedClasses {
    public static void main(String[] args) {
       Outer.Inner in = new Outer().new Inner();
       in.show();
       Outer outer = new Outer();
       outer.method();
​
    }
}
​
class Outer{
    /**
     * 外部类访问内部类的访问特点
     */
    Inner inner = new Inner(); //创建内部类的对象
    public void method(){
        inner.show();
    }
​
    class Inner{
​
        public void show(){
            System.out.println("I'm a method of Innnnnnner!");
        }
    }
}
​
控制台输出:
I'm a method of Innnnnnner!
I'm a method of Innnnnnner!

(3)内部类与外部类变量重名时的访问特点

下面是代码示例:

/**
 * @author Tweek
 */
public class NestedClasses {
    public static void main(String[] args) {
       Outer.Inner in = new Outer().new Inner();
       in.show();
    }
}
​
class Outer{
    /**
     * 变量访问特点
     */
    int num =10;
    class Inner{
        int num =20;
        public void show(){
            int num =30;
            System.out.println(num);    //就近原则访问变量
            System.out.println(this.num);  //在该内中的成员变量
            System.out.println(Outer.this.num); //类名引用成员变量
​
        }
    }
}

2、静态内部类

静态内部类:static修饰的成员内部类

(1)创建对象格式

class Outer{
    static class Inner{
        
    }
}
外部类名.内部类名 对象名 = new 外部类名.内部类对象();
Outer.Inner in = new Outer.Inner();

(2)调用方法

一般情况:

下面是代码示例:

/**
 * @author Tweek
 */
public class NestedClasses {
    public static void main(String[] args) {
       Outer.Inner in = new Outer.Inner();
       in.show();
    }
}
​
class Outer{
    /**
     * 访问static内部类中的方法
     */
   static class Inner{
        public void show(){
            System.out.println("I'm a method of Innnnnnner!");
        }
    }
}
​
控制台输出:
I'm a method of Innnnnnner!

当内部类方法被static修饰时:

/**
 * @author Tweek
 */
public class NestedClasses {
    public static void main(String[] args) {
       Outer.Inner.show();   //因为内部类中的方法是静态的,且内部类也是静态的,故调用静态类中的静态方法时可以用类名调用
    }
}
​
class Outer{
    /**
     * 访问static内部类中static修饰的方法
     */
   static class Inner{
        public static void show(){
            System.out.println("I'm a method of Innnnnnner!");
        }
    }
}
​
控制台输出:
I'm a method of Innnnnnner!

注意:静态内部类只能调用静态方法,当静态内部类想要调用外部类的非静态成员时,需要在内部类中创建对象。

下面是代码示例:

/**
 * @author Tweek
 */
public class NestedClasses {
    public static void main(String[] args) {
       Outer.Inner.show();   //因为内部类中的方法是静态的,且内部类也是静态的,故调用静态类中的静态方法时可以用类名调用
    }
}
​
class Outer{
    /**
     * static内部类访问外部类的成员
     */
    int num =20;
    public void method(){
        System.out.println("I'm a method of Outtttter!");
    }
   static class Inner{
        public static void show(){
            Outer outer = new Outer();  //创建外部类的对象
            outer.method();
            System.out.println(outer.num);
            System.out.println("I'm a method of Innnnnnner!");
        }
    }
}
​
控制台输出:
I'm a method of Outtttter!
20
I'm a method of Innnnnnner!

3、局部内部类

局部内部类:存在与方法、底阿妈快、构造器等执行体中

下面是代码示例:

/**
 * @author Tweek
 */
public class Test2 {
    public static void main(String[] args) {
        Outer outer = new Outer(); //创建外部类对象
        outer.method();  //调用外部类方法,外部类方法进入内部类,找到外部类中创建的局部内部类对象,再用局部类对象调用其方法show()
    }
}
class Outer{
    /**
     * 局部内部类
     * 例在方法内定义
     */
    public void method(){
    class Inner{
        public void show(){
​
            System.out.println("I'm a method of Innnnner!");
         }
      }
      Inner inner = new Inner();   //外部类访问内部类,先创建局部内部类对象
      inner.show(); //调用内部类方法
    }
}
​
控制台输出:
I'm a method of Innnnner!

4、匿名内部类

匿名内部类:匿名内部类是一种特殊的内部类,定义在方法内部

定义匿名内部类的前提:需要存在一个接口或类

格式:new 类名\接口名(){

}

new 类名(){} : 代表继承这个类

new 接口名(){}: 代表实现这个接口

匿名内部类的使用场景:若接口中的方法只有一个时(方法多的时候不建议使用匿名内部类,这样会使得代码变得臃肿,适得其反),我们可以使用匿名内部类,来使得我们的代码更加地简洁,因为若不使用匿名内部类,我们则需要创建新的类并实现接口,调用新类中重写接口的方法。

下面的代码示例,能让我们更好地理解匿名内部类

/**
 * @author Tweek
 */
public class NCTest3 {
    public static void main(String[] args) {
        /**
         * 通过额外的类来实现接口
         * 当方法参参数为接口时,我们此时应该传入接口的实现类,因为接口不能实例化。
         */
        userInter(new InterImp());
        userInter(new Inter(){
            /**
             * 通过匿名内部类来实现接口中的方法,不用再额外创建一个类来实现接口
             */
            @Override
            public void show() {
                System.out.println("I'm a method of The Interface Inter!");
            }
        } );
    }
​
    /**
     * 此处方法的参数传入的是一个接口,但是接口不能实例化,所以有两种方法
     * 1、创建新类实现接口
     * 2、利用方法内部的匿名内部类来实现接口中的方法
     * @param i
     */
    public static void userInter(Inter i){
        i.show();
    }
}
interface Inter{
    void show();
}
class InterImp implements Inter{
​
    @Override
    public void show() {
        System.out.println("I'm a method of The InterImp!");
    }
}
​
​
控制台输出:
I'm a method of The InterImp!
I'm a method of The Interface Inter!

三、Lambda表达式

1、Lambda表达式

JDK8开始后的一种新语法形式

作用:简化你们内部类的代码写法

格式:() -> {}

           () : 匿名内部类被重写方法的形参列表

           {} : 被重写方法的方法体代码

注意:Lambda表达式,只允许操作函数式变成接口:即有且仅有一个抽象方法的接口!

下面的代码示例,能让我们更好地了解Lambda表达式

/**
 * @author Tweek
 */
public class NCTest3 {
    public static void main(String[] args) {
        /**
         * 利用Lambda表达式来简化匿名内部类
         * Lambda表达式格式: () -> {}
         * 
         */
        userInter(()->{ System.out.println("I'm a method of The Interface Inter!");});
    }
​
​
    public static void userInter(Inter i){
        i.show();
    }
}
interface Inter{
    void show();
}
​
控制台输出:
I'm a method of The Interface Inter!

2、Lambda表达式的省略写法

(1)参数类型可以省略不写

下面是代码示例:

/**
 * @author Tweek
 */
public class NCTest3 {
    public static void main(String[] args) {
        /**
         * 省略参数类型
         */
        userCalculator(new Inter() {
            @Override
            public int calculate(int a, int b) {
                return a + b;
            }
        });
        System.out.println("---------------------------------");
        //省略参数类型
        userCalculator((a,b)->a+b);
    }
​
​
    public static void userCalculator(Inter i){
         int result= i.calculate(10,20);
         System.out.println(result);
    }
}
interface Inter{
    int calculate(int a,int b);
}
​
控制台输出:
30
---------------------------------
30

(2)如果只有一个参数,参数类型可以省略,同时()也可以省略。

下面是代码示例:

/**
 * @author Tweek
 */
public class NCTest3 {
    public static void main(String[] args) {
        /**
         * 如果只有一个参数,参数类型可以省略,同时()  也可以省略
         *
         */
        userInter(s->{ System.out.println("I'm a method of The Interface Inter!"+s);});
    }


    public static void userInter(Inter i){
         String s = "GOOD";
        i.show(s);
    }
}
interface Inter{
    void show(String s);
}

控制台输出:
I'm a method of The Interface Inter!GOOD

(3)如果Lambda表达式的方法体代码只有一行代码时

     1.可以省略大括号不写,同时要省略分号

下面是代码示例:

/**
 * @author Tweek
 */
public class NCTest3 {
    public static void main(String[] args) {
        /**
             可以省略代码的大括号,同时省略分号
             
         */
        userInter(s-> System.out.println("I'm a method of The Interface Inter!"+s));
    }
​
​
    public static void userInter(Inter i){
         String s = "GOOD";
        i.show(s);
    }
}
interface Inter{
    void show(String s);
}
​
控制台输出:
I'm a method of The Interface Inter!GOOD

     2.此时,如果这行代码是return语句,必须省略return,同时也必须省略一个;

/**
 * @author Tweek
 */
public class NCTest3 {
    public static void main(String[] args) {
        /**
         * 如果一行代码是return语句,那么必须省略return与;
         */
        userRandom(new Inter() {
            @Override
            public int getNumber() {
                return new Random().nextInt(100)+1;
            }
        });
        System.out.println("---------------------------------");
        userRandom(()->new Random().nextInt(100)+1);
    }
​
​
    public static void userRandom(Inter i){
         int result= i.getNumber();
         System.out.println(result);
    }
}
interface Inter{
    int getNumber();
}
​
控制台输出:
41
---------------------------------
93

3、Lambda表达式和匿名内部类的区别

(1)使用限制不同

    1.匿名内部类:可以操作类,接口

    2.Lambda表达式:只能操作函数式接口

(2)实现原理不同

    1.匿名内部类:编译之后,产生一个单独的.class字节码文件

    2.Lambda表达式:编译之后,没有一个单独的.class字节码文件

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kotlin中的嵌套类(Nested Classes)和内部类(Inner Classes)是非常相似的概念,但有一些细微的区别。以下是对它们的一些基本介绍: 1. **嵌套类(Nested Classes)**:在Kotlin中,嵌套类是一种类,它包含在另一个类的内部。它可以是静态的(static)、非静态的(inner)或者局部的(local)。嵌套类可以从任何访问它的外部类访问字段、方法、构造器和嵌套类。这允许一个类的数据可以在嵌套类中被更细粒度地访问和控制。 ```kotlin class OuterClass { class NestedClass { // code inside } } ``` 2. **内部类(Inner Classes)**:内部类是定义在另一个类内部的类。它可以直接访问外部类的所有成员,包括字段、方法、构造器和嵌套类。内部类可以包含自己的构造函数,并且可以访问外部类的私有成员。内部类可以嵌套在其他内部类中,形成一个复杂的层次结构。 ```kotlin class OuterClass { inner class InnerClass { // code inside } } ``` 总的来说,内部类在实现接口、继承某个类或封装内部数据结构时特别有用。另一方面,嵌套类提供了一种更灵活的方式来访问外部类的数据和方法,即使外部类在不同的包或模块中。 需要注意的是,尽管Kotlin中的嵌套类和内部类非常相似,但在某些情况下,使用嵌套类的语法可能更清晰和直观。例如,使用嵌套类可以更清楚地表示一个类的嵌套结构,而内部类则更适合实现接口或封装内部数据结构。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值