Java——内部类详解

内部类定义

将一个类的定义放在另一个类的内部

 

为什么要内部类?

1.每个内部类自身都能单独的继承基类或实现接口,而不受外部类的约束

2.通过内部类加上接口,可以很好的实现多继承的效果。

3.

public interface Contents {  
    int value();  
}  
public class Goods {  
    private class Content implements Contents {  
        private int i = 11;  
        public int value() {  
            return i;  
        }  
    }  
    public Contents cont() {  
        return new Content();  
    }  
}  
class TestGoods {  
    public static void main(String[] args) {  
        Goods p = new Goods();  
        Contents c = p.cont();  
        Destination d = p.dest("Beijing");  
    }  
} 

在main方法中,通过外部类对象直接对内部类进行操作,你甚至连这个内部类的名字都没有看见。及可以隐藏你不想让别人知道的操作,也即封装性。

4.

一个内部类对象可以访问创建它的外部类对象的内容,甚至包括私有变量!这是一个非常有用的特性,为我们在设计时提供了更多的思路和捷径。要想实现这个功能,内部类对象就必须有指向外部类对象的引用。Java编译器在创建内部类对象时,隐式的把其外部类对象的引用也传了进去并一直保存着。这样就使得内部类对象始终可以访问其外部类对象,同时这也是为什么在外部类作用范围之外向要创建内部类对象必须先创建其外部类对象的原因。

有人会问,如果内部类里的一个成员变量与外部类的一个成员变量同名,也即外部类的同名成员变量被屏蔽了,怎么办?没事,Java里用如下格式表达外部类的引用:

outerClass.this

 

 

和外部类关联

当你创建了内部类后,它就和外部类有了某种联系,确切的说就是内部类可以直接访问外部类的所有元素,包括方法、属性等,反之是不成立的,也就是说,外部类不可以直接访问内部类元素

我们可以使用 .this 来获得外部类的引用,使用 .new 内部类自身的引用

public class OutterClass {
 
    public class InnerClass {
        public OutterClass getOutterClass() {
            return OutterClass.this;  // 使用 .this 获取OutterClass实例
        }
    }
 
    public static void main(String[] args) {
        OutterClass outterClass = new OutterClass();
        InnerClass innerClass = outterClass.new InnerClass();  //使用 .new 获取InnerClass实例
    }
 
}

同时,我们也发现了在外部类作用范围之外得到内部类对象的第一个方法,那就是利用其外部类的方法创建并返回。那么还有没有别的方法呢?当然有,其语法格式如下:

outerObject=new outerClass(Constructor Parameters);

outerClass.innerClass innerObject=outerObject.new InnerClass(Constructor Parameters);

注意在创建非静态内部类对象时,一定要先创建起相应的外部类对象

 

当我想在外部类作用范围之外得到内部类对象的第一个方法,那就利用其外部类的方法创建并返回。上例中的cont()方法就是这么做的。那么还有没有别的方法呢?当然有,其语法格式如下:

 注意在创建非静态内部类对象时,一定要先创建起相应的外部类对象。

public class OutterClass {
 
    public class InnerClass {
        public OutterClass getOutterClass() {
            return OutterClass.this;  // 使用 .this 获取OutterClass实例
        }
    }
 
}
 public static void main(String[] args) {
        OutterClass outterClass = new OutterClass();
        outerClass.innerClass innerObject=outerObject.new InnerClass(Constructor Parameters);  //使用 .new 获取InnerClass实例
    }

 

 

内部类分类

1、成员内部类

成员内部类是最普通、常见的内部类,它被当做是外部类的一个普通成员,上面举例说明的都是成员内部类,它可以无限制的访问外部类的所有元素

使用成员内部类要注意以下两点:

  1. 成员内部类的元素(方法和变量)不能用static修饰;

  2. 成员内部类依赖于外部类,也就是说只有创建了外部类才能创建内部类;

public class OutterClass {
 
    public class InnerClass{
        public void method1(){
            System.out.println("inner method");
        }
    }
 
    public static void main(String[] args) {
        OutterClass outterClass = new OutterClass();
        InnerClass innerClass = outterClass.new InnerClass();
        innerClass.method1();
    }
}

2、方法内部类

当你实现了某类型的接口,于是可以方便返回对接口实例的引用;或者你需要创建一个类来辅助你解决一个复杂的问题时,同时又不希望这个内部类是公用的,这时方法内部类就派上用场了。

注意:

  1. 方法内部类不能有访问修饰符;

  2. 方法内部类中的元素不能用static修饰;

//方法内部类
public class OutterClass {
 
    public BaseClass out() {
        class InnerClass implements BaseClass {
            private String name;
 
            public InnerClass(String name) {
                this.name = name;
            }
 
            public void inner() {
                //TODO
            }
        }
        return new InnerClass("");
    }
 
    public static void main(String[] args) {
        OutterClass outterClass = new OutterClass();
        BaseClass out = outterClass.out();
    }
 
}
 
interface BaseClass {
 
}

 

3、匿名内部类

匿名内部类是一个没有名字的方法内部类

注意:

1.方法内部类不能有访问修饰符;

2.方法内部类中的元素不能用static修饰;

3.匿名内部类没有构造器,因为类名都没有;

但是如果这个匿名内部类继承了一个只含有带参数构造函数的父类,创建它的时候必须带上这些参数,并在实现的过程中使用super关键字调用相应的内容

4.匿名内部类必须实现一个接口或抽象类;

public class OutterClass {
 
    public BaseClass out() {
        return new BaseClass() {  //看起来是不是怪怪的……
            private int id = 15;
 
            public void test() {
                System.out.println(id);
            }
        };
    }
    
    public static void main(String[] args) {
        OutterClass outterClass = new OutterClass();
        outterClass.out();
    }
}
 
interface BaseClass {
 
}

那么我如果想初始化它的成员变量怎么办呢?

1.如果是在一个方法的匿名内部类,可以利用这个方法传进你想要的参数,不过记住,这些参数必须被声明为final。

2.将匿名内部类改造成有名字的局部内部类,这样它就可以拥有构造函数了。

3.在这个匿名内部类中使用初始化代码块。

 

4、静态内部类(嵌套类)

成员内部类加上static修饰久病成了静态内部类,静态内部类与非静态内部类最大的区别是,非静态内部类在代码编译后就会包含一个指向它的外部类的引用,但是静态内部类是没有的

注意

    1.静态内部类不可以使用外部类的非static元素(变量、方法);

    2.静态内部类可以直接创建,不需要依赖于外部类的创建;

public class OutterClass {
 
    private static int code;
    private String name;
 
    public static class InnerClass{
        /*  静态内部类的内部可以存在static元素  */
        private static String messge;
 
        public static void method1(){
 
            /*  静态内部类只能访问外部类的static元素  */
            System.out.println(code);
 
            /*  静态内部类不可以访问外部类的非static元素  */
            //  System.out.println(name);
        }
    }
}
public class BaseClass {
    public static void main(String[] args) {
        /*  静态内部类不用依赖于外部类的创建  */
        OutterClass.InnerClass innerClass = new OutterClass.InnerClass();
        innerClass.method1();
    }
}

 

内部类的实例化 

一、

/*  外部类的内部实例化内部类  */
public static void main(String[] args) {
    InnerClass innerClass = new InnerClass();
    innerClass.method1();
}
/*  外部类使用内部类  */
public static void main(String[] args) {
     /* 如果是静态内部类,直接 */
    OutterClass.InnerClass innerClass = new OutterClass.InnerClass();
    innerClass.method1();
     
     /* 如果是普通的内部类,则 */
     OutterClass.InnerClass innerClass = new OutterClass().new InnerClass();
     innerClass.method1();
}

二、

1.内部类是私有类的时候,只能通过其外部类方法创建实例

public class InnerClassTest {
public static void main(String[] args) {
	TalkingClock clock=new TalkingClock(1000, true);
	clock.start();
	JOptionPane.showMessageDialog(null, "Quit proj");
	System.exit(0);
	
}
	
}
class TalkingClock{
	private int interval;
	private boolean beep;
	public TalkingClock(int interval,boolean beep)
	{
		this.interval=interval;
		this.beep=beep;
	}
	public void start() {
		ActionListener listener=new TimePrinter();
		Timer t=new Timer(interval,listener);
		t.start();
	}
	private class TimePrinter implements ActionListener{
		public void actionPerformed(ActionEvent event) {
			System.out.println("At the tone,the time is "+new Date());
			if(beep)Toolkit.getDefaultToolkit().beep();
		}
	}
}

2.内部类是公有方法时,除了可以仿照上方案例创建外,还可以

Talking jabberer=new TalkingClock(1000,true);
TalkingClock.TimePrinter listener=jabberer.new TimePrinter();

 

关于内部类 

1.内部类可以有多个实例,每个实例都有自己的状态信息,而且与外部类相互独立;

2.一个外部类中可以让多个内部类以不同的方式继承基类或实现接口;

3.内部类的创建并不总是依赖于外部类的创建,这点上面强调过;

4.内部类是一个独立的实体类,我们编译下上面的OutterClass类发现生成了两个独立的class文件

OutterClass$InnerClass.class
OutterClass.class

 

可能的内存泄漏 

当外部类与内部类生命周期不一致的时候很有可能发生内存泄漏,例如在一个Activity启动一个Thread执行一个任务,因为Thread是内部类持有了Activity的引用,当Activity销毁的时候如果Thread的任务没有执行完成,造成Activity的引用不能释放,Activity不能被释放而引起了内存泄漏。这种情况下可以通过声明一个static的内部类来解决问题,从反编译中可以看出,声明为static的类不会持有外部类的引用,如果你想使用外部类的话,可以通过软引用的方式保存外部类的引用。
 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值