内部类/嵌套类,多用于类的设计上。
分析事物A时,发现事物A的内部还存在其他事物X,而且事物X又在使用事物A中的内容,此时,Java提供了内部类设计来实现这种需求!!!
访问特点:
内部类作为外部类的一个成员,可以直接访问外部类的中的成员,包括私有成员;
而外部内要想访问内部类的成员,必须通过创建内部类的对象,才能访问;
内部类出现的原因
两个类之间的关闭特别紧密,如心脏和人体的关系;
A作为外部类,B作为内部类;
当B定义为A的内部类之后:
首先,B离不开A而单独存在,使得程序更加严谨,合理,
其次,B访问A中的资源,直接访问,不需要创建A的对象就能调用,简化了过程;
内部类的调用
在外部类中调用内部类,需要创建内部类对象进行调用
//外部类
public class Body {
private int times;
//内部类
class Heart {
void heartBeat() {
//内部类直接使用外部类的私有成员变量
System.out.println("Body.Heart.heartBeat():\t"+times);
}
}
public void invoke() {
//外部类只能通过创建内部类对象访问内部类的成员
Heart inner = new Heart();
inner.heartBeat();
}
}
public class Test {
public static void main(String[] args) {
Body body = new Body();
body.invoke();
}
}
结果:Body.Heart.heartBeat(): 0
在其它类中调用内部类,需要创建外部类对象以及内部类对象
//外部类
public class Body {
private int times;
//内部类
class Heart {
void heartBeat() {
//内部类直接使用外部类的私有成员变量
System.out.println("Body.Heart.heartBeat():\t"+times);
}
}
}
public class Test {
public static void main(String[] args) {
Body.Heart heart = new Body().new Heart();
heart.heartBeat();
}
}
运行结果:Body.Heart.heartBeat(): 0
在其它类中访问静态内部类中的非静态成员,需要对象;访问静态成员,不需要对象;
//外部类
public class Body {
private static int times;
//静态内部类
static class Heart {
void heartBeat() {
//内部类直接使用外部类的私有成员变量
System.out.println("Body.Heart.heartBeat():\t"+times);
}
//静态内部类中的静态方法
static void size() {
System.out.println("Body.Heart.size()");
}
}
}
public class Test {
public static void main(String[] args) {
//访问静态内部类中的成员方法
Body.Heart heart = new Body.Heart();
heart.heartBeat();
//访问静态内部类中的静态方法
Body.Heart.size();
}
}
运行结果:
Body.Heart.heartBeat(): 0
Body.Heart.size()
内部类通过持有外部类的引用,实现访问外部类的成员变量
public class Outer {
private int num = 1;
private String name = "kk";
class Inner {
private int num = 2;
void method() {
int num = 3;
System.out.println(num);//方法入栈后,存在局部变量num,直接使用,结果为:3
System.out.println(Inner.this.num);//使用Inner对象在堆内存中的num,结果为:2
System.out.println(Outer.this.num);//使用Outer对象在堆内存中的num,结果为:1
//首先在Inner.this对象中找,没有找到,再到Outer中找!
System.out.println(name);//结果为:kk
//内部类持有了外部类的引用
System.out.println(Outer.this.name);//结果为:kk
}
}
}
内部类访问局部变量,该局部变量必须是final的,即常量,确保方法出栈后该变量仍能使用
public class Outer {
//成员方法
public Object method() {
//内部类使用到了局部变量,该变量必须final
//确保方法出栈后(局部变量消失),内部类使用到的局部变量仍能被访问到
final int num = Integer.MAX_VALUE;
//局部内部类
class Inner {
public String toString() {
return "local inner class,num="+num;
}
}
//返回局部内部类对象
return new Inner();
}
}
public class Test {
public static void main(String[] args) {
Object obj = new Outer().method();//多态
String str = obj.toString();//子类对象覆盖了父类中的方法
System.out.println(str);
}
}
=============================================================================
匿名内部类
匿名内部类实际上就是内部类的一种简写方式
一般,如果接口中的方法不多(1个或2个),则采用匿名内部类的方式来解决问题
如果接口中的方法比较多,则建议采用显示定义内部类来实现接口进行操作应用场景:
面向接口编程时,方法入参为接口类型,此时则可以通过匿名内部类的方式来实例化子类对象。
这样就设计到:
1.匿名内部类,它没有显示的定义一个类去实现接口,而是直接实现接口中的方法
2.面向接口来创建对象,因为子类没有名字,只能用父类名称来代替
3.多态,通过父类接口类型的引用指向子类对象
面向接口编程时,匿名内部类的使用
public interface InterfaceA {
public abstract String fun();
}
public class Main {
//面向接口编程,提供扩展性
public String say(InterfaceA a) {
return "Anonymouse inner class :"+a.fun();//多态,动态绑定,执行子类方法
}
}
public class Test {
public static void main(String[] args) {
//创建匿名内部类对象,作为参数传入到方法中
//多态调用
String str = new Main().say(new InterfaceA() {
@Override
public String fun() {
return "fun ?";
}
});
System.out.println(str);
}
}
运行结果:
Anonymouse inner class :fun ?
另一个小例子:
接口
public interface InterfaceA {
public String fun();
}
通过接口创建对象
public class Outer {
//成员方法
public InterfaceA method() {
final int num = Integer.MAX_VALUE;
//返回一个匿名内部类
return new InterfaceA() {
@Override
public String fun() {
return "Anonymous inner class, num="+num;
}
};
}
}
测试
public class Test {
public static void main(String[] args) {
InterfaceA a = new Outer().method();
String str = a.fun();
System.out.println(str);
}
}
结果
Anonymous inner class, num=2147483647
另一个例子
public class Main {
/**
* 显示定义内部类,没有局限性,可以继承类,也可以实现接口
*/
public void test1() {
class Inner extends Object {
public void funny() {
System.out.println("Main.funny()");
}
}
new Inner().funny();
}
/**
* 使用Object类创建匿名内部类,简写形式
* 只限于子类的一个特有方法的调用
*/
public void test2() {
new Object() {
public void funny() {
System.out.println("Main.funny()");
}
}.funny();
}
/**
* 错误
* 原因:多态,类型提升,调用父类中没有的子类特有方法,编译失败!
*/
public void test3() {
Object obj = new Object() {
public void funny() {
System.out.println("Main.funny()");
}
};
//obj.funny(); //子类对象发生类型提升,其特有方法无法被调用,因为父类Object中没有funny(),编译失败!
}
}