2.内部类相关说明
在内部类的结构中,不仅内部类可以方便地访问外部类的私有成员,外部类也同样可以访问内部类的私有成员。内部类本身是一个独立的结构,这样在进行普通成员属性的访问时,为了明确地标记处属性是外部类所提供的,可以采用“外部类.this.属性”的形式进行标注。
范例:外部类访问内部类私有成员
package cn.kuiba.util;
class Outer{ //外部类
private String msg="www.kuiba.cn"; //私有成员属性
public void fun(){ //普通方法
Inner in=new Inner(); //实例化内部对象
in.print(); //调用内部类方法
System.out.println(in.info); //访问内部类的私有属性
}
class Inner{ //Inner内部类
private String info="魁拔"; //内部类私有成员
public void print(){
System.out.println(Outer.this.msg); //Outer类中的私有成员属性
}
}
}
public class Main {
public static void main(String args[]){
Outer outer=new Outer(); //实例化外部类对象
outer.fun(); //调用外部类中的方法
}
}
执行结果
www.kuiba.cn(“in.print()”代码执行结果,外部类msg成员属性)
魁拔(“in.info”代码执行结果,内部类info成员属性)
本程序在内部类中利用了Outer.this.msg的形式调用外部类中的私有成员属性,而外部类同样可以利用内部类的对象访问内部类私有成员。
需要注意的是,虽然内部类被外部类包裹,但同样属于一个完整类,所以可以直接进行内部类对象实例化,采用如下语法格式:
外部类.内部类 内部类对象=new 外部类().new 内部类();
在此语法格式中,要求必须先获得相应的外部类实例化对象后,才可以利用外部类的实例化对象进行内部类对象实例化操作。
提示:关于内部类的字节码文件名称。
当进行内部类源代码编译后,读者会发现有一个Outer$Inner.class字节码文件,其中所使用的标识符"$"在程序中就会变成".",所以内部类的全称就是“外部类.内部类”,由于内部类与外部类之间可以直接进行私有成员的访问,就必须保证在实例化内部类对象前首先实例化外部类对象。
范例:实例化内部类对象
package cn.kuiba.util;
class Outer{ //外部类
private String msg="www.kuiba.cn"; //私有成员属性
class Inner{ //Inner内部类
public void print(){
System.out.println(Outer.this.msg); //Outer类中的私有成员属性
}
}
}
public class Main {
public static void main(String args[]){
Outer.Inner in=new Outer().new Inner(); //实例化内部类对象
in.print(); //直接调用内部类中的方法
}
}
执行结果
www.kuiba.cn
本程序在外部实例化内部类对象,由于内部类有可能要进行外部类的私有成员访问,所以在实例化内部类对象之前一定要实例化外部类对象。
如果一个内部类不希望被其他类使用,可以添加private关键字将其定义为私有内部类。private,protected定义类的结构只允许出现在内部类声明处。
内部类也可以应用在接口和抽象类中,即内部接口或者内部抽象类。
interface IChannel{ //外部接口
public void send(IMessage msg); //【抽象方法】发送消息
interface IMessage{ //内部接口
public String getContent(); //【抽象方法】获取消息内容
}
}
class ChannelImpl implements IChannel{ //外部接口实现子类
@Override
public void send(IMessage msg){ //方法覆写
System.out.println("发送消息:" + msg.getContent());
}
class MessageImpl implements IMessage{ //内部接口实现子类,不是必须实现
public String getContent(){ //覆写方法
return "www.kuiba.cn";
}
}
}
public class Main {
public static void main(String args[]){
IChannel channel=new ChannelImpl(); //实例化外部类接口对象
//实例化内部类接口实例化对象前需要首先获取外部类实例化对象
channel.send(((ChannelImpl)channel).new MessageImpl());
}
}
程序执行结果:
发送消息:www.kuiba.cn
本程序利用了内部类的形式定义了内部接口,并且分别为外部接口和内部接口定义了各自的子类。由于IMessage是内部接口,所以在定义MessageImpl子类的时候也采用了内部类的定义形式。
范例:在接口中定义内部抽象类
package cn.kuiba.util;
interface IChannel{ //外部接口
public void send(); //【抽象方法】发送消息
abstract class AbstractMessage{ //内部抽象类
public abstract String getContent(); //【抽象方法】获取信息内容
}
}
class ChannelImpl implements IChannel{ //外部接口实现子类
class MessageImpl extends AbstractMessage{ //内部抽象类子类
@Override
public String getContent(){ //方法覆写
return "www.kuiba.cn";
}
}
@Override
public void send(){ //方法覆写
AbstractMessage msg=new MessageImpl(); //实例化内部抽象类对象
System.out.println(msg.getContent()); //调用方法
}
}
public class Main {
public static void main(String args[]){
IChannel channel=new ChannelImpl(); //实例化外部接口对象
channel.send(); //消息发送
}
}
程序执行结果:
www.kuiba.cn
本程序在IChannel外部接口的内部定义了内部抽象类,在定义ChannelImpl子类的print()方法时,利用内部抽象类的子类为父类对象实例化,实现程序。
在JDK1.8之后由于接口中可以定义static方法,这样就可以直接在接口中进行该接口子类的定义,并利用static方法返回此接口实例。
范例:接口子类定义为自身内部类
package cn.kuiba.util;
interface IChannel{ //外部接口
public void send(); //发送消息
class ChannelImpl implements IChannel{ //内部类实现本接口
@Override
public void send(){ //方法覆写
System.out.println("www.kuiba.cn");
}
}
public static IChannel getInstance(){ //定义static方法获取本接口实例
return new ChannelImpl(); //返回接口子类实例
}
}
public class Main {
public static void main(String args[]){
IChannel channel= IChannel.getInstance(); //获取接口对象
channel.send(); //消息发送
}
}
程序执行结果:
www.kuiba.cn
本程序定义IChannel接口时直接在内部定义了其实现子类,同时为了方便用户获取接口实例,使用了static定义了一个静态方法,这样用户可以不关心子类的前提下直接使用接口对象。