浅析总结 Java 内部类的一些使用与梳理

========================================================

作者:qiujuer

博客:blog.csdn.net/qiujuer

网站:www.qiujuer.net

开源库:Genius-Android

转载请注明出处:http://blog.csdn.net/qiujuer/article/details/43282699

——学之开源,用于开源;初学者的心态,与君共勉!

========================================================

有这篇文章,纯属巧合;那天在使用中突然发现 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分钟~汗!!!!

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

不对的地方还请指正~~

========================================================

作者:qiujuer

博客:blog.csdn.net/qiujuer

网站:www.qiujuer.net

开源库:Genius-Android

转载请注明出处:http://blog.csdn.net/qiujuer/article/details/43282699

——学之开源,用于开源;初学者的心态,与君共勉!

========================================================

时间: 2025-01-09 11:43:25

浅析总结 Java 内部类的一些使用与梳理的相关文章

Java 内部类浅析

一.引言 由于目前是Android开发的实习生,在开发过程中发现越来越多自己知道但是真正去使用的时候却用不上的情况,比如内部类的使用上,所以在经过网上查找资料学习以及自己总结之后,特此发表一篇博文与大家分享,如有不当之处,万望指出. 二.内部类 内部类是指在一个外部类的内部再定义一个类,是一个编译时的概念,一旦编译成功,内部类与其外部类就会成为完全不同的两类,只是内部类的前面会冠以外部类的类名和$符号,如一个outer类内部定义了一个inner的内部类,那么编译完成后会生成outer.class

Java内部类

本文是<Java核心技术 卷1>中第六章接口与内部类中关于内部类的阅读总结. Java中的内部类(inner class)是定义在另一个类内部的类.那么内部类有什么用呢?这里主要由三个内部类存在的原因: 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据.即,如果类A中定义了类B,那么类B可以访问类A中的数据,甚至是私有数据,但类A不能访问类B中的私有数据: 内部类可以对同一个包中的其他类隐藏起来.在一个包中,定义一个类时,即使不加上访问权限关键词,这个类也是包内其他类可访问的,不

Java内部类:局部内部类(三)

Java内部类分为4个部分进行阐述,分别为概览.成员内部类.局部内部类和匿名内部类. 在本文中是Java内部类的局部内部类,主要讲局部内部类的概念和在使用局部内部的过程中,需要注意的一个细节. 1.局部内部类的概念 在一个类的方法内部定义另外一个类,那么另外一个类就称作为局部内部类. class OutterClass { void test() { class InnerClass//局部内部类 { } } } 在上述代码中,InnerClass定义在OutterClass的test方法的内部

Java内部类:匿名内部类(四)

Java内部类分为4个部分进行阐述,分别为概览.成员内部类.局部内部类和匿名内部类. 在本文中是Java内部类的匿名内部类,主要讲述匿名内部类的概念.匿名内部类的好处.匿名内部类的使用前提.和匿名内部类的应用场景. 1.匿名内部类的概念 没有类名的类就称作为匿名内部类 2.匿名内部类的好处 简化书写 3.匿名内部类的使用前提 必须存在继承或者实现关系才能使用 4.匿名内部类的应用场景 匿名内部类一般是用于实参 示例代码: package com.rk.innerclass; public cla

Java内部类小程序(成员内部类,静态内部类,匿名内部类)

1 /** 2 * 测试java内部类(成员内部类,静态内部类,匿名内部类) 3 * 局部内部类不常用,就不写了. 4 * @package :java05 5 * @author shaobn 6 * @Describe : 7 * @Time: 2015-9-6 下午8:32:38 8 */ 9 public class TestInner { 10 11 /** 12 * @author shaobn 13 * @Describe : 14 * @param args 15 * @Time

Java内部类的使用小结

内部类是指在一个外部类的内部再定义一个类.类名不需要和文件夹相同. *内部类可以是静态static的,也可用public,default,protected和private修饰.(而外部顶级类即类名和文件名相同的只能使用public和default). 注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类.对于一个名为outer的外部类和其内部定义的名为inner的内部类.编译完成后出现outer.class和outer$inner.class两类.所以内部类的成员变量/方法名可

java内部类和匿名内部类

内部类即是包含在类里面的又一个类. java内部类分为: 成员内部类.静态嵌套类.方法内部类.匿名内部类 . 内部类的共性 (1).内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 . (2).内部类不能用普通的方式访问.内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的 . (3).内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量 . 成员内部类

Java内部类的继承

Java内部类的构造器必须连接到指向其外围类对象的引用(构造内部类必须给它一个外部类对象的引用,内部类依赖于外部类对象),所以在继承内部类的时候,需要在导出类的构造器中手动加入对基类构造器的调用. 因为,在导出类实例化时,并不存在一个外围类对象,以让导出类的实例去连接到它. 所以,我们需要创建一个外围类,然后用一个特定的语法来表明内部类与外围类的关系. 在下例子中,需要给导出类InheritInner一个来自内部类的外围类中的引用.普通的继承,只需在导出类构造器中加入super();,而内部类则

【转】Java 内部类种类及使用解析

Java 内部类种类及使用解析 内部类Inner Class 将相关的类组织在一起,从而降低了命名空间的混乱. 一个内部类可以定义在另一个类里,可以定义在函数里,甚至可以作为一个表达式的一部分. Java中的内部类共分为四种: 静态内部类static inner class (also called nested class) 成员内部类member inner class 局部内部类local inner class 匿名内部类anonymous inner class 静态内部类Static