Java 内部类 收集整理

时间:2022-12-28 17:59:21


一.什么是内部类,

1.内部类是指在一个外部类的内部再定义一个类。
2.定义在一个类内部的类叫内部类,包含内部类的类称为外部类。

3.内部类的优缺点:
缺点:正常的一个类操作时,在类中最好只定义属性或方法。如果定义一个类的话,则肯定破坏了程序的结果。代码增加了,而且复杂度也增加了。
优点:使用内部类最大的优点:可以方便的访问外部类中的私有属性。


二.出现内部类的原因
真正的原因是这样的,java中的内部类和接口加在一起,可以的解决常被C++程序员抱怨java中存在的一个问题:没有多继承。实际上,C++的多继承设计起来很复杂,而java通过内部类加上接口,可以很好的实现多继承的效果。
 
内部类的第二个好处 一个内部类对象可以访问创建它的外部类对象的内容,甚至包括私有变量!这是一个非常有用的特性,为我们在设计时提供了更多的思路和捷径。要想实现这个功能,内部类对象就必须有指向外部类对象的引用。Java编译器在创建内部类对象时,隐式的把其外部类对象的引用也传了进去并一直保存着。这样就使得内部类对象始终可以访问其外部类对象,同时这也是为什么在外部类作用范围之外向要创建内部类对象必须先创建其外部类对象的原因。

JAVA内部类还有一个作用,那就是实现JAVA的多继承。JAVA本身是不允许多继承的,如果我们想一个类继承多个基类,就可以使用内部类。通过内部类分别继承一个基类,外部类创建内部类的对象,并使用内部类的方法,变相地实现了多继承。
 
 
 三.需要注意的地方:
1.内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。所以内部类的成员变量/方法名可以和外部类的相同。

2.内部类可以声明public、protected、private等访问限制(而外部*类即类名和文件名相同的只能使用public和default),可以声明为abstract的供其他内部类或外部类继承与扩展,或者声明为static、final的,也可以实现特定的接口。static的内部类行为上象一个独立的类,非static在行为上类似类的属性或方法且禁止声明static的方法。内部类可以访问外部类的所有方法与属性,但static的内部类只能访问外部类的静态属性与方法。

3.类名不需要和文件夹相同。


四.内部类分类
内部类主要有以下几类:成员内部类、局部内部类、静态内部类、匿名内部类
将静态内部类和成员内部类分别类比成静态的和非静态的成员变量或者方法

1.静态内部类(Static  Inner Class)
定义:
嵌套内部类,就是修饰为static的内部类。声明为static的内部类,不需要内部类对象和外部类对象之间的联系,就是说我们可以直接引用outer.inner,即不需要创建外部类,也不需要创建内部类。
嵌套类和普通的内部类还有一个区别:普通内部类不能有static数据和static属性,也不能包含嵌套类,但嵌套类可以。而嵌套类不能声明为private,一般声明为public,方便调用。

特点:
只能访问外部类的静态方法和成员变量,
生成实例的方式为:OutterClass.InnerClass instance = new OutterClass.InnerClass(Constructor params);

2.成员内部类(Member Inner Class)
定义;
成员内部类,就是作为外部类的成员,可以直接使用外部类的所有成员和方法,即使是private的。同时外部类要访问内部类的所有成员变量/方法,则需要通过内部类的对象来获取。

注意:
要注意的是,成员内部类不能含有static的变量和方法。因为成员内部类需要先创建了外部类,才能创建它自己的。
解释:普通的内部类对象隐含地保存了一个引用,指向创建它的外围类对象。
Java编译器在创建内部类对象时,隐式的把其外部类对象的引用也传了进去并一直保存着。这样就使得内部类对象始终可以访问其外部类对象,同时这也是为什么在外部类作用范围之外向要创建内部类对象必须先创建其外部类对象的原因。

特点:
可以访问外部类的任何方法和成员变量,
生成实例的方式为:OutterClass.InnerClass instance = outterInstance.new InnerClass(Constructor params);
在内部类中使用this.member访问的是内部类自己的成员变量;
访问被内部类覆盖的外部类成员变量:
使用outer.this来表示外部类对象;
而需要创建内部类对象,可以使用outer.inner  obj = outerobj.new inner();
OutterClass.this.member
不能使用静态方法或者变量

3.局部内部类(Local Inner Class)
定义:局部内部类,是指内部类定义在方法和作用域内(甚至一个代码块之内)

特点:
定义在方法、语句块儿中,只能被修饰符Abstract、Final修饰,只能访问final的局部变量

4.匿名内部类(Anonymous Inner Class)
是局部内部类的特殊情况
没有修饰符,不能继承、或者实现接口、没有构造方法
会隐式的去继承一个类或者实现一个接口

5.什么情况下需要使用匿名内部类?如果满足下面的一些条件,使用匿名内部类是比较合适的:

  ·只用到类的一个实例。
  ·类在定义后马上用到。
  ·类非常小(SUN推荐是在4行代码以下)
  ·给类命名并不会导致你的代码更容易被理解。
  在使用匿名内部类时,要记住以下几个原则:
  ·匿名内部类不能有构造方法。
  ·匿名内部类不能定义任何静态成员、方法和类。
  ·匿名内部类不能是public,protected,private,static。
  ·只能创建匿名内部类的一个实例。
·一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
  ·因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。

6.为什么匿名内部类你们使用的外部类变量都必须是final的?
当所在的方法的形参需要被内部类里面使用时,该形参必须为final。这里可以看到形参name已经定义为final了,而形参city 没有被使用则不用定义为final。为什么要定义为final呢?
这是一个编译器设计的问题,如果你了解java的编译原理的话很容易理解。 
首先,内部类被编译的时候会生成一个单独的内部类的.class文件,这个文件并不与外部类在同一class文件中。
当外部类传的参数被内部类调用时,从java程序的角度来看是直接的调用例如: 

public void dosome(final String a,final int b){ 

  class Dosome{public void dosome(){System.out.println(a+b)}}; 

  Dosome some=new Dosome(); 

  some.dosome(); 

从代码来看好像是那个内部类直接调用的a参数和b参数,但是实际上不是,在java编译器编译以后实际的操作代码是 

class Outer$Dosome{ 

  public Dosome(final String a,final int b){ 

  this.Dosome$a=a; 

  this.Dosome$b=b; 

  public void dosome(){ 

  System.out.println(this.Dosome$a+this.Dosome$b); 

}} 

从以上代码看来,内部类并不是直接调用方法传进来的参数,而是内部类将传进来的参数通过自己的构造器备份到了自己的内部,自己内部的方法调用的实际是自己的属性而不是外部类方法的参数。 

这样理解就很容易得出为什么要用final了,因为两者从外表看起来是同一个东西,实际上却不是这样,如果内部类改掉了这些参数的值也不可能影响到原参数,然而这样却失去了参数的一致性,因为从编程人员的角度来看他们是同一个东西,如果编程人员在程序设计的时候在内部类中改掉参数的值,但是外部调用的时候又发现值其实没有被改掉,这就让人非常的难以理解和接受,为了避免这种尴尬的问题存在,所以编译器设计人员把内部类能够使用的参数设定为必须是final来规避这种莫名其妙错误的存在。”

 (简单理解就是,拷贝引用,为了避免引用值发生改变,例如被外部类的方法修改等,而导致内部类得到的值不一致,于是用final来让该引用不可改变)

五:思考
1.内部类的继承,是指内部类被继承,普通类 extents 内部类。
2.内部类种嵌套内部类
3. 为什么外部类可以创建内部类的对象?并且内部类能够方便的引用到外部类对象? 静态内部类只能访问其外围类的静态成员?(可通过Java 反射机制查看)