Java 内部类

Java内部类是在另一个类的主体内定义的。Java内部类可以声明为private、public、protected或默认访问权限,而外部类只能具有public或默认访问权限。Java嵌套类分为两种。

  1. 静态嵌套类

    如果嵌套类是静态的,则称为静态嵌套类。静态嵌套类只能访问外部类的静态成员。静态嵌套类与任何其他顶级类相同,仅为了包装方便而嵌套。可以使用以下语句创建静态类对象。

    OuterClass.StaticNestedClass nestedObject =
         new OuterClass.StaticNestedClass();
    
  2. java 内部类

    在 Java 中,任何非静态嵌套类都被称为内部类。Java 内部类与类的对象相关联,它们可以访问外部类的所有变量和方法。由于内部类与实例相关联,因此我们不能在其中有任何静态变量。Java 内部类的对象是外部类对象的一部分,要创建内部类的实例,我们首先需要创建外部类的实例。Java 内部类可以像这样实例化;

    OuterClass outerObject = new OuterClass();
    OuterClass.InnerClass innerObject = outerObject.new InnerClass();
    
  1. 本地内部类

    如果一个类在方法体内定义,它被称为本地内部类。由于本地内部类与对象无关,我们不能使用private、public或protected访问修饰符。唯一允许的修饰符是abstract或final。本地内部类可以访问封闭类的所有成员和在其定义范围内的本地final变量。此外,它还可以访问方法中定义的非final本地变量,但不能修改它们。因此,如果尝试打印非final本地变量的值,将被允许,但如果尝试在方法本地内部类内部更改其值,则会得到编译时错误。本地内部类的定义如下:

    package com.journaldev.innerclasses;
    
    public class MainClass {
    
    	private String s_main_class;
    
    	public void print() {
    		String s_print_method = "";
    		// 方法内部的本地内部类
    		class Logger {
    			// 能够访问封闭类变量
    			String name = s_main_class; 
    			// 能够访问非final方法变量
    			String name1 = s_print_method; 
    
    			public void foo() {
    				String name1 = s_print_method;
    				// 下面的代码将引发编译时错误:
    				// 在封闭范围内定义的本地变量s_print_method必须是final或有效最终的
    				// s_print_method= ":";
    			}
    		}
    		// 在方法中实例化本地内部类以使用
    		Logger logger = new Logger();
    
    	}
    }
    

    我们还可以在任何块内定义本地内部类,如静态块、if-else块等。但在这种情况下,类的范围将非常有限。

    public class MainClass {
    
    	static {
    		class Foo {
    			
    		}
    		Foo f = new Foo();
    	}
    	
    	public void bar() {
    		if(1 < 2) {
    			class Test {
    				
    			}
    			Test t1 = new Test();
    		}
    		// 由于类的范围,下面将引发错误
    		//Test t = new Test();
    		//Foo f = new Foo();
    	}
    }
    
  2. 匿名内部类

    没有名称的局部内部类称为匿名内部类。匿名类在单个语句中定义并实例化。匿名内部类总是扩展一个类或实现一个接口。由于匿名类没有名称,因此无法为其定义构造函数。匿名内部类只能在定义它的位置访问。如何创建匿名内部类有点困难,我们将在下面的测试程序中看到它的实时用法。

下面是一个展示如何定义Java内部类、静态嵌套类、局部内部类和匿名内部类的Java类。 OuterClass.java

package com.journaldev.nested;

import java.io.File;
import java.io.FilenameFilter;

public class OuterClass {
    
    private static String name = "OuterClass";
    private int i;
    protected int j;
    int k;
    public int l;

    //OuterClass构造函数
    public OuterClass(int i, int j, int k, int l) {
        this.i = i;
        this.j = j;
        this.k = k;
        this.l = l;
    }

    public int getI() {
        return this.i;
    }

    //静态嵌套类,可以访问OuterClass的静态变量/方法
    static class StaticNestedClass {
        private int a;
        protected int b;
        int c;
        public int d;

        public int getA() {
            return this.a;
        }

        public String getName() {
            return name;
        }
    }

    //内部类,非静态的,可以访问外部类的所有变量/方法
    class InnerClass {
        private int w;
        protected int x;
        int y;
        public int z;

        public int getW() {
            return this.w;
        }

        public void setValues() {
            this.w = i;
            this.x = j;
            this.y = k;
            this.z = l;
        }

        @Override
        public String toString() {
            return "w=" + w + ":x=" + x + ":y=" + y + ":z=" + z;
        }

        public String getName() {
            return name;
        }
    }

    //局部内部类
    public void print(String initial) {
        //局部内部类 inside the method
        class Logger {
            String name;

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

            public void log(String str) {
                System.out.println(this.name + ": " + str);
            }
        }

        Logger logger = new Logger(initial);
        logger.log(name);
        logger.log("" + this.i);
        logger.log("" + this.j);
        logger.log("" + this.k);
        logger.log("" + this.l);
    }

    //匿名内部类
    public String[] getFilesInDir(String dir, final String ext) {
        File file = new File(dir);
        //匿名内部类 implementing FilenameFilter interface
        String[] filesList = file.list(new FilenameFilter() {

            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(ext);
            }

        });
        return filesList;
    }
}

这是一个测试程序,展示了如何在Java中实例化和使用内部类。InnerClassTest.java

package com.journaldev.nested;

import java.util.Arrays;
//嵌套类可以在导入中使用,以便进行简单的实例化
import com.journaldev.nested.OuterClass.InnerClass;
import com.journaldev.nested.OuterClass.StaticNestedClass;

public class InnerClassTest {

    public static void main(String[] args) {
        OuterClass outer = new OuterClass(1,2,3,4);
        
        //静态嵌套类示例
        StaticNestedClass staticNestedClass = new StaticNestedClass();
        StaticNestedClass staticNestedClass1 = new StaticNestedClass();
        
        System.out.println(staticNestedClass.getName());
        staticNestedClass.d=10;
        System.out.println(staticNestedClass.d);
        System.out.println(staticNestedClass1.d);
        
        //内部类示例
        InnerClass innerClass = outer.new InnerClass();
        System.out.println(innerClass.getName());
        System.out.println(innerClass);
        innerClass.setValues();
        System.out.println(innerClass);
        
        //使用局部内部类调用方法
        outer.print("Outer");
        
        //使用匿名内部类调用方法
        System.out.println(Arrays.toString(outer.getFilesInDir("src/com/journaldev/nested", ".java")));
        
        System.out.println(Arrays.toString(outer.getFilesInDir("bin/com/journaldev/nested", ".class")));
    }

}

这是上述Java内部类示例程序的输出。

OuterClass
10
0
OuterClass
w=0:x=0:y=0:z=0
w=1:x=2:y=3:z=4
Outer: OuterClass
Outer: 1
Outer: 2
Outer: 3
Outer: 4
[NestedClassTest.java, OuterClass.java]
[NestedClassTest.class, OuterClass$1.class, OuterClass$1Logger.class, OuterClass$InnerClass.class, OuterClass$StaticNestedClass.class, OuterClass.class]

请注意,当编译OuterClass时,为内部类、局部内部类和静态嵌套类分别创建了单独的类文件。

Java内部类的优点

  1. 如果一个类只对一个类有用,将其嵌套并保持在一起是有意义的。它有助于打包类。
  2. Java内部类实现封装。请注意,内部类可以访问外部类的私有成员,同时我们可以将内部类从外部世界隐藏起来。
  3. 将小类放在顶层类内部使得代码更接近其使用位置,使代码更易读和易维护。

关于Java内部类就是这些。

Source:
https://www.digitalocean.com/community/tutorials/java-inner-class