java语言基础内部类2.docx
《java语言基础内部类2.docx》由会员分享,可在线阅读,更多相关《java语言基础内部类2.docx(18页珍藏版)》请在冰豆网上搜索。
![java语言基础内部类2.docx](https://file1.bdocx.com/fileroot1/2023-1/14/6e62c15d-a745-4a1d-9cd5-ec9ae7c27b45/6e62c15d-a745-4a1d-9cd5-ec9ae7c27b451.gif)
java语言基础内部类2
内部类
内部类包括如下几种形式:
l作为类成员的内部类;
l成员方法中定义的内部类;
l匿名内部类;
l静态内部类。
1作为类成员的内部类
1.1内部类的编写
内部类和外部类的定义形式相同,但是需要在类中定义:
publicclassMyOuter{
publicclassMyInner{
}
}
该文件编译后能够生成两个类:
MyOuter.class和MyOuter$MyInner.class。
注意:
内部类的访问控制符有:
public、protected、private和缺省的,与类的成员变量和成员方法的访问控制符相同,而外部类的访问控制符只有public和缺省的。
内部类可以访问所在的外部类的成员变量,包括私有成员变量,就像类自身的方法能够访问类的所有类型的成员变量一样,例如下面的代码是正确的:
publicclassMyOuter{
privateStringname="test";
classMyInner{
publicvoidprint(){
System.out.println(name);
}
}
}
内部类中不能定义static类型的方法,下面的代码是错误的:
publicclassMyOuter{
privateStringname="test";
classMyInner{
publicstaticvoidprint(){
System.out.println(name);
}
}
}
内部类可以是抽象的,内部类可以继承某个类,也可以实现某个接口,
publicclassMyOuter{
privateStringname="test";
abstractclassMyInner1{
publicabstractvoidprint();
}
classMyInner2extendsMyInner1implementsSerializable{
publicvoidprint(){
System.out.println(name);
}
}
}
内部类也可以是final类。
1.2从外部类的代码中使用内部类
可以把内部类的对象作为外部类的成员变量使用,可以在外部类的方法中使用内部类的对象。
下面的代码演示了如何把内部类的对象作为成员并且展示了两种实例化的代码:
publicclassMyOuter{
privateMyInnerin=newMyInner();//定义的时候实例化
privateMyInnerin2;//先定义
publicMyOuter(){
in2=newMyInner();//在构造方法中实例化,也可以在其他方法中实例化
}
…
}
下面的代码展示了如何在外部类的方法中使用内部类的对象:
publicclassMyOuter{
publicvoidmakeInner(){
MyInnerin3=newMyInner();//方法中定义变量并实例化
in3.print();
}
…
}
上面的实例化代码相当于MyOuter.MyInnerin3=this.newMyInner();,因为在类的内部使用所以在类型前面省略了MyOuter,实例化的时候省略的“this.”。
1.3从外部类的代码外实例化内部类
在外部类的代码之外使用内部类,就像访问类的实例变量一样,需要先创建外部类的对象,然后通过外部类的对象访问内部类的方法,下面的代码展示了用法:
publicstaticvoidmain(String[]args){
MyOuter.MyInnerin=newMyOuter().newMyInner();
in.print();
MyOuterout=newMyOuter();
MyOuter.MyInnerin2=out.newMyInner();
in2.print();
}
代码中展示了两种方式,两种方式的作用是相同的,下面的代码是错误的:
MyOuter.MyInnerin3=MyOuter.newMyInner();
MyOuter.MyInnerin4=newMyOuter.MyInner();
注意:
在外部类的代码之外使用内部类,内部类必须是可见的,下面的代码是错误的:
publicclassMyOuter{
privateclassMyInner{
publicvoidprint(){
System.out.println(name);
}
}
…
}
publicclassMain{
publicstaticvoidmain(String[]args){
MyOuter.MyInnerin=newMyOuter().newMyInner();
}
}
1.4在内部类中引用外部类实例或者内部类实例
在类中引用当前实例可以使用this,但是内部类中要引用内部类的实例或者内部类所在的外部类的实例如何引用呢?
在内部类中引用内部类自身的实例仍然是通过this,在内部类中引用外部类的实例需要使用外部类的名字加上this的方式,下面的代码展示了用法:
publicclassMyOuter{
intx=20;
publicclassMyInner2{
intx=10;
publicvoidprint(){
intx=5;
System.out.println("局部变量x的值:
"+x);
System.out.println("内部类成员变量x的值:
"+this.x);
System.out.println("外部类成员变量x的值:
"+MyOuter.this);
}
}
publicstaticvoidmain(Stringargs[]){
newMyOuter().newMyInner2().print();
}
…
}
程序的运行结果:
局部变量x的值:
5
内部类成员变量x的值:
10
外部类成员变量x的值:
20
李绪成
2成员方法中定义的内部类
2.1内部类的编写
成员方法中的内部类的编写与作为成员变量的内部类的编写方法基本相同,下面的代码展示了用法:
publicclassMyOuter2{
publicvoidtest(){
classMyInner{
publicvoidprint(){
System.out.println(x);
}
}
}
}
方法内部的类具有如下特点:
l方法内部定义的类就像方法的局部变量,所以在类外或者类的其他方法中不能访问这个内部类。
l没有访问控制符,因为该类只能在定义该类的方法中并且在类的定义之后使用;
l不能访问方法的局部变量,除非局部变量是final类型的;
l能够访问外部类的各种成员变量,如果内部类所在的方法是静态方法,则这个内部类只能访问外部类的静态成员;
l可以使用final和abstract修饰。
2.2方法中内部类的访问
方法中的内部类只能在定义该内部类的方法中访问,并且是方法中内部类的定义之后访问。
下面的代码展示了用法:
publicvoidmain2(String[]args){
classMyInner{
publicvoidprint(){
System.out.println(x);
}
}
MyInnerin=newMyInner();
in.print();
}
李绪成
3匿名内部类
顾名思义,匿名内部类没有类名,而我们创建对象是根据类名创建的,没有类名如何创建对象的?
可以使用类的定义直接创建实例,例如下面的代码:
Parentp=newParent(){
publicvoidprint(){
System.out.println("匿名内部类中的输出方法");
}
};
new后面的信息表示创建了一个继承了Parent类的子类的实例。
匿名内部类有两种形式:
l通过继承父类而形式的匿名内部类;
l通过实现接口而形式的匿名内部类。
下面分别介绍。
3.1通过继承父类而形成的匿名内部类
看下面的代码:
classParent{
publicvoidprint(){
System.out.println("父类的输出方法");
}
}
publicclassMyOuter3{
Parentp=newParent(){
publicvoidprint(){
System.out.println("匿名内部类中的输出方法");
}
};
}
在MyOut3中声明了类型为Parent的成员变量,通过newParent来实例化对象,但是这里的实例化代码与以前见到过的实例化代码不同,以前的代码这样写:
Parentp=newParent();
而这里是:
Parentp=newParent(){
这里的大括号意味着新创建了一个类,这个类是Parent的子类,在子类中可以覆盖父类中的方法或者实现父类中定义的抽象方法,上面的代码重写了父类中的print方法。
注意在倒数第二行的“};”,这个分号不能省略。
上面的代码中定义的成员变量p指向了匿名内部类的实例,也可以在成员方法中定义局部变量指向匿名内部类的实例。
对于匿名内部类的实例的方法的调用是通过执行该实例的父类引用,利用了Java语言的多态性。
下面的代码展示了如何调用(在MyOuter3中增加的代码):
publicstaticvoidmain(String[]args){
newMyOuter3().p.print();
}
输出结果是:
子类中的输出方法
注意:
因为匿名内部类中的方法都是通过父类引用访问的,所以不能在匿名内部类中定义父类中没有声明的方法,这样的方法不能被访问到。
如果是为了匿名内部类中的方法之间共享代码,可以编写供内部方法调用的在父类中没有定义的方法。
3.2通过实现接口而形成的匿名内部类
匿名内部类也可以通过实现接口来创建,与继承父类没有本质区别。
下面的代码展示了使用接口创建匿名内部类:
interfaceFly{
publicvoidtakeof();//起飞
publicvoidlanding();//降落
}
publicclassMyOuter3{
Flybird=newFly(){
publicvoidtakeof(){
System.out.println("小鸟起飞了");
}
publicvoidlanding(){
System.out.println("小鸟降落了");
}
};
}
代码中newFly(){…}意味着创建了一个实现了Fly接口的类的对象,这个类就是匿名内部类。
这个匿名内部类必须实现接口中定义的所有方法,这与普通类实现接口的要求是相同的。
在这个类中也不能定义其他的业务方法,这些方法是通过接口的引用访问的,因为接口中没有声明该方法,所以该方法将不能被访问。
注意:
newFly(){…}实例化的对象是实现了Fly接口的类的对象,而不是实例化Fly接口,接口是不能被实例化的。
这些匿名内部类被实例化以后通过父类引用或者接口引用访问,通常都会有一个引用指向这个新创建的匿名内部类的实例。
有个特殊的应用不需要创建引用指向匿名内部类的实例,而是传递给形参,看下面的代码(在MyOuter3中添加如下代码):
publicstaticvoidmain(String[]args){
//直接把匿名内部类的实例作为实参使用
newMyOuter3().printFly(newFly(){
publicvoidtakeof(){
System.out.println("飞机起飞");
}
publicvoidlanding(){
System.out.println("飞机降落");
}
});
}
publicvoidprintFly(Flyfly){//参数需要是实现Fly接口的类的对象
fly.takeof();
fly.landing();
}
注意:
我们自己在开发程序的时候尽量不要使用内部类,内部类不利于代码重用,如果非常确定这个类只会使用一次,可以使用匿名内部类。
李绪成
4静态内部类
4.1静态内部类的定义
静态内部类与作为成员的内部类基本相同,只是这个内部类是静态的,使用static,类似于静态成员变量和静态成员方法。
下面的代码展示了如何定义静态内部类:
publicclassMyOuter4{
staticclassMyInner{
…
}
}
与静态方法一样,在静态内部类中只能访问外部类的静态方法,看下面的代码:
publicclassMyOuter4{
intx=10;
staticinty=20;
staticclassMyInner{
publicvoidprint(){
System.out.println(x);//错误
System.out.println(y);//正确
}
}
}
System.out.println(x);是错误的,因为它试图访问非静态成员变量x,System.out.println(y)是正确的。
4.2静态内部类的使用
在实例化作为实例成员变量的内部类的时候,要先创建外部类的对象,然后通过对象的new操作符创建内部类的实例。
而静态内部类就像静态方法一样,可以通过类名直接访问而不用创建实例。
下面的代码展示了在外部类的内容和外部类的外部如何访问静态内部类(第一个方法是在MyOuter4中添加的代码,第二个方法是测试类中的代码):
publicvoidoutprint(){
MyInnerinner=newMyInner();
inner.print();
}
publicstaticvoidmain(Stringargs[]){
MyOuter4.MyInnerinner=newMyOuter4.MyInner();
inner.print();
}