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