我们在描述事物的时候,事物的内部还有事物,这个内部事物还要访问外部事物中的内容时。那么,这个内部事物就可以用内部类来描述。内部类也叫内置类,嵌套类。
一,内部类的形式以及对外访问的方式
顾名思义,内部类就是一个类嵌套在另一个类中。内部类可以在外部类的成员位置,也可以在外部类的局部位置,也就是成员函数中。
一般,我们在定义内部类时设置其访问权限为私有private,并在外部类中提供访问它的方法。下面来看例子:
package com.jimmy.basicInnerClass;
class OuterClass{ // 外部类
private int num = 5; // 外部类的成员变量
private class InnerClass{ // 私有的内部类,定义在外部类的成员位置
public void innerMethod() { // 内部类的成员方法
System.out.println("你好啊,我是内部类的方法.."+num); // 内部类可直接访问外部类的成员
}
}
public void outerMethos() { // 外部类方法,实例化内部类对象,并调用其方法
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
innerClass.innerMethod();
}
}
public class InnerClassDemo1 {
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
outerClass.outerMethos(); // 通过外部类方法访问内部类成员,就像get方法访问私有成员变量一样。
}
}
上面代码的输出结果:
你好啊,我是内部类的方法..5
值得注意的是,外部类也是一个完整的类,在编译的时候也有class文件生成。上面这个文件就会产生3个class文件。内部类的名字比较特别,会标明所属的外部类名。
OuterClass.class
OuterClass$InnerClass.class
InnerClassDemo1.class
上面的代码中,我们直接在外部类的方法中创建了内部类对象,并调用了内部类的方法,这样就显得有点越俎代庖了。我们想自己拿到内部类的对象来调用内部类中的方法。但是,内部类是私有的,我们不能直接new出内部类的对象,虽然可以用“new Outer().new Inner()”来实例化内部类对象,但是却没有可用的对象名来接收它(因为内部类对外不可见)。怎么解决呢?我们知道,内部类也是类,同样具有类的继承特性,所以我们将内部类继承自外部的某个类,或者实现外部的某个接口,就可以通过多态来接收内部类对象了,代码如下:
package com.jimmy.basicInnerClass;
interface Inter{ // 外部接口
public void innerMethod();
}
class Outer3{
private int num = 5;
private class Inner implements Inter{ // 内部类实现接口,并实现其中的方法。
@Override
public void innerMethod() {
System.out.println("你好啊,我是内部类的方法...."+num);
}
}
public Inner getInnerObject() { // 外部类函数只返回内部类对象,并不越俎代庖去调用方法
return new Inner();
}
}
public class InnerClassDemo5 {
public static void main(String[] args) {
Outer3 outer3 = new Outer3();
Inter innerObject = outer3.getInnerObject(); // 私有的内部类对象可以用多态性来接收
innerObject.innerMethod();
}
}
上述代码的输出结果如下:
你好啊,我是内部类的方法....5
这样一来,私有化的内部类对象就可以通过多态在外部被持有了,这也符合java中的“面向接口编程”的要求。
二,匿名内部类
从上面的代码可以看出,内部类在外部类的里面,并可以实现外部接口,然后实现接口中的方法。有的时候,外部接口中的有些实现只用到一次,也就没必要特意写一个类来实现接口,可以使用匿名内部类的形式来实现,匿名内部类在外部类的局部位置,即方法中。
匿名内部类必须继承一个父类或者实现一个接口。匿名内部类其实就是一个带有内容的子类对象,格式为:new 接口/父类(){子类内容}。这个格式比较新颖,一般来说,我们在”new Object();”后会以“;”结束。现在new Object(){}后面跟着的是一对“{}”,表示这是一个子类结构体,接口的实现就在这里面写。看个例子:
package com.jimmy.basicInnerClass;
interface InterInner{ // 外部接口以及方法
void innerMethod1();
void innerMethod2();
}
class Outer2{
private int num = 1;
public void outerMethod(){
new InterInner() { // 这就是匿名内部类,大括号里面是接口的实现
@Override
public void innerMethod1() { // 实现方法1
System.out.println("你好,我是匿名内部类的方法1..."+num);
}
@Override
public void innerMethod2() { // 实现方法2
// TODO Auto-generated method stub
System.out.println("你好,我是匿名内部类的方法2..."+num+1);
}
}.innerMethod1(); // new出对象,就能调用函数
}
}
public class InnerClassDemo4 {
public static void main(String[] args) {
Outer2 outer2 = new Outer2();
outer2.outerMethod();
}
}
上面代码new出匿名内部类的对象后直接调用了实现后的方法。代码输出:
你好,我是匿名内部类的方法1...1
我们也可以提供匿名内部类的对象,并在外部调用匿名内部类的方法,代码如下:
package com.jimmy.basicInnerClass;
interface InterInner2{ // 外部接口以及方法
void innerMethod1();
void innerMethod2();
}
class Outer4{
private int num = 1;
public InterInner2 outerMethod(){
InterInner2 inner2 = new InterInner2() { // 接收匿名内部类对象,大括号里面是接口的实现
@Override
public void innerMethod1() { // 实现方法1
System.out.println("你好,我是匿名内部类的方法1..."+num);
}
@Override
public void innerMethod2() { // 实现方法2
// TODO Auto-generated method stub
System.out.println("你好,我是匿名内部类的方法2..."+(num+1));
}
};
return inner2;
}
}
public class InnerClassDemo4_1 {
public static void main(String[] args) {
Outer4 outer4 = new Outer4();
InterInner2 inner2 = outer4.outerMethod();
inner2.innerMethod1();
inner2.innerMethod2();
}
}
代码输出为:
你好,我是匿名内部类的方法1...1
你好,我是匿名内部类的方法2...2
三,匿名内部类的常见用法
匿名内部类只是对接口的一次实现和调用,用完就被回收了。其使用可以像上面那样,将匿名内部类放在外部类的方法中,在外面调用外部类的方法,得到内部类对象进而调用内部类的方法。如果内部类不需要访问外部类的成员变量,就可以直接将其放在main方法中。如下示例:
package com.jimmy.niMingInnerClass;
interface movable{
public void run();
}
public class NimingInnerClassDemo1 {
public static void main(String[] args) {
new movable() {
@Override
public void run() {
System.out.println("i am running...");
}
}.run();
}
}
输出结果:
i am running...
实际中使用匿名内部类有很多,常见的就是创建线程时使用匿名内部类,如下示例:
package com.jimmy.niming;
public class NiMingNeibuleiTest {
public static void main(String[] args) {
new Thread(new Runnable() { // 线程1
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"..."+i);
}
}
}).start();
new Thread(new Runnable() { // 线程2
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"..."+i);
}
}
}).start();
}
}
输出结果:
2个线程交替执行
只学会了内部类的形式和对外调用方法,以及匿名内部类如何实现简化代码。并不是很理解内部类的好处,以后编程学习过程中慢慢体会。