前言
学习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只是集成了内部类,但是其缺省的构造器并不能用,而且仅仅传递一个
外部类的引用还不够,还必须首先调用外部类的构造方法.这样才提供了内部类与外部类对象
的引用关联,才能够通过编译的.