Java内部类(一)类级别内部类的可视性

JAVA类成员访问权限

表1-1所示,不详述,这里列出方便下文引用。

修饰词本类同一包类子类其他类
private
default
protected
public

内部类基本知识点

我们首先看一个内部类的例子,并借助javap工具观察编译器对内部类的处理方式。代码1-1如下:

package df;

public class OuterClassTest1 {
	private String outer;

	public class InnerClassTest1 {
		private int inner;

		public InnerClassTest1(int p){
			this.inner = p;
		}

		public void access(){
			System.out.println(outer);
			System.out.println(inner);
		}
	}
	
	public static void main(String[] args){
		OuterClassTest1 outerClass = new OuterClassTest1();
		//外部类的静态方法创建内部类的时候,不需要指定具体类型
		InnerClassTest1 innerClass1 = outerClass.new InnerClassTest1(1);
		//除外部类外,其他地方创建内部类对象需要指定具体类型
		OuterClassTest1.InnerClassTest1 innerClass2 = outerClass.new InnerClassTest1(1);
	}
}

javap查看编译结果如图1-1

输入图片说明

  • 编译器为内部类添加了指向外部类对象的引用this$0,通过构造函数初始化。因此创建内部类时,需要首先创建外部类对象,然后再创建内部类对象。
  • 编译器为外部类添加了access$0静态方法,猜测应该是当内部类access方法访问外部类成员变量outer时,内部类会调用access$0方法并传参this$0,然后访问到outer的值。编译器通过向外部类添加静态成员方法,实现了内部类对外部类所有成员的访问权,更准确的说是间接访问权。
  • 除外部类外,任何地方创建内部类对象,需要指定内部类的具体类型:OuterClassTest1 .InnerClassTest1。

注:java编程思想对这一知识点描述有所不同:

If you want to make an object of the inner class anywhere except from within a non-static method of the outer class, you must specify the type of that object as OuterClassName.InnerClassName.

但从代码1-1可以看出,外部类的静态方法也可以不用前缀OuterClassName.。

  • this$0变量对源码不可见,内部类访问外部类对象引用方法:OuterClassTest1.this。
  • 除外部类的非静态方法,其他地方创建内部类方法:OuterClassObject.new。

内部类可见性

本小节我们讨论一下当不同访问权限修饰符(private、default、protected、public)作用于内部类时,内部类对外可视性。代码1-2如下:

package df;

public class OuterClassTest {
	
	private class PrivateInnerClass{
		private void private_method() {
		};

		void default_method() {
		};

		protected void protected_method() {
		};

		public void public_method() {
		};
	}

	class DefaultInnerClass{
		private void private_method() {
		};

		void default_method() {
		};

		protected void protected_method() {
		};

		public void public_method() {
		};
	}

	protected class ProtectedInnerClass{
		private void private_method() {
		};

		void default_method() {
		};

		protected void protected_method() {
		};

		public void public_method() {
		};
	}

	public class PublicInnerClass{
		private void private_method() {
		};

		void default_method() {
		};

		protected void protected_method() {
		};

		public void public_method() {
		};
	}
}

决定内部类可视性的因素

创建内部类的方法是:OuterClass.InnerClass obj = OuterClassObject.new InnerClass()。因此能否成功创建内部类对象,依赖两方面的可视性:

  • OuterClass.InnerClass类型的可视性,由内部类的修饰符决定。如PrivateInnerClass由private修饰,则决定了只有外部类可以创建PrivateInnerClass类型对象。
  • InnerClass的构造函数的可视性,可以显示声明构造函数并指定权限修饰符,也可以由编译器默认生成。默认构造函数的修饰符和类的修饰符一致,如PrivateInnerClass类的默认构造函数的修饰符就是private。我们可以借助于javap -p 查看默认构造函数,如下图1-2

输入图片说明

外部类访问内部类

代码1-3

package df;

public class OuterClassTest {
//...省略代码
public static void main(String[] args) {
		OuterClassTest out = new OuterClassTest();

		PrivateInnerClass privateIn = out.new PrivateInnerClass();
		privateIn.private_method();
	}
}
  • private内部类仅对外部类可见,外部类可以访问内部类的所有成员,包括私有成员。同样default\protected\public内部类对外部类都完全可见。

相同包的类对内部类的访问

代码1-4

package df;

public class SamePackage {
    public static void main(String[] args) {
       OuterClassTest out = new OuterClassTest();
     
       //ERROR
       //OuterClassTest.PrivateInnerClass privateIn = out.new PrivateInnerClass();
       
       OuterClassTest.DefaultInnerClass defaultIn = out.new DefaultInnerClass(); 
       //ERROR
       //defaultIn.private_method();
       defaultIn.default_method();
 
       
    }
}
  • 除外部类外,private内部类对其他类不可见。
  • default内部类可以被相同包下的类访问,对default内部类对象成员的访问遵从开头JAVA类成员访问权限,即可以访问内部类default/protected/public修饰的成员,但不能访问private修饰的成员。

外部类的子类

代码1-5

package test;

import df.OuterClassTest;

public class OtherPackage extends OuterClassTest{
    public static void main(String[] args){
    	OuterClassTest out = new OuterClassTest();
    	
    	//ERROR
    	//OuterClassTest.DefaultInnerClass defaultIn = out.new DefaultInnerClass(); 
    	
    	//ERROR
    	//OuterClassTest.ProtectedInnerClass protectedIn = out.new ProtectedInnerClass();
    	
     }
 }

  • 尽管OtherPackage 是外部类的子类,因处于不同的包下,无法创建default内部类DefaultInnerClass。
  • ProtectedInnerClass对象创建失败的原因是:ProtectedInnerClass的默认构造函数是protected的,OtherPackage继承OuterClassTest只能保证OuterClassTest.ProtectedInnerClass的可视性,不能保证ProtectedInnerClass构造函数的可视性,如果想让上述代码创建成功,可以显示声明ProtectedInnerClass的构造函数,并且用public修饰。

转载于:https://my.oschina.net/arvinzhao/blog/830941

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值