1 内部类基本概念
虽然在类之中的基本组成就是成员属性与方法,但是在任何的语言里面结构也是允许进行嵌套的,所以在一个类的内部可以定义其他的类,这样的类就称为内部类。
本身就是一个独立且完善的类结构,在一个类的内部除了属性和方法外可以继续使用class定义内部类。
范例:内部类的基本定义
class Outer{
private String msg = "lks"; //定义私有成员属性
public void fun(){
Inner in = new Inner(); //声明并实例化内部类对象
in.print(); //调用内部类方法
}
class Inner{ //定义一个内部类
public void print(){
System.out.println(Outer.this.msg); //使用外部类的私有成员属性
}
}
}
public class JavaDemo{
public static void main(String[] args){
Outer out = new Outer();
out.fun();
}
}
从整个代码结构上实际上发现内部类的结构并不难理解,甚至可以说其结构与普通类一样清晰明了。
为什么会提供内部类这样的结构呢?因为从整体的代码结构上来讲内部类的结构并不合理,所以内部类最大的缺陷在于破坏了程序的结构,但是破坏需要有目的的破坏。
范例:将以上程序分为两个类
class Outer{
private String msg = "lks"; //定义私有成员属性
public void fun(){
Inner in = new Inner(this); //声明并实例化内部类对象
in.print(); //调用内部类方法
}
//思考一:内部类要想获取外部类的私有成员属性,外部类必须提供getter方法
public String getMsg(){
return this.msg;
}
}
class Inner{ //定义一个内部类
private Outer out;
//思考四:那么我们需要一个引用来接收外部类对象
public Inner(Outer out){
this.out = out;
}
public void print(){
//思考二:内部类要想调用外部类getter方法,必须声明并实例化外部类对象
//,但是我并不想这样,因为主方法中已经有了外部类实例化对象
System.out.println(out.getMsg()); //使用外部类的私有成员属性
}
}
public class JavaDemo{
public static void main(String[] args){
Outer out = new Outer();
out.fun();
}
}
通过以上代码,我们可以知道内部类的优势是轻松的访问外部类的私有属性。
2 内部类相关说明
内部类可以轻松访问外部类中的私有成员或私有方法,同理,外部类也可以轻松访问内部类的私有成员或私有方法。
范例:外部类访问内部类的私有成员属性
class Outer{
private String msg = "lks"; //定义私有成员属性
public void fun(){
Inner in = new Inner(); //声明并实例化内部类对象
in.print(); //调用内部类方法
}
class Inner{ //定义一个内部类
private String info = "hhy";
public void print(){
System.out.println(Outer.this.msg);
}
}
}
public class JavaDemo{
public static void main(String[] args){
Outer out = new Outer();
out.fun();
}
}
使用了内部类之后,就不需要使用setter、getter来获取私有属性,而可以在类内部直接进行处理操作。
但是需要注意的是,内部类本身也属于一个类,虽然在大部分情况下内部类往往是被外部类包裹的,但是外部类依然可以产生内部类的实例化对象,而此时内部类的实例化对象的格式如下:外部类.内部类 内部类对象名称 = new 外部类().new 内部类();
class Outer{
private String msg = "lks"; //定义私有成员属性
public void fun(){
Inner in = new Inner(); //声明并实例化内部类对象
in.print(); //调用内部类方法
}
class Inner{ //定义一个内部类
private String info = "hhy";
public void print(){
System.out.println(Outer.this.msg);
}
}
}
public class JavaDemo{
public static void main(String[] args){
Outer.Inner in = new Outer().new Inner();
in.print();
}
}
在内部类编译完成之后会自动形成一个“Outer$Inner.class”类文件,其中“$”这个符号换到程序之中就变成了“.”,所以内部类的全称就是:“外部类.内部类”。内部类与外部类之间可以直接进行私有成员的访问,这样一来内部类如果要是提供有实例化对象了,一定要先保证外部类实例化了。
如果Inner类只允许Outer类来使用,就可以使用private进行私有定义。
class Outer{
private String msg = "lks"; //定义私有成员属性
public void fun(){
Inner in = new Inner(); //声明并实例化内部类对象
in.print(); //调用内部类方法
}
private class Inner{ //定义一个内部类
private String info = "hhy";
public void print(){
System.out.println(Outer.this.msg);
}
}
}
/*JavaDemo.java:21: 错误: Outer.Inner 在 Outer 中是 private 访问控制
Outer.Inner in = new Outer().new Inner();
^
JavaDemo.java:21: 错误: Outer.Inner 在 Outer 中是 private 访问控制
Outer.Inner in = new Outer().new Inner();
^
2 个错误
*/
在Java之中类作为最基础的结构体实际上还有与之类似的抽象类或者接口,抽象类与接口中都可以定义内部结构。
范例:定义内部接口
interface IChannel{
public abstract void getMessage(IMessage msg);
interface IMessage{
public abstract String getContent();
}
}
class ChannelImpl implements IChannel, IChannel.IMessage{
public void getMessage(IMessage msg){
System.out.println(msg.getContent());
}
public String getContent(){
return "hhy";
}
}
public class JavaDemo{
public static void main(String[] args){
ChannelImpl chan = new ChannelImpl();
chan.getMessage(chan);
}
}
interface IChannel{
public abstract void getMessage(IMessage msg);
interface IMessage{
public abstract String getContent();
}
}
class ChannelImpl implements IChannel{
public void getMessage(IMessage msg){
System.out.println(msg.getContent());
}
class MessageImpl implements IMessage{
public String getContent(){
return "hhy";
}
}
}
public class JavaDemo{
public static void main(String[] args){
IChannel chan = new ChannelImpl();
chan.getMessage(((ChannelImpl)chan).new MessageImpl());
}
}
下面观察一个内部的抽象类,内部抽象类可以定义在普通类,抽象类、接口内部都是可以的。
范例:观察接口内部抽象类
interface IChannel{
public abstract void send();
abstract class AbstractMessage{
public abstract String getContent();
}
}
class ChannelImpl implements IChannel{
public void send(){
AbstractMessage msg = new Message();
System.out.println(msg.getContent());
}
class Message extends AbstractMessage{
public String getContent(){
return "hhy";
}
}
}
public class JavaDemo{
public static void main(String[] args){
IChannel chan = new ChannelImpl();
chan.send();
}
}
内部类还有一种结构,即:如果现在定义了一个接口,那么可以在内部利用类实现该接口,在JDK 1.8之后接口中追加了static方法可以不受到实例化对象的控制,现在就可以使用此特性来完成功能。
范例:接口内部进行接口实现
interface IChannel{
public abstract void send();
class ChannelImpl implements IChannel{
public void send(){
System.out.println("hhy,my love");
}
}
}
public class JavaDemo{
public static void main(String[] args){
IChannel chan = new IChannel.ChannelImpl();
chan.send();
}
}
内部类是一种非常灵活的定义结构,只要你的语法满足了,各种需求都可以帮你实现。
3 static定义内部类
在内部类使用static定义,那么这个内部类就变成了“外部类“,static定义的都是独立于类的结构,该类结构就相当于是一个独立的程序类。需要注意的是,static定义的不管定义的是类还是方法,只能够访问static成员,所以static定义的内部类,只能访问外部static属性或方法。
范例:使用static定义内部类
class Outer{
private static final String msg = "hhy";
static class Inner{
public void fun(){
System.out.println(Outer.msg);
}
}
}
这个时候的Inner是一个独立的类,如果此时要想实例化Inner类对象,只需要按如下格式实例化:
外部类.内部类 内部类对象名称 = new 外部类.内部类();
范例:实例化static内部类对象
public class JavaDemo{
public static void main(String[] args){
Outer.Inner in = new Outer.Inner();
in.fun();
}
}
如果以后在实际开发之中看到类名称上提供有”.“,首先应该想到的是这是一个内部类结构,如果可以直接进行实例化,则应该立刻认识到这是一个static定义的内部类。
如果以static定义内部类的形式来讲并不常用,static定义内部接口的形式最为常用。
范例:使用static定义内部接口
interface IMessageWrap{ //消息包装
static interface IMessage{
public abstract String getContent();
}
static interface IChannel{
public abstract boolean connect();
}
public static void send(IMessage msg, IChannel chan){
if(chan.connect()){
System.out.println(msg.getContent());
}else{
System.out.println("消息通道建立失败,消息发送失败!");
}
}
}
class Message implements IMessageWrap.IMessage{
public String getContent(){
return "hhy";
}
}
class Channel implements IMessageWrap.IChannel{
public boolean connect(){
return true;
}
}
public class JavaDemo{
public static void main(String[] args){
IMessageWrap.send(new Message(), new Channel());
}
}
之所以使用static定义内部接口,主要是因为这些操作属于一组相关定义,有了外部接口之后,可以更加明确的描述出这些接口的主要功能。
4 方法中定义内部类
内部类可以在任意的结构中进行定义,这就包括了:类中、方法中、代码块中,但是从实际的开发来讲,在方法中定义内部类的形式较多。
范例:在方法中定义的内部类
class Outer{
private String msg = "hhy";
public void send(long time){
class Inner{
public void fun(){
System.out.println(time + Outer.this.msg);
}
}
Inner in = new Inner();
in.fun();
}
}
public class JavaDemo{
public static void main(String[] args){
Outer out = new Outer();
out.send(100);
}
}
此时在fun()方法内部提供有Inner内部类的定义,并且可以发现内部类可以直接访问外部类中的私有属性也可以直接访问方法中的参数,但是对于方法中的参数直接访问是从JDK 1.8开始支持的,而在JDK 1.8之前,如果方法中定义的内部类要想访问方法中的参数,则参数前必须追加final。
范例:在JDK 1.8以前的程序结构
class Outer{
private String msg = "hhy";
public void send(final long time){
class Inner{
public void fun(){
System.out.println(time + Outer.this.msg);
}
}
Inner in = new Inner();
in.fun();
}
}
public class JavaDemo{
public static void main(String[] args){
Outer out = new Outer();
out.send(5201314);
}
}
之所以取消这样的限制,主要是为了其扩展的函数式编程的功能。
5 匿名内部类
匿名内部类是一种简化的内部类处理形式,其主要是在抽象类和接口的子类上使用的。
范例:观察一个基本的程序结构
interface IMessage{
public abstract void fun();
}
class MessageImpl implements IMessage{
public void fun(){
System.out.println("hhy");
}
}
public class JavaDemo{
public static void main(String[] args){
IMessage msg = new MessageImpl();
msg.fun();
}
}
如果说现在IMessage接口中的MessageImpl只是用唯一的一次,那么是否还有必要将其定义为单独的类那么在这样的要求下就发现这个时候定义的子类是有些多余的,所以就可以使用匿名内部类的形式解决此问题。
范例:使用匿名内部类
interface IMessage{
public abstract void fun();
}
public class JavaDemo{
public static void main(String[] args){
IMessage msg = new IMessage(){
public void fun(){
System.out.println("hhy");
}
};
msg.fun();
}
}
有些时候为了更加方便的体现出匿名内部类的使用,往往可以利用静态方法做一个内部的匿名内部类实现。
范例:在接口中直接定义匿名内部类
interface IMessage{
public abstract void fun();
public static IMessage getInstance(){
return new IMessage(){
public void fun(){
System.out.println("hhy");
}
};
}
}
public class JavaDemo{
public static void main(String[] args){
IMessage.getInstance().fun();
}
}
与内部类相比,匿名内部类只是一个没有名字的只能够使用一次的,并且结构固定的一个子类操作。