Java内部类是在另一个类的主体内定义的。Java内部类可以声明为private、public、protected或默认访问权限,而外部类只能具有public或默认访问权限。Java嵌套类分为两种。
-
静态嵌套类
如果嵌套类是静态的,则称为静态嵌套类。静态嵌套类只能访问外部类的静态成员。静态嵌套类与任何其他顶级类相同,仅为了包装方便而嵌套。可以使用以下语句创建静态类对象。
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
-
java 内部类
在 Java 中,任何非静态嵌套类都被称为内部类。Java 内部类与类的对象相关联,它们可以访问外部类的所有变量和方法。由于内部类与实例相关联,因此我们不能在其中有任何静态变量。Java 内部类的对象是外部类对象的一部分,要创建内部类的实例,我们首先需要创建外部类的实例。Java 内部类可以像这样实例化;
OuterClass outerObject = new OuterClass(); OuterClass.InnerClass innerObject = outerObject.new InnerClass();
-
本地内部类
如果一个类在方法体内定义,它被称为本地内部类。由于本地内部类与对象无关,我们不能使用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(); } }
-
匿名内部类
没有名称的局部内部类称为匿名内部类。匿名类在单个语句中定义并实例化。匿名内部类总是扩展一个类或实现一个接口。由于匿名类没有名称,因此无法为其定义构造函数。匿名内部类只能在定义它的位置访问。如何创建匿名内部类有点困难,我们将在下面的测试程序中看到它的实时用法。
下面是一个展示如何定义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内部类的优点
- 如果一个类只对一个类有用,将其嵌套并保持在一起是有意义的。它有助于打包类。
- Java内部类实现封装。请注意,内部类可以访问外部类的私有成员,同时我们可以将内部类从外部世界隐藏起来。
- 将小类放在顶层类内部使得代码更接近其使用位置,使代码更易读和易维护。
关于Java内部类就是这些。
Source:
https://www.digitalocean.com/community/tutorials/java-inner-class