前言

          学习Java已经有一段日子了,最近的日子笔者在重新对java进行再学习。不过这个阶段的学习

    笔者不会再着眼于具体的语法哪些细枝末节的东西了,这个阶段的学习中笔者将会对以前学习的

    模糊的,遗漏的知识概念做一些相关性的总结。今天,恰好看到内部类这块了,记得以前对内部类

    的使用就有一些模糊,因此专门就内部类做一些总结。

      内部类概念

               所谓内部类就是指在一个外部类中再定义一个类(内部类),这样内部类就作为一个成员依附于

          外部类而存在。不过在使用内部类的时候需要注意的是内部类可以static,protect,private,但是

          外部类只能使用public和缺省的包访问权限.

            若非这两种编译出错: 

            Illegal modifier for the class Outer; only public, abstract & final are permitted  

package com.kiritor; public class Outer { 	private String type;  	public String getType() { 		return type; 	}  	public void setType(String type) { 		this.type = type; 	}  	class Inner { 		private String type;  		public String getType() { 			return type; 		}  		public void setType(String type) { 			this.type = type; 		}  	} } 

      内部类的意义

                 简单看来内部类好像就是一种代码隐藏机制:将类至于其他类的内部.不过内部类远不止这样

          它了解外部类,能够和外部类进行必要的通信。

                  1、封装一些别人不想知道的操作.

                  2、内部类可以访问创建它的外部类对象的内容,甚至包括了private的变量.

            内部类同样可以实现接口,继承基类,这使得java中的多继承变得完整.。我们可以使用内部类

            的方式模拟出多继承的效果。

                 通过内部类继承基类,外部类创建内部类对象,并使用内部类提供的方法,这样就变相的实现了

           多继承的效果.

public class Graduate{           private Graduate_stu  gaduate_stu= new Graduate_stu();           private Graduate_emp  graduate_emp = new Graduate_emp();           private class Graduate_stu  extends Student{                public void getName() {               ....          }       }           private class Graduate_emp extends Employee{                public double getMoney()             {                 return 0.0;              }     }           public void getName() {           gaduate_stu.getName();       }           public double getMoney() {           graduate_emp .getMoney();       }   }  
            只是用代码简单的模拟了一下!
                 内部类还有一个颇具吸引力的特点,那就是内部类和外部类对于接口的继承是"分离"的

            相互不存在影响的,基于现实的情况,有时候我们实现一个接口,但是接口的方法在此类

            中已经有定义了,对于这种情况,我们就可以使用内部类实现该接口,实现其方法,因为内

           部类对于外部类的成员是可访问的,因此使用内部类的方法就解决可该问题。

        内部类的分类

                   我们现在知道内部类是放在外部类中的,根据内部类不同的"位置"和特性,内部类可以

             分为以下几类:

                           ●  成员内部类

                           ●  局部内部类

                           ●  静态内部类(嵌套类)

                           ●  匿名内部类

               对于其具体的特性和用法下面介绍

           成员内部类

             内部类作为外部类的一个成员存在,与外部类的方法,属性并列.                    

package com.kiritor; public class Outer { 	private String type="Outer Class"; 	private static int flag = 1;  	public String getType() { 		return type; 	}  	public void setType(String type) { 		this.type = type; 	} 	@Override 	public String toString() { 		System.out.println(""+getType()+":"+this.flag); 		Inner inner = new Inner(); 		inner.toString();//外部类的非静态方法访问内部类的方法 		//外部类的静态方法访问与其是一样的,不做演示了. 		return super.toString(); 	}  	class Inner { 		private String type="Inner Class";         private   int flag=2;//这里成员内部类中不允许定义静态成员 		public String getType() { 			return type; 		}  		public void setType(String type) { 			this.type = type; 		} 		public String toString() { 			System.out.println(""+getType()+":"+this.flag); 			System.out.println(""+Outer.this.getType()+Outer.this.flag);//若有变量重名,通过此种方式访问 			return super.toString(); 		} 		 		 	} 	public static void main(String[] args) { 		Outer outer = new Outer(); 		outer.toString(); 		Outer.Inner inner = outer.new Inner();//通过此种方式new inner 		inner.toString(); 	} } 
            

              Tips:在创建一个内部类的时候除非你已经有了一个外部类对象,否则不可能生成

                 方法内部类对象,因为内部类对象会悄悄的链接到创建他的外部类的对象,没有外部类对象

             自然也就不可能生成内部类对象了,不过还需注意的是内部类是一个在编译时的概念,一旦编译

             通过,就会成为完全不同的两个类,也就是会出现Outer,class和Outer$Inner,class两个字节码

             文件。

          

              局部内部类

                   在方法中定义的内部类称为局部内部类.它与局部变量类似,因此局部内部类是不能有访问

           修饰符的,因为它不是外部类成员,但是他可以访问当前方法中的代码块的常量,和外部类的所有

          成员.

package com.kiritor;  public class Outer { 	private String type = "Outer Class"; 	private static int flag = 1;  	public String getType() { 		return type; 	}  	public void setType(String type) { 		this.type = type; 	}  	@Override 	public String toString() { 		System.out.println("" + getType() + ":" + this.flag); 		return super.toString(); 	}  	public void innerInfo() { 		final String innerFinal = "可以访问方法体内的常量"; 		class Inner { 			private String type = "Inner Class"; 			private int flag = 2;// 这里成员内部类中不允许定义静态成员  			public String getType() { 				return type; 			}  			public void setType(String type) { 				this.type = type; 			}  			public String toString() { 				System.out.println("" + getType() + ":" + this.flag 						+ innerFinal); 				System.out.println("" + Outer.this.getType() + Outer.this.flag);// 若有变量重名,通过此种方式访问 				return super.toString(); 			}  		} 		new Inner().toString();//注意是通过这种方式调用内部类的方法的! 	}  	public static void main(String[] args) { 		Outer outer = new Outer(); 		outer.toString(); 		outer.innerInfo(); 	} } 

          静态内部类(嵌套类)

                 前面两种内部类和变量类似,这里的变量就是成员变量,和局部变量,可以参照进行对比

              如果你不需要内部类对象与其外部类对象之间有联系,那你可以将内部类声明为static的,这就

              是静态内部类.我们需要明白的是:普通的内部类对象隐含的保存了一个外部类对象的引用

                   但是当内部类为static的时候这种“特性”也就没有了,这意味着:

                         1、创建静态内部类对象的时候并不需要外部类对象

                         2、不能通过静态内部类对象访问非静态的外部类对象了。

              看例子:

package com.kiritor;  public class Outer {     private String type = "Outer Class";     private static int flag = 1;      public String getType() {         return type;     }      public void setType(String type) {         this.type = type;     }      @Override     public String toString() {         System.out.println("" + getType() + ":" + this.flag);         Inner.info();//外部类访问内部类的静态成员:内部类.静态成员(静态方法)         Inner inner = new Inner();//这里生成一个内部类对象不再需要通过外部类对象了         inner.toString();//外部类访问静态内部类的非静态成员或方法必须new一个对象         System.out.println(inner.type);         return super.toString();     }      static class Inner {             private String type = "Inner Class";             private int flag = 2;             private static String info="Inner Class 2";             //静态内部类中可以有非静态方法、属性             public String getType() {                 return type;             }              public void setType(String type) {                 this.type = type;             }              public  static void info()             {                 System.out.println(info);             }             public String toString() {                 System.out.println("" + getType() + ":" + this.flag                         );                 //System.out.println("" + Outer.getType() + Outer.this.flag);// 若有变量重名,通过此种方式访问                 return super.toString();             }          }      public static void main(String[] args) {         Outer outer = new Outer();         outer.toString();              } }  
                可以看出的是:生成一个内部类对象不再需要通过一个外部类对象了,这也是静态内部类和

        成员内部类的区别:Outer.Inner in = new Outer.Inner();

           匿名内部类

             简单的说匿名内部类就是没有名字的类了,这在GUI编程里面是较为常见的,给个例子:

             

package com.kiritor;  import java.awt.event.MouseEvent; import java.awt.event.MouseListener;  import javax.swing.JButton; import javax.swing.JFrame;  public class MyFrame extends JFrame{ 	private JButton button = null; 	public MyFrame() { 		this.setSize(200, 200); 		this.setVisible(true); 		button = new JButton("匿名内部类"); 		button.addMouseListener(new MouseListener() {//一个匿名的类 			 			@Override 			public void mouseReleased(MouseEvent e) { 				// TODO Auto-generated method stub 				 			} 			 			@Override 			public void mousePressed(MouseEvent e) { 				// TODO Auto-generated method stub 				 			} 			 			@Override 			public void mouseExited(MouseEvent e) { 				// TODO Auto-generated method stub 				 			} 			 			@Override 			public void mouseEntered(MouseEvent e) { 				// TODO Auto-generated method stub 				 			} 			 			@Override 			public void mouseClicked(MouseEvent e) { 				// TODO Auto-generated method stub 				 			} 		}); 		this.add(button); 		 		 	}      } 
          对于匿名内部类,笔者现就不做总结了,之后会找个时间理解一下.

          内部类的相关问题

                    下面讨论的是内部类中的一些有趣的问题!

                         内部类能否被"重载"、“继承”?

               内部类重载问题

                       假设如果你创建了一个外部类,并定义了一个内部类,之后继承外部类并重新定义内部类

                   的时候会发生什么呢?

package com.kiritor;  class Outer { 	public Outer() { 		System.out.print("Outer:"); 		new Inner(); 	}  	class Inner {  		public Inner() { 			System.out.println("Inner"); 		}  	}  }  public class Outer2 extends Outer { 	class Inner {  		public Inner() { 			System.out.println("outer2:Inner"); 		} 	}  	public static void main(String[] args) { 		new Outer2();  	}  } 
            看一看输出情况:Outer:Inner
                缺省的构造器Outer2()是编译器自动生成的,他会先调用父类的构造器,通过结果可以看出

          虽然创建的是子类对象,但是 内部类并不是使用的"重载"过的.这说明档你继承了某个外部类

          的时候,内部类并未发生特别变化,当然明确的继承某个内部类的方式除外!

         

package com.kiritor;  class Outer { 	public Outer() { 		System.out.print("Outer:"); 		new Inner(); 	}  	class Inner {  		public Inner() { 			System.out.println("Inner"); 		}  	}  }  public class Outer2 extends Outer { 	class Inner extends com.kiritor.Outer.Inner{  		public Inner() { 			System.out.println("outer2:Inner"); 		} 	}  	public Outer2() { 		new Inner(); 	} 	public static void main(String[] args) { 		new Outer2();  	}  } 
           明确继承之后的输出结果为:

              

         内部类的继承问题

                有时候我们只是需要继承内部类,但是内部类的构造器又必须用到外部对象的引用

           , 因此在继承一个内部类的时候就有点特别了,主要的问题在于外部类对象的引用必须

           初始化,而在被继承类中并不存在,也就是单一继承内部类的时候,没有内部类与其外部类

           的一种关联.

               可以使用一下方式解决:

      

package com.kiritor;  import com.kiritor.Outer.Inner;  class Outer { 	public Outer() { 		System.out.print("Outer:"); 		new Inner(); 	}  	class Inner {  		public Inner() { 			System.out.println("Inner"); 		}  	}   }  public class Inner2 extends Outer.Inner {   Inner2(Outer outer)    { 	   outer.super(); 	   //构造器只能是这种方式的 	   System.out.println("只能为此种构造器");    }   public static void main(String[] args) { 	new Inner2(new Outer()); } } 
      输出结果为:

          Outer:Inner
           Inner
          只能为此种构造器
        可以看出的是,Inner2只是集成了内部类,但是其缺省的构造器并不能用,而且仅仅传递一个

    外部类的引用还不够,还必须首先调用外部类的构造方法.这样才提供了内部类与外部类对象

    的引用关联,才能够通过编译的.