Java内部类
内部类
虽然在类之中的基本组成就是成员属性与方法,但是在任何语言里面结构也是允许进行嵌套的,所以在一个类的内部可以定义其他的类,这样的类就称为内部类。
1,内部类基本概念
如果说到内部类肯定其本身是一个独立且完善的类结构,在一个类的内部除了属性和方法之外可以继续使用使用class定义内部类
范例:内部类的基本定义
1 class Outer{ 2 private String msg="https://www.cnblogs.com/Mufasa"; 3 public void fun(){ 4 Inner inner=new Inner(); 5 inner.print(); 6 } 7 class Inner{ 8 public void print(){ 9 System.out.println(Outer.this.msg); 10 } 11 } 12 } 13 14 public class Main { 15 public static void main(String[] args) { 16 Outer outer=new Outer(); 17 outer.fun(); 18 System.out.println("Hello World!"); 19 } 20 }
因为从整体代码结构上来讲内部类的结构并不合理,所以内部类本身最大的缺陷在于破坏了程序的结构,但是有目的破坏,那么它一定有其他优势,如果要更好的观察出内部类的优势,就可以将内部类拿到外面来。从整个的代码上实际上发现内部类的结构并不难理解,甚至可以说其结构与普通类一样清晰明了。那为什么会提高内部类这样的结构呢?
范例:分为两种
1 class Outer{ 2 private String msg="https://www.cnblogs.com/Mufasa"; 3 public void fun(){ 4 //思考5:需要将当前对象outer传递到Inner类之中 5 Inner inner=new Inner(this); 6 inner.print(); 7 } 8 //思考1:msg的属性如果要被外部访问需要getter方法 9 public String getMsg(){ 10 return this.msg; 11 } 12 } 13 class Inner{ 14 //思考3:Inner这个类对象实例化的时候需要Outer类的引用 15 private Outer outer; 16 //思考4:应该通过Inner类的构造方法获取outer类对象 17 public Inner(Outer outer){ 18 this.outer=outer; 19 } 20 public void print(){ 21 //思考2:如果想要调用外部类中的getter方法,那么就一定需要有Outer001类对象 22 System.out.println(this.outer.getMsg()); 23 } 24 } 25 public class Main { 26 public static void main(String[] args) { 27 Outer outer=new Outer(); 28 outer.fun(); 29 System.out.println("Hello World!"); 30 } 31 }
可以发现,整体的操作之中,折腾半天主要的目的就是为了让Inner这个内部类可以访问Outer这个类中的私有属性,但是不用内部类的时候整体代码非常麻烦,所以可以得出内部类的优点:轻松的访问外部类中的私有属性
2,内部类相关说明
现在我们已经清楚的认识到内部类的优势以及结构,那么随后需要对内部类进行一些相关的说明,现在所定义的内部类都属于普通的内部类形式,普通的内部类往往会提供有属性和方法,需要注意的是,内部类虽然可以方便的访问外部类中的私有成员和私有方法,同理外部类也可以访问内部类中的私有成员和私有方法。
范例:外部类访问内部类的私有成员和私有方法
1 class Outer{ 2 private String msg="https://www.cnblogs.com/Mufasa"; 3 public void fun(){ 4 Inner inner=new Inner(); 5 inner.print(); 6 System.out.println(inner.info);//访问内部类的私有属性 7 } 8 class Inner{ 9 private String info="今天天气很好"; 10 public void print(){ 11 System.out.println(Outer.this.msg); 12 } 13 } 14 } 15 16 public class Main { 17 public static void main(String[] args) { 18 Outer outer=new Outer(); 19 outer.fun(); 20 } 21 }
但是需要注意内部类本身也是属于一个类,虽然在大部分的情况下内部类往往是被外部类包裹的,但是外部依然可以产生内部类的实例化对象,而此时内部类的实例化对象的格式如下:使用内部类之后,内部类与外部类之间的私有操作的访问就不需要通过setter、getter以及其他的间接方式完成了,直接进行处理操作。
1 外部类.内部类 内部类对象 = new 外部类().new 内部类();
在内部类编译完成之后会自动形成一个“Outer$Inner.class”类文件,其中“$”这个符号换到程序中就变成了“.”,所以内部类的全程就是“外部类.内部类”。内部类与外部类之间可以直接进行私有成员的访问,这样一来内部类如果要提供有实例化对象了,一定要先保证外部类以及实例化对象了。
1 class Outer{ 2 private String msg="https://www.cnblogs.com/Mufasa"; 3 class Inner{ 4 public void print(){ 5 System.out.println(Outer.this.msg); 6 } 7 } 8 } 9 10 public class Main { 11 public static void main(String[] args) { 12 Outer.Inner inner=new Outer().new Inner(); 13 inner.print(); 14 } 15 }
如果此时Inner类只允许Outer类来使用,那么在这样的情况下可以使用private进行私有定义。
1 class Outer{ 2 private String msg="https://www.cnblogs.com/Mufasa"; 3 private class Inner{ 4 public void print(){ 5 System.out.println(Outer.this.msg); 6 } 7 } 8 }
在java之中类作为最基础的结构体实际上还有与之类似的抽象类或者是接口,抽象类与接口中都可以定义内部结构。此时的Inner类无法在外部类进行使用。
范例:定义内部接口
1 interface IChannel{//定义接口 2 public void send(IMessage msg);//发送消息 3 interface IMessage{//内部接口 4 public String getContent();//获取消息内容 5 } 6 } 7 class ChannelImpl implements IChannel{ 8 public void send(IMessage msg){ 9 System.out.println("发送消息:"+msg.getContent()); 10 } 11 class MessageImpl implements IMessage{ 12 public String getContent(){ 13 return "https://www.cnblogs.com/Mufasa"; 14 } 15 } 16 } 17 18 public class Main { 19 public static void main(String[] args) { 20 IChannel channel=new ChannelImpl(); 21 channel.send(((ChannelImpl)channel).new MessageImpl()); 22 } 23 }
范例:观察内部抽象类下面继续观察一个内部的抽象类,内部抽象类可以定义在普通类、抽象类、接口内部都是可以的。
1 interface IChannel{//定义接口 2 public void send();//发送消息 3 abstract class AbstractMessage{ 4 public abstract String getContent(); 5 } 6 } 7 8 class ChannelImpl implements IChannel{ 9 public void send(){ 10 AbstractMessage msg=new MessageImpl(); 11 System.out.println(msg.getContent()); 12 } 13 class MessageImpl extends AbstractMessage{ 14 public String getContent(){ 15 return "https://www.cnblogs.com/Mufasa"; 16 } 17 } 18 19 } 20 21 public class Main { 22 public static void main(String[] args) { 23 IChannel channel=new ChannelImpl(); 24 channel.send(); 25 } 26 }
范例:接口内部进行接口实现内部类还有一个更有意思的结构,即:如果现在定义了一个接口,那么可以在内部类实现该接口,在JDK1.8之后接口中追加了static方法可以不受到实例化对象的控制,现在就可以利用此特性来完成功能。
1 interface IChannel{//定义接口 2 public void send();//发送消息 3 class ChannelImpl implements IChannel{ 4 @Override 5 public void send() { 6 System.out.println("https://www.cnblogs.com/Mufasa"); 7 } 8 } 9 public static IChannel getInstance(){ 10 return new ChannelImpl(); 11 } 12 } 13 public class Main { 14 public static void main(String[] args) { 15 IChannel channel=IChannel.getInstance(); 16 channel.send(); 17 } 18 }
3,static定义内部类
如果说在内部类上使用了static定义,那么这个内部类就变成了“外部类”,static定义的都是独立于类的结构,所以该类的结构就相当于是一个独立的程序类了。需要注意的是。static定义的不管是类还是方法只能访问static成员,所以static定义的内部类只能访问外部类中的static属性或方法。
范例:使用static定义内部类
1 class Outer{ 2 private static final String MSG="www.cnblog.com/Mufasa"; 3 static class Inner{ 4 public void print(){ 5 System.out.println(Outer.MSG); 6 } 7 } 8 }
1 外部类.内部类 内部类对象 = new 外部类.内部类();
这个时候的类名称带有“.”这个时候的Inner类是一个独立的类,如果此时要想实例化Inner类对象,只需要根据“外部类.内部类”实例化对象即可
范例:实例化static内部类对象
1 class Outer{ 2 private static final String MSG="www.cnblog.com/Mufasa"; 3 static class Inner{ 4 public void print(){ 5 System.out.println(Outer.MSG); 6 } 7 } 8 } 9 10 public class Main { 11 public static void main(String[] args) { 12 Outer.Inner inner=new Outer.Inner();//只要见到类名称上有点的——内部类,可以直接实例化-static 13 inner.print(); 14 } 15 }
如果以static定义内部类的形式来讲并不常用,static定义内部接口的形式最为常用。以后在开发之中如果发现类名称上提供有“.”,首先应该想到这是一个内部类的结构,如果可以直接实例化应该立刻认识到这是一个static定义的内部类。
范例:使用static定义内部接口
1 interface IMessageWarp{//消息包装 2 static interface IMessage{ 3 public String getContent(); 4 } 5 static interface IChannel{ 6 public boolean connect(); 7 } 8 public static void send(IMessage msg,IChannel channel){ 9 if (channel.connect()){ 10 System.out.println(msg.getContent()); 11 }else{ 12 System.out.println("消息通道无法建立,消息发送失败!"); 13 } 14 } 15 } 16 class DefaultMessage implements IMessageWarp.IMessage{ 17 @Override 18 public String getContent() { 19 return "www.cnblog.com/Mufasa"; 20 } 21 } 22 class NetChannel implements IMessageWarp.IChannel{ 23 @Override 24 public boolean connect() { 25 return true; 26 } 27 } 28 29 public class Main { 30 public static void main(String[] args) { 31 IMessageWarp.send(new DefaultMessage(),new NetChannel()); 32 } 33 }
4,方法中定义内部内部类之所以使用static定义我们的内部接口,主要是因为这些操作是属于一组相关的定义,有了外部接口之后可以更加明确的描述出这些接口的主要目的和主要功能。内部接口出现的形式较多!!!
内部类可以在任意的结构中进行定义,这就包括:类中,方法中,代码块中,但是从实际开发中从方法中定义内部类的形式较多。
范例:观察在方法中定义的内部类
1 class Outer{ 2 private String msg="www.cnblog.com/Mufasa"; 3 public void fun(long time){ 4 class Inner{//内部类 5 public void print(){ 6 System.out.println(Outer.this.msg); 7 System.out.println(time); 8 } 9 } 10 new Inner().print();//方法中直接实例化内部类对象 11 } 12 } 13 14 public class Main { 15 public static void main(String[] args) { 16 new Outer().fun(158273L);//注意需要加上括号 17 } 18 }
范例:在JDK1.8以前的程序结构此时在fun()方法内部提供有Inner内部的类的定义,并且可以发现内部类可以直接访问外部类中的私有属性也可以直接访问方法中的参数,但是对于方法中的参数直接访问是从JDK1.8开始支持的,而在JDK1.8之前,如果方法中定义的内部类要想访问方法中的参数则参数前必须追加final。
1 class Outer{ 2 private String msg="www.cnblog.com/Mufasa"; 3 public void fun(final long time){ 4 final String info="这个是JDK1.8以前的版本"; 5 class Inner{//内部类 6 public void print(){ 7 System.out.println(Outer.this.msg); 8 System.out.println(time); 9 System.out.println(info); 10 } 11 } 12 new Inner().print();//方法中直接实例化内部类对象 13 } 14 } 15 16 public class Main { 17 public static void main(String[] args) { 18 new Outer().fun(158273L); 19 } 20 }
之所以取消这样的限制,主要是为了其扩展的函数式编程准备的功能。
5,匿名内部类
匿名内部类是一种简化的内部类的处理形式,其主要是在抽象类和接口的子类上使用的。
范例:观察一个基本的程序结构
1 interface IMessage{ 2 public void send(String str); 3 } 4 class MessageImpl implements IMessage{ 5 public void send(String str){ 6 System.out.println(str); 7 } 8 } 9 public class Main { 10 public static void main(String[] args) { 11 IMessage msg=new MessageImpl(); 12 msg.send("这是个普通继承接口类"); 13 } 14 }
范例:使用匿名内部类如果说现在IMessage接口中的MessageImpl子类只使用唯一的一次,那么是否还有必要将其定义为单独的类。那么在这样的要求下就发现这个时候定义的子类是有些多余了,所以就可以利用匿名内部类的形式类解决此类问题。
1 interface IMessage{ 2 public void send(String str); 3 } 4 5 public class Main { 6 public static void main(String[] args) { 7 IMessage msg=new IMessage(){ 8 public void send(String str){ 9 System.out.println(str); 10 } 11 }; 12 msg.send("这是个匿名内部类");//类没有名称 13 } 14 }
范例:在接口中直接使用定义匿名内部类有些时候为了更加方便的体现出匿名内部类的使用,往往可以利用静态方法做一个内部的匿名内部类实现。
1 interface IMessage{ 2 public void send(String str); 3 public static IMessage getInstance(){ 4 return new IMessage() { 5 @Override 6 public void send(String str) { 7 System.out.println(str); 8 } 9 }; 10 } 11 } 12 13 public class Main { 14 public static void main(String[] args) { 15 IMessage.getInstance().send("这是一个在接口中实现的匿名内部类"); 16 } 17 }
与内部类相比匿名内部类只是一个没有名字的只能使用一次的,并且结构固定的一个子类操作。