内部类
1、内部类基本概念
虽然在类之中的基本组成就是成员属性与方法,但是在任何的语言里面结构也是允许嵌套的,所以在一个类的内部可以定义其他类,这样的类就成为内部类
内部类的基本定义
如果说道内部类肯定其本身就是一个独立且完善的类结构,在一个类的内部除了属性和方法之外可以继续使用class定义内部类
例:内部类的基本定义
public class JavaDemo{
public static void main(String [] args){
Outer out = new Outer(); //实例化外部类对象
out.fun(); //调用外部类中的方法
}
}
class Outer{ //外部类
private String msg = "www.shenmenglin.com"; //私有成员属性
public void fun(){ //普通方法
Inner in = new Inner(); //实例化内部类对象
in.print(); //调用内部类方法
}
class Inner{ //在Outer类的内部定义了Inner类
public void print(){
System.out.println(Outer.msg);
}
}
}
从整个的代码上实际上发现内部类的结构并不难理解,甚至可以说其结构与普通类一样。
但是从整体的代码结构上来讲内部类的结构并不合理,所以内部类本身最大的缺陷在于破坏了程序的结构,但是破坏需要有目的的破坏,那么它也会有一定的优势
如果想要更好的观察内部类的优势,就可以将内部类拿到外面来
例:将上面的程序分为两个类
public class JavaDemo{
public static void main(String [] args){
Outer out = new Outer(); //实例化外部类对象
out.fun(); //调用外部类中的方法
}
}
class Outer{ //外部类
private String msg = "www.shenmenglin.com"; //私有成员属性
public void fun(){ //普通方法
//思考五:需要将当前对象Outer传递到Inner类之中
Inner in = new Inner(this); //实例化内部类对象
in.print(); //调用内部类方法
}
//思考一:msg属性如果要被外部访问需要提供有getter方法
public String getMsg(){
return msg;
}
}
class Inner{ //在Outer类的内部定义了Inner类
//思考三:Inner这个类对象实例化的时候需要Outer类的引用
private Outer out;
//思考四:应该通过Inner类的构造方法获取Outer类对象
public Inner(Outer out){
this.out = out;
}
public void print(){
//思考二:如果想要调用外部类中的getter方法,那么一定需要有Outer类的对象
System.out.println(new Outer().getMsg());
}
}
可以发现,整体的操作之中,折腾半天主要的目的就是为了让Inner这个内部类可以访问Outer这个类中的私有属性
但是如果不用内部类的时候整体代码非常的麻烦,所以可以得出内部类的优点:轻松访问外部类中的私有属性
2、内部类的相关说明
现在已经清楚的认识到了内部类的优势以及结构,那么随后需要对内部类进行一些相关说明,现在所定义的内部类都属于普通的内部类形式
普通类内部往往也会提供有属性和方法,需要注意的是,内部类虽然可以方便的访问外部类中的私有成员或私有方法,同理,外部类也可以轻松访问内部类中而定私有成员或私有方法
例:外部类访问内部类中的私有属性
public class JavaDemo{
public static void main(String [] args){
Outer out = new Outer(); //实例化外部类对象
out.fun(); //调用外部类中的方法
}
}
class Outer{ //外部类
private String msg = "www.shenmenglin.com"; //私有成员属性
public void fun(){ //普通方法
Inner in = new Inner(); //实例化内部类对象
in.print(); //调用内部类方法
System.out.println(in.info);
}
class Inner{ //在Outer类的内部定义了Inner类
private String info = "今天天气不好!!!";
public void print(){
System.out.println( Outer.this.msg);
}
}
}
使用了内部类之后,内部类与外部类之间的私有操作的访问就不在需要通过setter和getter以及其他的间接方式完成了,可以直接进行处理操作
但是内部类本身也属于一个类,虽然在大部分的情况下内部类往往是被外部类包裹的,但是外部依然可以产生内部类的实例化对象,而此时内部类实例化对象的格式如下:
外部类.内部类 内部类对象 = new 外部类().new 内部类;
在内部类编译完成之后会自动形成一个“Outer
I
n
n
e
r
.
c
l
a
s
s
”
类
文
件
,
其
中
“
Inner.class”类文件,其中“
Inner.class”类文件,其中“”这个符号换到程序之中就变成了“.”
所以内部类全称:“外部类.内部类”.内部类与外部类之间克以直接进行私有成员的访问,这样一来内部类如果要是提供有实例化对象了,一定要先保证外部类已经实例化了
public class JavaDemo{
public static void main(String [] args){
Outer.Inner in = new Outer().new Inner();
in.print();
}
}
class Outer{ //外部类
private String msg = "www.shenmenglin.com"; //私有成员属性
class Inner{ //在Outer类的内部定义了Inner类
public void print(){
System.out.println( Outer.this.msg);
}
}
}
如果此时Inner类只允许Outer类来使用,那么在这样的情况下就可以使用private来进行私有定义
class Outer{ //外部类
private String msg = "www.shenmenglin.com"; //私有成员属性
private class Inner{ //在Outer类的内部定义了Inner类
public void print(){
System.out.println( Outer.this.msg);
}
}
}
此时的Inner类无法在外部进行使用
在Java之中类做为最基础的结构体实际上还有与之类似的抽象类或者接口,抽象类与接口中都是可以定义内部结构的
例:定义内部类结构
interface IChannel{
void send(IMessage msg);
interface IMessage{
String getContent();
}
}
class ChannelImpl implements IChannel{
public void send(IMessage msg){
System.out.println("发送消息:" + msg.getContent());
}
class MessageImpl implements IMessage{
public String getContent(){
return "www.shenemnglin.com";
}
}
}
public class JavaDemo{
public static void main(String [] args){
IChannel channel = new ChannelImpl();
channel.send(((ChannelImpl)channel).new MessageImpl());
}
}
内部抽象类可以定义在普通类、抽象类、接口内部
例:内部抽象类
interface IChannel{
void send();
abstract class AbstractMessage{
abstract String getContent();
}
}
class ChannelImpl implements IChannel{
public void send(){
AbstractMessage msg = new MessageImpl();
System.out.println("发送消息:" + msg.getContent());
}
class MessageImpl extends AbstractMessage{
public String getContent(){
return "www.shenemnglin.com";
}
}
}
public class JavaDemo{
public static void main(String [] args){
IChannel channel = new ChannelImpl();
channel.send();
}
}
内部类还有一些更为有意思的结构,即:如果现在定义了一个接口,那么可以在内部利用类实现该接口,在JDK1.8之后接口中追加了static方法可以不受实例化对象控制,现在就可以利用此特性来完成功能
例:接口内部进行接口实现
interface IChannel{
void send();
class ChannelImpl implements IChannel{
public void send(){
System.out.println("发送消息:www.shenmenglin.com");
}
public static IChannel getInstance(){
return new ChannelImpl();
}
}
}
public class JavaDemo{
public static void main(String [] args){
IChannel channel = IChannel.getInstance();
channel.send();
}
}
内部类是一种非常灵活的定义结构,只要你的须发满足了,各种需求都可以帮你实现
3、static定义内部类
如果说现在在内部类上使用了static定义,那么这个内部类就变成了“外部类”,static定义的都是独立于类的结构,所以该类结构就相当于一个独立的程序类了。
需要注意的是,static定义的不管是类还是方法只能够访问static成员,所以定义的static内部类只能够访问static的成员或方法
例:使用static定义内部类
class Outer{
private static final String MSG = "www.shenemnglin.com";
static class Inner{
public void print(){
System.out.println(Outer.MSG);
}
}
}
这个时候的Inner类是一个独立的类,如果此时想要实例化Inner类对象,只需要根据“外部类.内部类”的结构实例化对象即可,
格式如下:
外部类.内部类 内部类对象 = new 外部类.内部类() ;
例:实例化static内部类对象
class Outer{
private static final String MSG = "www.shenemnglin.com";
static class Inner{
public void print(){
System.out.println(Outer.MSG);
}
}
}
public class JavaDemo{
public static void main(String [] args){
Outer.Inner in = new Outer.Inner();
in.print();
}
}
以后在开发之中如果发现名称上提供有“.”首先应该想到这是一个内部类的结构,如果可以直接进行实例化,则应该立刻认识到这是一个static定义的内部类
但是这种结构并不常用,static定义的内部接口的形式是最为常用的
例:使用static定义内部接口
interface IMessageWarp{ //消息包装
static interface IMessage{
String getContent();
}
static interface IChannel{
boolean connect(); //消息的发送通道
}
public static void send(IMessage msg,IChannel channel){
if(channel.connect()){
System.out.println(msg.getContent());
}else{
System.out.println("消息通道无法建立,消息发送失败!!!");
}
}
}
class DefaultMessage implements IMessageWarp.IMessage{
public String getContent(){
return "www.shenmenglin.com";
}
}
class NetChannel implements IMessageWarp.IChannel{
public boolean connect(){
return true ;
}
}
public class JavaDemo{
public static void main(String [] args){
IMessageWarp.send(new DefaultMessage(),new NetChannel());
}
}
之所以使用static定义的内部接口,主要是因为这些操作是属于一组相关的定义,有了外部接口之后可以更加明确的描述出这些接口的主要功能
4、方法中定义内部类
内部类可以在任意的接口中进行定义,这就包括了:类中,方法中,代码块中
但是在实际的开发之中,在方法中定义内部类的形式较多
例:在方法中
class Outer{
private String msg = "www.shenmenglin.com";
public void fun(String name){
class Inner{ //内部类
public void print(){
System.out.println(Outer.this.msg);
System.out.println(name);
}
}
new Inner().print(); //方法中直接实例化内部类对象
}
}
public class JavaDemo{
public static void main(String [] args){
new Outer().fun("沈梦琳");
}
}
此时在fun()方法内提供有Inner内部类的定义,并且可以发现内部类可以直接外部类中的私有属性也可以直接访问中的参数,
但是对于方法中的参数直接访问是从JDK1.8开始支持的,而在JDK1.8之前,如果方法中定义的内部类想要访问方法中的参数则参数前必须追加final
例:在JDK1.8以前的程序结构
之所以取消这样的限制,主要是为了其扩展的函数式编程准备的功能
5、匿名内部类
匿名内部类是一种简化的内部类的处理形式,其主要是在抽象类和接口的子类上使用的
例:一个基本的程序结构
interface IMessage {
void send(String str);
}
class MessageImpl implements IMessage{
public void send(String str){
System.out.println(str);
}
}
public class JavaDemo{
public static void main(String [] args){
IMessage msg = new MessageImpl();
msg.send("www.shenmenglin.com");
}
}
如果说显示IMessage接口中的MessageImpl子类只是用唯一的一次,那么是否还有必要将其定义为单独的类,那么在这样的要求下,就发现这个时候定义 的子类是有些多余了,所以就可以利用匿名内部类的形式来解决此问题
例:使用匿名内部类
interface IMessage{
void send(String str);
}
public class JavaDemo{
public static void main(String args [] ){
IMessage msg = new IMessage(){
public void send(String str){
System.out.println("www.shenmenglin.com");
}
};
msg.send("www.shenmenglin.com");
}
}
有些时候为了更加方便的体现出匿名内部类的使用,往往可以里哟i你静态方法做一个内部的匿名内部类实现
例:在接口中直接定义匿名内部类
interface IMessage{
void send(String str);
static IMessage getInstance(){
return new IMessage(){
public void send(String str){
System.out.println(str);
}
};
}
}
public class JavaDemo{
public static void main(String args [] ){
IMessage.getInstance().send("www.shenmenglin.com");
}
}
与内部类相比匿名内部类只是一个没有名字的只能使用一次的,并且结构固定的一个子类