Java 编程语言允许一个类被定义在另一个类中,这样的类就称为嵌套类。嵌套类分为两种:静态的和非静态的。没有用 static 关键字来声明的嵌套类,就称为非静态嵌套类。用 static 关键字来声明的嵌套类,就称为静态嵌套类。
包含嵌套类的类,可称为外围类(Enclosing Class)或外部类(Outer Class)。非静态嵌套类可访问其外围类的其他成员,即使这些成员被声明为私有的。 若内部类作为其外部类的成员,则它可声明为 private、public、protected 或包私有的。
内部类是类的第五大成员→类的五大成员是哪些?[属性、方法、构造器、代码块、内部类]】
内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。
成员内部类在一个类里面作为类的一个字段直接定义就可以了
public class OuterClass {
public class InnerClass {
}
}
成员内部类对象可以访问外部类对象中所有访问权限的字段,同时,外部类对象也可以通过成员内部类的对象引用来访问内部类中定义的所有访问权限的字段
成员内部类是依附外部类而存在的,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。所以在外部类访问内部类的时候必须先实例化外部类对象
成员内部类可以使用四种权限修饰符进行修饰(四种权限修饰符:public(公有的) >protected(受保护的) > (default)(缺省/默认的) > private(私有的));
成员内部类中不能书写静态变量和方法。
public class OutClass01 {
public String outerName1="outerName1";
protected String outerName2="outerName2";
String outerName3="outerName3";
private String outerName4="outerName4";
public OutClass01() {
// 在外部类对象内部,直接通过 new InnerClass(); 创建内部类对象
InnerClass01 innerObj = new InnerClass01();
System.out.println("外部类的构造方法中创建 " + this.getClass().getSimpleName() + " 对象");
System.out.println("其内部类的 innerName1 字段的值为: " + innerObj.innerName1);
System.out.println("其内部类的 innerName2 字段的值为: " + innerObj.innerName2);
System.out.println("其内部类的 innerName3 字段的值为: " + innerObj.innerName3);
System.out.println("其内部类的 innerName4 字段的值为: " + innerObj.innerName4);
System.out.println();
}
public class InnerClass01 {
public String innerName1 = "innerName1";
protected String innerName2 = "innerName2";
String innerName3 = "innerName3";
private String innerName4 = "innerName4";
// Inner classes cannot have static declarations
// 编译错误!成员内部类中不能定义 static 属性
// static String innerName5 = "innerName5";
public InnerClass01() {
System.out.println("内部类的构造方法中创建 " + this.getClass().getSimpleName() + " 对象");
System.out.println("外部类 outerName1 字段为: " + outerName1);
System.out.println("外部类 outerName2 字段为: " + outerName2);
System.out.println("外部类 outerName3 字段为: " + outerName3);
System.out.println("外部类 outerName4 字段为: " + outerName4);
System.out.println();
}
}
public static void main(String[] args) {
OutClass01 outerObj = new OutClass01();
// 不在外部类内部,使用:外部类对象. new 内部类构造器(); 的方式创建内部类对象
//InnerClass01 innerObj01 =outerObj.new InnerClass01();
}
}
静态内部类是不需要依赖于外部类的,和类的静态成员属性有点类似
静态内部类中无法访问外部类的非静态成员,因为外部类的非静态成员是属于每一个外部类对象的,而本身静态内部类就是独立外部类对象存在。
外部类可以访问静态内部类对象的所有访问权限的成员,和成员内部类无异。
不能使用外部类的非static成员变量或者方法;
静态内部类中即能声明静态成员也可以声明非静态成员。
public class Outclass02 {
public static String outerName1 = "outerName1";
protected static String outerName2 = "outerName2";
static String outerName3 = "outerName3";
private static String outerName4 = "outerName4";
public String outerName5 = "outerName5";
public Outclass02() {
StaticClass innerObj=new StaticClass();
System.out.println("外部类的构造方法中创建 " + this.getClass().getSimpleName() + " 对象");
System.out.println("其内部类的 innerName1 字段的值为: " + innerObj.innerName1);
System.out.println("其内部类的 innerName2 字段的值为: " + innerObj.innerName2);
System.out.println("其内部类的 innerName3 字段的值为: " + innerObj.innerName3);
System.out.println("其内部类的 innerName4 字段的值为: " + innerObj.innerName4);
System.out.println();
}
public static void show(){
System.out.println("这是外部类的show方法");
}
public static class StaticClass {
public String innerName1 = "innerName1";
protected static String innerName2 = "innerName2";
String innerName3 = "innerName3";
private static String innerName4 = "innerName4";
public StaticClass() {
System.out.println("内部类的构造方法中创建 " + this.getClass().getSimpleName() + " 对象");
//静态内部类能访问外部类的静态成员以及方法
System.out.println("外部类 outerName1 字段为: " + outerName1);
System.out.println("外部类 outerName2 字段为: " + outerName2);
System.out.println("外部类 outerName3 字段为: " + outerName3);
System.out.println("外部类 outerName4 字段为: " + outerName4);
//静态内部类不能访问外部类的非静态成员
//System.out.println("外部类 outerName5 字段为: " + outerName5);
Outclass02.show();
System.out.println();
}
}
public static void main(String[] args) {
Outclass02 outclass02=new Outclass02();
//不需要依赖外部类
System.out.println("不需要外部类直接在main创建静态内部类对象");
StaticClass innerObj=new StaticClass();
}
}
匿名内部类有多种形式,其中最常见的一种形式莫过于在方法参数中新建一个接口对象 / 类对象,并且实现这个接口声明 并重写接口声明的方法,然后再创建一个这个匿名内部类的对象并赋值给前面的 Function01 类型的引用(见代码)。
外部类不能使用匿名内部类定义的属性,匿名内部类可以使用外部类的属性,因为外部类无法获取这个类的类名,无法得到属性信息。
匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
匿名内部类可用于给方法传递实参首先有一个接口,然后在使用的类中编写了一个方法,其参数类型是接口对象。调用此方法时构造一个接口对象传入,此时会自动生成一个此接口的子类(匿名内部类)实现接口中的方法。本质传入的类是匿名内部类。
// 实现关系下的匿名内部类:
interface Function01 {
void show();
}
interface Function02 {
void call();
}
class A {
public String outerName1="outerName1";
protected String outerName2="outerName2";
String outerName3="outerName3";
private String outerName4="outerName4";
public void InnerFun01(){
// 在这个过程中会新建一个匿名内部类对象,
// 这个匿名内部类实现了 Function01 接口并重写 show 方法
Function01 fun= new Function01(){
// 内部类中定义属性,只能在当前内部类中使用,
// 无法在外部类中使用,外部类获取不到匿名内部类的类名,
// 无法创建匿名内部类的对象
//出错 原因:内部类不能有静态声明
//public static String innerName2 = "innerName2";
public String innerName1 = "innerName1";
//实现子类 但是没有名字 所以叫匿名内部类
@Override
public void show() {
//在匿名内部类中可以使用外部类的属性
//无法获得对象因为是匿名内部类没有名字
System.out.println("内部类的构造方法中创建 " + this.getClass().getSimpleName() + " 对象");
System.out.println("外部类 outerName1 字段为: " + outerName1);
System.out.println("外部类 outerName2 字段为: " + outerName2);
System.out.println("外部类 outerName3 字段为: " + outerName3);
System.out.println("外部类 outerName4 字段为: " + outerName4);
System.out.println("这是一个show接口方法...");
}
};
fun.show();
}
//匿名内部类可用于给方法传递实参
public void InnerFun02(Function02 fun){
System.out.println();
System.out.println("匿名内部类可用于给方法传递实参");
fun.call();
}
}
public class Outclass03 {
public static void main(String[] args) {
A a = new A();
a.InnerFun01();
a.InnerFun02(new Function02() {
@Override
public void call() {
System.out.println("这是一个call方法");
}
});
}
}
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
局部内部类不可使用权限修饰符 静态(static)修饰符进行修饰 同局部变量相同。
局部内部类可以直接访问方法中的属性。
局部内部类使用较少其声明在一个方法体 / 一段代码块的内部,若不在定义类的定义域之内便无法使用。
局部内部类里可访问外部类对象的所有访问权限的字段,外部类却不能访问局部内部类中定义的字段,因为局部内部类的定义只在其特定的方法体 / 代码块中有效,出了定义域,定义就失效了。
public class OutClass04 {
public String outerName1="outerName1";
protected String outerName2="outerName2";
String outerName3="outerName3";
private String outerName4="outerName4";
public OutClass04() {
System.out.println("创建了 " + this.getClass().getSimpleName() + " 对象");
}
private void InnerClassTest() {
// 局部内部类 InnerClass01,只能在当前方法中使用
class InnerClass01 {
//Inner classes cannot have static declarations
// 编译错误!局部内部类中不能定义 static 字段
//private static String innerName4 = "innerName4";
public String innerName1 = "innerName1";
public InnerClass01() {
System.out.println("InnerClass01内部类的构造方法中创建 " + this.getClass().getSimpleName() + " 对象");
System.out.println("外部类 outerName1 字段为: " + outerName1);
System.out.println("外部类 outerName2 字段为: " + outerName2);
System.out.println("外部类 outerName3 字段为: " + outerName3);
System.out.println("外部类 outerName4 字段为: " + outerName4);
System.out.println();
}
}
InnerClass01 inner01 = new InnerClass01();
// InnerClass02 inner03 = new InnerClass02(); // 编译错误!不在类 InnerClass02 的定义域内,找不到类 InnerClass02,
if (true) {
// 局部内部类 InnerClass02,只能在当前代码块中使用
class InnerClass02 {
public InnerClass02() {
System.out.println("InnerClass02内部类的构造方法中创建 " + this.getClass().getSimpleName() + " 对象");
System.out.println("外部类 outerName1 字段为: " + outerName1);
System.out.println("外部类 outerName2 字段为: " + outerName2);
System.out.println("外部类 outerName3 字段为: " + outerName3);
System.out.println("外部类 outerName4 字段为: " + outerName4);
System.out.println();
}
}
InnerClass02 inner02 = new InnerClass02();
}
}
public static void main(String[] args) {
OutClass04 outObj = new OutClass04();
outObj.InnerClassTest();
}
}
内部类的嵌套,即为内部类中再定义内部类,类只能实现单个的类继承,而使用内部类的嵌套,在一个外部类中不同的内部类可以继承不同的类,从而相当于一个类实现了多重继承。以下代码是使用普通内部类进行演示。
class Father {
public String str1(){
return "我是爸爸类";
}
}
class Mother {
public String str2(){
return "我是妈妈类";
}
}
class Son {
//普通内部类Father_1继承Father
class Father_1 extends Father{
public String str1(){
//调用父类的方法并加上一个字符串
return super.str1() + 888;
}
}
//普通内部类Mother_1继承Mother
class Mother_1 extends Mother{
public String str2(){
//调用父类的方法并加上一个字符串
return super.str2() +999;
}
}
public String getstr1(){
return new Father_1().str1();
}
public String getstr2(){
return new Mother_1().str2();
}
}
public class OutClass05 {
public static void main(String[] args) {
Son son = new Son();
System.out.println( son.getstr1());
System.out.println( son.getstr2());
}
}