java内部类的一些使用与梳理-mile米乐体育

有这篇文章,纯属巧合;那天在使用中突然发现 java 内部类中还分 static ,说实话平时都在用,但是就是没有注意到;感觉有必要总结一下。

有必要说一下的是本文纯属浅析,如有补充还请在评论中指出,欢迎总结。

内部类的位置

public class a { 	class b {  	}  	public void pint() { 		class c { 		} 		new c(); 	}  	public void pint(boolean b) { 		if (b) { 			class d { 			} 			new d(); 		} 	} }

从代码中可以看出,内部类可以定义到很多地方,常用的是成员变量中(b),方法中也叫局部内部类(c),作用域中(d)

从上面来看似乎没有用到过在方法中和作用域中的情况啊,这就错了;再来看看这个:

public interface ainterface { 	void show(); } public class b {  	public void show() { 		class man implements ainterface { 			@override 			public void show() {  			}  		} 		man man = new man(); 		man.show(); 	}  }

其中我们定义了两个文件,一个文件是一个接口类,一个是b文件;在b类中,的 show()方法中我们使用了局部内部类的方式创建了类 man ,man class继承接口并实现方法,随后使用该类。

内部类的权限

为什么要有内部类的存在?

在我看来类主要的就是封装、继承、多态;当然其中的回调思想我认为是很重要的;而内部类的出现就是为了简化多重继承的问题;一个a类,并不能继承多个其他类,但是在使用中又需要使用到其他类的方法,这个时候内部类就发挥作用了;典型的就是事件点击的回调实现。

那么内部类的权限究竟有多大?

至于答案是什么,代码上看看就知道了。

public class c { 	int a = 1; 	private int b = 2; 	protected int c = 3; 	public int d = 4;  	void a() { 		system.out.println("a:"   a); 	}  	private void b() { 		system.out.println("b:"   b); 	}  	protected void c() { 		system.out.println("c:"   c); 	}  	public void d() { 		system.out.println("d:"   d); 	}  	class d {  		void show() { 			int max = a   b   c   d; 			a(); 			b(); 			c(); 			d(); 			system.out.println("max:"   max); 		} 	}  	public static void main(string[] args) { 		d d = new c().new d(); 		d.show(); 	} }

运行结果:

可以看出,内部类 d 对类 c 具有完整的访问权限,等于全身脱光了给你看。

那要是反过来呢?

public class c { 	class d { 		private int a = 20; 		private void a(){ 			system.out.println("d.a:"   a); 		} 	}  	void show(){ 		d d = new d(); 		d.a();  		system.out.println("d.a:"   d.a); 	}  	public static void main(string[] args) { 		new c().show(); 	} }

运行结果:

可见也是完全可行的,也能直接访问私有属性 私有方法,在这里似乎私有的限制已经失效了一般,这个让我想起了以前看见过一个面试:在 java 中 private 修饰何时会失效。

这完全是两个人互相脱光光了啊~

匿名内部类

这个非常常见,特别是在按钮点击事件绑定中。

public class d { 	void initbutton() { 		button b1 = new button(); 		b1.setonclicklistener(new onclicklistener() {  			@override 			public void onclick(button v) {  			} 		});  		button b2 = new button(); 		b2.setonclicklistener(new onclicklistener() {  			@override 			public void onclick(button v) {  			} 		}); 	}  }

其中的:

    new onclicklistener() {  			@override 			public void onclick(button v) {  			} 		}

就是匿名内部类的使用方式,onclicklistener 是一个接口类,接口类是无法直接new 一个实例的;这里也并不是那样,而是new 了一个其他的类,该类是匿名的,也就是没有名字,只不过该类实现了 onclicklistener接口类中的方法。

上面的添加回调部分可等同于:

public class d { 	void initbutton1() { 		button b1 = new button(); 		b1.setonclicklistener(new listener1());  		button b2 = new button(); 		b2.setonclicklistener(new listener2()); 	}  	class listener1 implements onclicklistener {  		@override 		public void onclick(button v) {  		} 	}  	class listener2 implements onclicklistener {  		@override 		public void onclick(button v) {  		} 	}  }

这里就是先建立类,继承自接口;而后赋值到 button 中。

要说两者的区别与好处,这个其实看具体的使用情况吧;如果你的按钮很多,但是为了避免建立太多类;那么可以建立一个回调类,然后都赋值给所有的按钮,不过最后就是需要在 onclick方法中进行判断是那个按钮进行的点击。

匿名内部类的使用地方很多;具体的使用应视使用情况而定~

静态内部类/静态嵌套类

这个其实并不应该叫做内部类了,因为其并不具备内部类的完全权限,在使用上与一般的类基本一样;那为什么会有这个的存在?

在我看来这个类的存在是为其包括类服务;意思是可以单独服务,不被外面的类所知晓;如这样:

public class e { 	private void show(){ 		new a(); 	}  	private static class a{  	} }

其中类 a 使用了 static ,所以是静态嵌套类,在这里使用private 修饰;那么该类只能在 e 类中进行实例化;无法在 其他文件中实例化。

这样的情况使用外面的类能行么?不行吧?也许你会说在 e.java 文件夹中建立 a.java ,并使用protected修饰;但是在同样的包下,或者继承的类中同样能访问了;这也只是其中一个较为特殊的情况。

我们来看看权限

public class e { 	int a1 = 0; 	private int a2 = 0; 	protected int a3 = 0; 	public int a4 = 0;  	private void show(){ 		a a =new a(); 		system.out.print("b1:" a.b1); 		system.out.print("b2:" a.b2); 		system.out.print("b3:" a.b3); 		system.out.print("b4:" a.b4);  	}  	private static class a{ 		int b1 = 0; 		private int b2 = 0; 		protected int b3 = 0; 		public int b4 = 0;  		private void print(){ 			system.out.print("a1:" a1); 			system.out.print("a2:" a2); 			system.out.print("a3:" a3); 			system.out.print("a4:" a4);  		} 	} }

在这个中的结果是怎样?

从图片中可以看出,其权限级别是单方向的;静态嵌套类 a 对其包含类 e 完全透明;但 e 并不对 a 透明。

再来看看方法:

可以看出同样的情况;这个是为什么呢?为什么就是多一个 static 的修饰就这么完全不同?其是很好理解,两个独立的类;本来就无法直接使用,必须有引用才能调用其属性与方法。

我们或许可以这么调整一下就ok

public class e { 	int a1 = 0; 	private int a2 = 0; 	protected int a3 = 0; 	public int a4 = 0;  	private void show() { 		a a = new a(); 		system.out.print("b1:"   a.b1); 		system.out.print("b2:"   a.b2); 		system.out.print("b3:"   a.b3); 		system.out.print("b4:"   a.b4);  		a.b1(); 		a.b2(); 		a.b3(); 		a.b4(); 	}  	void a1() {  	}  	private void a2() {  	}  	protected void a3() {  	}  	public void a4() {  	}  	private static class a { 		int b1 = 0; 		private int b2 = 0; 		protected int b3 = 0; 		public int b4 = 0;  		void b1() {  		}  		private void b2() {  		}  		protected void b3() {  		}  		public void b4() {  		}  		private void print(e e) { 			system.out.print("a1:"   e.a1); 			system.out.print("a2:"   e.a2); 			system.out.print("a3:"   e.a3); 			system.out.print("a4:"   e.a4);  			e.a1(); 			e.a2(); 			e.a3(); 			e.a4(); 		} 	} }

在其静态类中传递一个 e 的引用进去就能解决问题了:

可以看出其中现在并没有报错了;能正常运行。

两者之间的隐藏区别

但是最开始上面的内部类是怎么回事?难道是闹鬼了?上面的内部类没有传递引用的啊;为啥加上一个 static 就不行了?

在这里我们需要看看字节码,我们先建立一个简单的内部类:

public class f {  	class a{  	} }

这个够简单吧?别说这个都难了;汗~

然后我们找到 class 文件,然后查看字节码:

在这里分别查看了 f 类的字节码和 f$a 类的字节码。

其中有这样的一句: final f this$0; 这句是很重要的一句,这句出现的地方在其内部类中,意思是当你 new 一个内部类的时候就同时传递了当前类进去;所以在内部类中能具有当前类的完全权限,能直接使用所有的东西;就是因为在隐藏情况下已经传递了当前类进去。

那么我们再看看一个简单的静态内部类:

public class g { 	static class a {  	} }

与上面的区别唯一就是在于添加了一个 static 。此时我们看看字节码:

可以看出其中无论是 g 类,还是 g$a 类的初始化中都没有其他多余的部分,也没有进行隐藏的传递进去当前类;所以这样的情况下并不具备访问权限,需要我们传递引用进去,可以通过接口也可以完全传递进去,具体取决于个人。所以加了static类的内部类除了在权限上比一般的类更加开放(与其包含类)外,与一般的类在使用上是一样的;所以准确的说应该叫做静态嵌套类。

初始化的区别

一个类中,同时包含了内部类与静态内部类,那么其初始化应该是怎么样的呢?

都是直接 new ?还是看看代码:

public class h { 	int a = 1;  	public class a { 		public void show() { 			system.out.print("a:"   a); 		} 	}  	public static class b { 		public void show(h h) { 			system.out.print("a:"   h.a); 		} 	}  	public static void main(string[] args) { 		h h = new h(); 		//a a = new a(); 		a a1 = h.new a(); 		b b = new b(); 		//b b1 = h.new b(); 		b b3 = new h.b(); 	} }

其中注释了的两种方式是不允许的方式,也就是无法正常运行。

a 因为有一个隐藏的引用,所以必须是h 的实例才能进行初始化出a 类;而b 类则是因为是在h 类中以静态方式存在的类,所以需要 new h.b();之所以能直接使用new b(),与该 main 方法在 h 类中有关,因为本来就在 h类中,所以直接使用 h类的静态属性或者方法可以不加上:“h.”  在前面。

内部类的继承

直接继承的情况:

可以看出报错了,为什么?因为需要传递一个 h 类进去,所以我们在继承的时候需要显示的指明:

public class i extends h.a{ 	public i(h h){ 		h.super(); 	} }

也就是在构造方法中,传递一个 h 的引用进去,并调用 h 实例的 super() 方法,才能进行实例化。

使用的话应该这样:

public static void main(string[] args) {         h h = new h();         i i = new i(h);     }

而,如果是继承其静态嵌套类,则不需要这样:

public class j extends h.b{  }

就这样就ok。

哎,差不多了~~整个内部类的东西差不多就是这些了,写了我3个小时42分钟~汗!!!!

如果有没有写到的地方,还请补充~~

不对的地方还请指正~~

展开全文
内容来源于互联网和用户投稿,文章中一旦含有米乐app官网登录的联系方式务必识别真假,本站仅做信息展示不承担任何相关责任,如有侵权或涉及法律问题请联系米乐app官网登录删除

最新文章

网站地图