详解 java 内部类



定义 :将一个类的定义放在另一个类中 .

 

首先说如何创建一个内部类的实例: 从外部类的非静态方法之外的人一位置创建某个内部类的对象,那么必须像在main()方法中那样,具体的致命这个对象的类型:

OuterClassName.InnerClassName

外部类可以访问内部类中的信息那是没什么疑问的,可是内部类也可以访问外部类的信息,包括私有信息,当生成一个内部类的对象时,此对象与制造它的外围对象(enclosing object)

之间就有了一种联系,所以它能 访问其外围对象的所有成员,而不需要特殊条件。    实现机制:当某个外围类的对象创建了一个内部类对象时,此对象会秘密持有一个对外围对象的引用。

下面给出一个例子

package com.meran.thinkingInJava.innerClass;

public class Test1 {
	private String label="合肥";
	class Destination{
		private String label;
	    Destination(String whereTo){
	    	label=whereTo;
	    }
	    String readFatherLabel(){
	    	return Test1.this.label;//父类.this相当于 父类中的this
	    }
	    String readLabel(){
	    	return label;
	    }
	}
	public Destination getDest(String label){
		return new Destination(label);
	}
	public void ship(String dest){
	        Destination dest1=new Destination(dest);
	        System.out.println(dest1.label);
	}
	static class Context{
		private String label="静态内部类不需要内部类对外部类对象的引用";
		public String getLabel(){
			return label;
		};
	}

	public static void main(String [] args){
		Test1 test=new Test1();
		test.ship("北京");
		Test1 test1=new Test1();
		Test1.Destination dest=test1.getDest("上海");
		Destination dest1=test1.getDest("南京");
		System.out.println(dest.readLabel());
		System.out.println(dest1.readFatherLabel());
	    Destination dest2=test1.new Destination("哈尔滨");//直接创建内部类对象。
	    Context c=new Context();
	    System.out.println(c.getLabel());

		
	}

}


 

北京
上海
合肥
静态内部类不需要内部类对外部类对象的引用


 

如上面结果所写, 静态内部类的创建不需要内部类对外部对象的引用。

 

 

下面来说下

.this .new

.this  父类对象实例。this 相当于当前父类对象的引用     父类对象实例。new 用于创建内部类。   当类为静态内部类(嵌套类)的时候,不需要.new方法不需要对父类对象的引用。

 

 

内部类与向上转型。

当将内部类向上转型为其基类,尤其是转型为一个接口的时候,内部类就有了用武之地(从实现了某个几口的对象,得到对此接口的引用)这是因为内部类-----某接口实现-------能够完全不可见并且不可用。所得的只是指向接口的引用,可以很方便的隐藏实现。

 

 

 

下面一段代码

package com.meran.thinkingInJava.innerClass;
/*
 * 可以看出 destination 方法返回的一个向Destination类型的上转型
 */

abstract class  Destination{
	abstract  String readLabel();
	
}
class Context {
	private String label;
	public Context(String s)
	{   
		System.out.println("调用Context构造方法");
		this.label=s;
	}
	public void printLabel(){
		  System.out.print("父类printLabel被调用打印父类中label");
    System.out.println(label);
	}
}
public class Test2 {
	
     public Context context(String label,final String _label1){
    	 return new Context(label){
    		 String label1;
    		 {   
    			 System.out.println("子类实例化函数被调用");
    			 label1=_label1;
    		 }
             
                       public void printLabel(){
                    	   System.out.println("子类printLabel被调用 打印子类中label1"+label1);
          super.printLabel();
    	 }
     };
     }
	
	public Destination destination(final String dest,final float price){
		return new Destination(){
        private int cost;
        //小括号中代码是对象初始化代码
          {
            cost=Math.round(price);
            if(cost>100)
            	System.out.println("over budget!");
	         }
        private String label=dest;
        public String readLabel(){return label;}
		};
	}
	public static void main(String []args){
		Test2 t=new Test2();
		Destination d=t.destination("Tasmania",101.395F);
		System.out.println(d.readLabel());
		Context c=t.context("小明的爸爸", "小明");
		c.printLabel();
		
	}

	                                       

}


 

over budget!
Tasmania
调用Context构造方法
子类实例化函数被调用
子类printLabel被调用 打印子类中label1小明
父类printLabel被调用打印父类中label小明的爸爸


 

Test2中public Context context(String label,final String _label1)方法  返回的是Context 类型的引用,这句话的意思相当于,创建一个继承自Context的匿名类对象。这个类的作用于今夏怒public Context context(String label,final String _label1) 方法内部。 注意这个方法的两个参数, 第一个参数没加 final ,因为它是要被 Context类调用的, 而 _label1这个变量则是被我们的匿名内部类访问的,所以它要被设置为final类型。 在匿名内部类中无法定义构造器,----_-----!!!!!!因为我们连类名都不知道,所以只能调用父类构造器,或者使用实例初始化块,这段代码的作用就相当于构造器。

 

 

嵌套类:如果不需要内部类对象与其外部类对象之间有联系,可以把它声明为static类型,就通常称为嵌套类。

潜逃类意味着:1.要创建嵌套类的类的对象,并不需要其外围类的对象 2.不能从嵌套类的对象访问非静态的外围类对象

 

 

 

1。接口内部的类

正常情况下不可以在接口中放任何代码,接口中热不和类都是static 和public的,因为类是static的 只是相当于把潜逃类放到了接口的命名空间中,这样坐可以创建公共代码,为不同接口的实现所共用。

 

 

利用内部类实现多重继承

每个内部类都能独立的继承子一个(接口)的实现,所以无论外部类是否已经继承了某(接口的)实现,对内部类没有影响。

接口解决的 “多重继承问题”

 

interface A{};
interface B{};
public class x implements A,B{];

public class x implements A{
B getB{
//匿名内部类实现
return new B():
}
}
//实现多继承
class D{}
abstract F{}
class Z extends D{
E makeE(){
return new E(){};}
}


 

 

闭包与回调

闭包(closure)是一个可调用的对象。它记录了一些信息,这些信息来自创建它的作用域(内部类是面向对象的闭包),因为它不但了解外部类信息,还包含一个对外部类的引用,可以调用外部类中的所有字段和方法。

package com.meran.thinkingInJava.innerClass;

interface Incrementable{
	void increment();
}

class Callee1 implements Incrementable{
	private int i=0;
	 
	public void increment(){
		i++;
		System.out.println(i);
	}
}

class MyIncrement{
	public void increment(){ System.out.println("Another method");}
	static void f(MyIncrement mi){mi.increment();};
}

class Callee2 extends MyIncrement{
private int i=0;
public void increment(){
super.increment();
i++;
System.out.println(i);
}
private class Closure implements Incrementable{
	public void increment(){
Callee2.this.increment();
}

}
Incrementable getCallbackReference(){
	return new Closure();
}

}
class Caller{
	private Incrementable callbackReference;
    Caller(Incrementable cbh){callbackReference=cbh;}
    void go(){callbackReference.increment();}
}
public class CallBacks {
	public static void main(String [] args){
		Callee1 c1=new Callee1();
		Callee2 c2=new Callee2();
		MyIncrement.f(c2);
		Caller caller1=new Caller(c1);
		Caller caller2=new Caller(c2.getCallbackReference());
		caller1.go();
		caller1.go();
		caller2.go();
		caller2.go();
		
	}

}



 

Another method
1
1
2
Another method
2
Another method
3


这个例子掩饰了外围类实现接口与内部类实现接口间的区别。 Callee2 继承自MyIncrement 后者已经有了一个increment() 方法,并且与incrementable 接口完全不相关。如果Calle2继承了MyIncrement ,就不能为了Incrementable 用途而覆盖 increment()s覆盖increment 方法,于是只能使用内部类独立实现increment。当创建了一个内部类的时候并没有在外围类的接口中添加东西,也没有修改外围接口。

 

内部类Closure 实现了Incrementable ,以提供一个”钩子“(hook)-------而且是一个安全的钩子。无论谁获得 Incrementable 都只能使用 increment()方法。

 

Caller 的构造器需要一个Incrementable的引用类型作为参数,然后再以后的某个时刻,Caller对象可以使用此引用回调Callee类

 

内部类的继承: java 编程思想212.

内部类可以被覆盖么??: 详见213页。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值