Java 内部类是在另一个类的主体内定义的。Java 内部类可以声明为私有、公共、受保护或具有默认访问权限,而外部类只能具有公共或默认访问权限。
Java 嵌套类分为两种类型。
静态嵌套类
如果嵌套类是静态的,则称为静态嵌套类。静态嵌套类只能访问外部类的静态成员。静态嵌套类与任何其他顶级类相同,嵌套只是为了方便打包。
可以使用以下语句创建静态类对象。
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
java内部类
任何非静态嵌套类在 Java 中都称为内部类。Java内部类与类的对象相关联,可以访问外部类的所有变量和方法。
由于内部类与实例相关联,因此我们不能在其中包含任何静态变量。
java内部类的对象是外部类对象的一部分,要创建内部类的实例,首先需要创建外部类的实例。
Java内部类可以这样实例化;
OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
有两种特殊的 Java 内部类。
本地内部类
如果在方法体中定义了一个类,则它被称为局部内部类。
由于本地内部类不与 Object 关联,我们不能对它使用私有、公共或受保护的访问修饰符。唯一允许的修饰符是abstract 或final。
局部内部类可以访问其定义范围内的封闭类的所有成员和局部最终变量。此外,它还可以访问定义它的方法的非最终局部变量,但不能修改它们。因此,如果您尝试打印非最终局部变量的值,它将被允许,但是如果您尝试从方法局部内部类内部更改其值,则会出现编译时错误。
本地内部类可以定义为:
package com.journaldev.innerclasses;
public class MainClass {
private String s_main_class;
public void print() {
String s_print_method = "";
// local inner class inside the method
class Logger {
// able to access enclosing class variables
String name = s_main_class;
// able to access non-final method variables
String name1 = s_print_method;
public void foo() {
String name1 = s_print_method;
// Below code will throw compile time error:
// Local variable s_print_method defined in an enclosing scope must be final or effectively final
// s_print_method= ":";
}
}
// instantiate local inner class in the method to use
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();
}
// Below will throw error because of the scope of the class
//Test t = new Test();
//Foo f = new Foo();
}
}
匿名内部类
没有名字的局部内部类被称为匿名内部类。匿名类在单个语句中定义和实例化。
匿名内部类总是扩展一个类或实现一个接口。由于匿名类没有名称,因此不可能为匿名类定义构造函数。
匿名内部类只能在定义的地方访问。
定义如何创建匿名内部类有点困难,我们将在下面的测试程序中看到它的实时用法。
这是一个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 constructor
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;
}
//static nested class, can access OuterClass static variables/methods
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;
}
}
//inner class, non-static and can access all the variables/methods of the outer class
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;
}
}
//local inner class
public void print(String initial) {
//local inner class 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);
}
//anonymous inner class
public String[] getFilesInDir(String dir, final String ext) {
File file = new File(dir);
//anonymous inner class 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;
//nested classes can be used in import for easy instantiation
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);
//static nested classes example
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);
//inner class example
InnerClass innerClass = outer.new InnerClass();
System.out.println(innerClass.getName());
System.out.println(innerClass);
innerClass.setValues();
System.out.println(innerClass);
//calling method using local inner class
outer.print("Outer");
//calling method using anonymous inner class
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 内部类的好处
- 如果一个类只对一个类有用,那么将它嵌套在一起是有意义的。它有助于类的打包。
- Java 内部类实现封装。请注意,内部类可以访问外部类的私有成员,同时我们可以对外部世界隐藏内部类。
- 将小类保留在顶级类中会使代码更靠近使用它的地方,并使代码更具可读性和可维护性。
这就是java内部类的全部内容。