Java – 内部类

简介

在一个类的里面,再定义一个类。

本篇文章讲解Java中的各种内部类的定义、概念、使用场境等。

 

内部类

就是在类的内部再创建一个类

// 创建一个外部类
public class Car {
    private String carName;
    private int carAge;
    
    // 创建一个内部类
    class Engine{
        public String engineName;
        public int engineAge;
        
        public void show(){
            // 在内部类中可以访问自己的内部类成员属性
            System.out.println(engineName);
            // 在内部类中,可以访问外部类的私有成员属性
            System.out.println(carName);
        }
    }
    // 在外部类不能访问内部类的成员属性
    System.out.println(engineName);  // => 报错
}

 

要访问内部类的成员,需要实例化内部类,再访问。

 

内部类的分类

匿名内部类

概念:它是应用在类内部一种没有名字的类,这种内部类通常是用于实现接口或抽象类方法的,它的类本身没有名字,因此叫匿名内部类,详细解释可看下面讲解:

有名内部类的定义如下:

public class OutCalss {
    public class InnerClass{
        String name;
        int age;
    }
}

InnerClass 就是这个类的名字, 如果这个类需要实现某个接口,或需要重写某个抽象类中的方法

 

我们一般的操作是,通过创建一个新的java文件,然后定义一个新的类,让这个类去实现接口或抽象类中的抽象方法,如下代码所示

// 定义一个游泳的接口,要求实现类实现 swim() 方法
public interface Swim {
    void swim();
}

如果我们需要实现Swim接口的方法,我们需要创建一个类文件,并实现Swim接口,如下代码

 

public class doSwim implements Swim{
    @Override
    public void swim() {
        System.out.println("游泳的实现方法");
    }
}

 

 

从上面的有名类实现Swim接口,对比匿名内部类与有名内部类的区别如下:

public class doSwim implements Swim{
    @Override
    public void swim() {
        System.out.println("游泳的实现方法");
    }
}

代码中的【public class doSwim implements Swim】定义我们可以看作是一个类的名称,和需要实现的接口声明,这部分可以看作是类的全名,而下面的粉色的代码可以看作是这个实现类的实现部分,那么我们可以这么看作,匿名类,就是没有类的全名,只有实现部分:

 

{
    @Override
    public void swim() {
        System.out.println("游泳的实现方法");
    }
}

但是如果只定义上面的代码,Java并不知道我们这段代码实现的是那个接口的方法,因此,接口名就要带在实现方法体之前作为说明:

 

Swim() {
    @Override
    public void swim() {
        System.out.println("游泳的实现方法");
    }
}

其中的Swim 指的是这个匿名类要实现的Swim接口而并非是匿名类的名称,() 指的是这个匿名类的构造函数在创建空参对象,而橙色的代码,才是这个匿名类的真实代码块

 

所以我们可以具体化一点,匿名类除了没有名称外,与一般的类是完全相同的,我们可以实现自己的方法,成员变量等,如下:

Swim(){
    // 定义自己的成员变量
    public String name;
    public int age;
    // 实现接口需要的方法
    @Override
    public void swim() {
        
    }
     // 定义自己的方法
     public String getName(){
         return this.name;
     }
}

 

 

当我们需要创建一个类的对象时,我们使用以下方法创建:

Object o = new Object();

而创建匿名类时,也是同样,使用new 来创建即可:

 

new Swim(){
    @Override
    public void swim() {
        System.out.println("内部类的实现接口方法");
    }
};

因为它本身作为整个类,所以在创建对象时,需要使用【;】号进行结尾。

 

P.S:抽象类中的抽象方法,与接口一样:

// 创建一个抽象类,并创建一个抽象方法
public abstract class Swim {
    public abstract void swim();
}

如果匿名类,需要实现抽象类中的方法,一样使用相同的套路创建就可以了,如下代码:

 

new Swim(){
    @Override
    public void swim() {
        System.out.println("内部类的实现抽象方法");
    }
};

此时只是对一个匿名类进行对象的创建,但没有对对象进行接收,我们可以通过多态方式进行接收:

 

Swim s = new Swim(){
     @Override
     public void swim() {
         System.out.println("内部类的实现抽象方法");
     }
};

 

格式:

new 抽象父类/接口 {
    重写方法
    @override
    public void method(){}
};

匿名内部类的变化过程(*)

变换说明:

1.因为叫匿名内部类,所以定义类的名称就被删掉了,只剩下继承的 接口 或 抽象类。

去掉类名声明后只剩下类的函数体
{
    @Override
    public void show() {

    }
}

 

2.因为要突出这个匿名类是继承那个抽象类或接口,所以要定义继承类

// 抽象类或接口 ( 构造参数列表 )
Inter ( 构造参数列表 ){
    @Override
    public void show() {

    }
}

 

3.因为匿名类是没有名字的,所以就要先 new 出来,所以要在前面加上 new,和正常的 new Class(); 一样,后面都有一个 ";" 号,所以,我们 new 这个匿名内部类时都要在后面加上 ";"

// 抽象类或接口 ( 构造参数列表 )
new Inter ( 构造参数列表 ){
    @Override
    public void show() {

    }
};

 

4.其它重写要求就和一般子类一样定义了,注意,抽象类和接口都一样定义。

P.S:虽然说匿名内部类,但实际上Java会在编译的时候自动帮我们加上这个类的类名,如Class$1.class

 

 使用场景:

当方法的参数是接口或者类时,

以接口为例,可以传递这个接口的实现类对象

如果实现类只要使用一次,就可以用匿名内部类简化代码

 

关于匿名内部类 {{}} 双大括号的概念

从上面的匿名内部类的学习我们知道,当使用匿名类时,实际上是创建一个没有名字的类代码块,它是依赖于实现接口,或实现抽象类中要实现的方法,对于接口,匿名类以"implements"方式实现,对于抽象类,匿名类以“extends”方式继承,那么可得,匿名类还可以像继承抽象类那样,继承普通类:

// 普通类,也能被匿名类进行继承
public class Swim {
    public void swim(){
        System.out.println("定义类的swim");
    }
}

当我们使用匿名类时,则可以对普通类进行继承:

 

Swim s = new Swim(){};

 注意:这里“Swim(){}”之后,所创建的就不是 Swim 类了,而是在Swim之下,创建了一个子类,并继承了 Swim 类,因此,“s”实际上是Swim的子类的对象,只是这个子类没有写任何代码;

根据Java特有的“代码块”特性,我们知道,每一个类都能提供一个代码块,如下:

public class Swim {
    {
        System.out.println("类的代码块");
    }
    
    public void swim(){
        System.out.println("定义类的swim");
    }
}

 

所以其实,Swim() {{}} 这种语法,实际上是匿名类继承了Swim类作为子类,并在创建这个子类时,调用代码块而已,即如下代码:

Swim s2 = new Swim(){{
     System.out.println("创建一个子类继承Swim,并在代码块中执行");
}};

等同于

public class doSwim extends Swim{
    {
        System.out.println("创建一个子类继承Swim,并在代码块中执行");
    }
}

因为匿名类实际上是使用了继承,又因为代码块是在对象创建时执行的,所以可以利用匿名类的代码块,来调用父类的方法,实现,如下应用实例中:

List<String> list = new ArrayList<String>(){
    {
        add("增加一个成员");
    }
};

代码解析:利用匿名类,对ArrayList 以父类进行继承创建一个子类,在子类创建时,调用了匿名类的代码块,并调用父类的add方法。而对象"list"则不是ArrayList对象了,而是ArrayList的子类匿名类的对象了,因为匿名类使用了继承,所以 ArrayList<String> 中的泛型必须要填写。(好比你创建了一个新的子类来继承ArrayList,也必须在子类中定义泛型,不能省略了)。

 

成员内部类

1.写在成员位置的,属于外部类的成员。

public class Car {
  class Engine{}
}

2. 成员内部类可以被一些修饰符所修饰,如 public , 不写(默认),protected , private , static 等,这些修饰符在内部类中和类成员一样作用。

3.在成员内部类里面,JDK16之前不能定义静态变量,JDK16开始才可以定义静态变量。

 

获取成员内部类对象

方法一:在外部类中编写方法,对外提供内部类的对象

方法二:直接创建格式 外部类类名.内部类类名 内部类实例 = new 外部类类名().new 内部类类名()

示例:Outer.Inner oi = new Outer().new Inner();

访问外部类成员

外部类成员变量和内部类成员变量重名时,在内部类如何访问?

public class Outer {
    String name = "10";
    class Inner {
        String name = "20";

        public void show(){
            String name = "30";
            // 我们需要如何才能获得这三个成员变量?
            System.out.println(??);  // => 10
            System.out.println(??);  // => 20
            System.out.println(??);  // => 30
        }
    }
}

 

1.通过就近原则,我们可以使用直接访问的方式取得离自己最近的成员变量值。

2.通过 this 方式获取本类的成员变量值。

3.通过 Outer.this  方式获取外部类的成员变量值

System.out.println(Outer.this.name);  // => 10
System.out.println(this.name);  // => 20
System.out.println(name);  // => 30

 

静态内部类

静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象。

public class Outer {
    static class Inner {
        public void show(){
        }
    }
}

 

创建静态内部类对象

外部类类名.内部类类名 内部类实例 = new 外部类类名.内部类类名()

public class Outer {
    static class Inner {
        public void show(){ }
        public static void staticShow(){}
    }
}

Outer.Inner oi = new Outer.Inner();

 

 

调用非静态方法的格式

先创建对象,用对象调用

public class Outer {
    static class Inner {
        public void show(){ }
        public static void staticShow(){}
    }
}

Outer.Inner oi = new Outer.Inner();
oi.show()

 

调用静态方法的格式

外部类名.内部类名.方法名();

public class Outer {
    static class Inner {
        public void show(){ }
        public static void staticShow(){}
    }
}

Outer.Inner.staticShow()

 

局部内部类

1.将内部类定义在方法里就叫做局部内部类,类似于方法里面的局部变量

2.外界是无法直接使用,需要在方法内部创建对象并使用。

3.该类可以直接访问外部类的成员,也可以访问方法内的局部变量。

public class Outer {
    // 成员内部类
    static class Inner {
        public void show(){ 
            // 成员方法中的局部内部类
            class innerClass{
                
            }
        }
        public static void staticShow(){
            // 静态方法中的内部类
            class innerStaticClass{
                
            }
        }
    }
}

 

如果您喜欢本站,点击这儿不花一分钱捐赠本站

这些信息可能会帮助到你: 下载帮助 | 报毒说明 | 进站必看

修改版本安卓软件,加群提示为修改者自留,非本站信息,注意鉴别

THE END
分享
二维码
打赏
海报
Java – 内部类
在一个类的里面,再定义一个类
<<上一篇
下一篇>>