根据类定义时所在的位置不同可以将内部类分为四大类:成员内部类、方法内部类、静态内部类、匿名内部类。
成员内部类
顾名思义成员内部类定义在外部类的成员变量位置,相当于外部类的一个成员。将成员内部类当成当前封装类中的一个成员即可,容易理解,外部类中的任何属性和方法在成员内部类中均可直接调用,成员内部类中的任何方法和属性在封装类中也均可使用,但是需要通过声明内部类的实例,通过对象调用。并且内部类中不可使用static修饰变量和方法。代码如下:
public class OutterTest{
private int a = 5;
public int b = 6;
private void outFirst() {
System.out.println("outFirst...");
}
//想要访问内部类中的变量和方法则需使用内部类的实例
InnerTest innerTest = new InnerTest();
public void outSecond() {
System.out.println("outSecond..."+innerTest.c);
}
//声明一个和内部类中方法重名的方法
public void overName() {
System.out.println("overName...outter");
}
//声明一个类作为OutterTest的成员,成员内部类
class InnerTest{
private int c = 1;
public int d = 2;
//编译错误,成员内部类中不允许使用static来修饰属性和方法
//之所以叫做成员内部类,是因为作为外部封装类的一个成员存在,成员内部类依赖于外部封装类
//当创建一个外部类对象时,就可以使用这个对象来创建多个内部类对象;如果在声明要给外部类对象,还是可以继续声明多个内部类对象
//如果在内部类中声明一个static修饰的变量,也就是说内部类中的变量e是类变量,它并不依赖于内部类对象,并且它只能有一份
//但是呢,每个外部类对象都可创建多个内部类(内部类依赖于外部类才存在),此时就会出现多个变量e,这就违反了java的语法
static String e = "aa";
//内部类使用外部类的变量和方法时直接访问即可,不需声明外部类实例
private void innerFirst() {
outFirst();
System.out.println("innerFirst..."+a);
}
//调用重名方法
//当时用内部类中的方法时,直接调用即可
//当使用外部类中的方法时,可以使用 OutterTest.this.overName(); 来调用外部类方法
public void innerSecond() {
OutterTest.this.overName();
System.out.println("innerSecond..."+b);
}
//声明一个和外部类中方法重名的方法
public void overName() {
System.out.println("overName...innner");
}
}
}
----------------------------------------------------------------------------
public class Test {
public static void main(String[] args) {
//先创建外部类的实例,才能创建内部类实例
OutterTest.InnerTest innerTest = new OutterTest().new InnerTest();
innerTest.innerSecond();
innerTest.overName();
}
}
方法内部类
在方法中定义一个类,用于辅助解决一些比较复杂的问题。可随便使用外部类中的成员变量和方法。并且内部类中不可使用static修饰变量和方法。
/**
* 方法内部类(局部内部类)
* 在方法中定义一个类,用于辅助解决问题
* @author chaizepeng
*
*/
public class MethodOutterTest {
private int b = 6;
/**
* 在此方法中定义一个类
* @author chaizepeng
*
*/
public void outFirst(int code) {
//声明一个内部类,用来做一些复杂的操作,例如:求一下code的平方+成员变量b的值
class InnerTest{
private int flag;
// private static int a;//同样的不能用static修饰
public void innerFirst() {
flag = code * code + b;
System.out.println(code+"的平方是:"+flag);
}
//同名方法
public void overName() {
System.out.println("overName...inner");
}
}
//调用内部类中的方法
InnerTest innerTest = new InnerTest();
innerTest.innerFirst();
overName();//这样调用的是外部类的方法
}
//声明一个和内部类中方法重名的方法
public void overName() {
System.out.println("overName...outter");
}
public static void main(String[] args) {
MethodOutterTest methodOutterTest = new MethodOutterTest();
methodOutterTest.outFirst(2);
}
}
静态内部类
使用static关键字修饰的成员内部类就是静态内部类,其他的内部类中不能使用static修饰,而静态内部类可以,它只可以访问外部类中static修饰过的属性和方法,外部类可直接使用它的内部类方法,它不依赖于外部类的实例,可以向调用静态方法似的直接调用静态内部类中的静态方法。
/**
* 静态内部类:使用static关键字修饰的成员内部类就是静态内部类
* @author chaizepeng
*
*/
public class StaticOutterTest {
private int a = 5;
public int b = 6;
private static int c = 5;
public void outFirst() {
InnerTest.innerFirst();
System.out.println("outFirst...");
}
private static void outStaticFirst() {
System.out.println("outStaticFirst...");
}
public void outSecond() {
System.out.println("outSecond...");
}
//声明静态内部类
static class InnerTest{
private static int flag = 3;
private static void innerFirst() {
// outFirst();//调用非static方法是回报错
outStaticFirst();//可以直接调用static方法
System.out.println(flag +"...innerFirst..."+c);//只可以访问static类型的变量
}
}
public static void main(String[] args) {
StaticOutterTest.InnerTest.innerFirst();
}
}
匿名内部类
顾名思义,匿名内部类就是没有名字的内部类,一般适用于swing处的控件监听、线程的开启、线程池的使用等。代码如下
/**
* 匿名内部类
* @author chaizepeng
*
*/
public class AnonOutterTest {
//开启一个线程
public static void main(String[] args) {
new Thread(new Runnable() {//只知道这个类实现了Runnable接口,但是叫什么不知道,这就是匿名的
@Override
public void run() {
System.out.println("-----------");
}
}).start();
}
}
总结
内部类不知可以使得业务实现更优雅,更重要的是它使得类更容易扩展,是对java单继承机制的补充,每一个内部类都可以去继承和实现接口而不必在乎外部类是否已经继承了类,这使得扩展性进一步的提升。代码如下:
public class ExtendOutterTest extends Exception{
private static final long serialVersionUID = 1L;
//这个方法用于自定义异常
public ExtendOutterTest() {
System.out.println("字符错误,不能为0");
}
//用于开启线程
//抛出异常
public void run() throws ExtendOutterTest{
Thread thread = new OneThreadInnerTest();
thread.start();
//这里也可以使用匿名内部类实现
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// System.out.println("就是这么任性,我还能开启一个线程...");
//
// }
// }).start();
int flag = 0;
if (flag == 0) {
throw new ExtendOutterTest();
}
}
//内部类用于开启线程
class OneThreadInnerTest extends Thread{
@Override
public void run() {
System.out.println("就是这么任性,我还能开启一个线程...");
}
}
public static void main(String[] args) {
ExtendOutterTest outterTest = new ExtendOutterTest();
try {
outterTest.run();
} catch (ExtendOutterTest e) {
System.out.println("我不但可以开启线程,还能捕捉异常");
e.printStackTrace();
}
}
}