`

彻底搞清楚java的内部类

阅读更多
内部类允许在一个类中定义另一个类。允许一个类成为另一个类的成员。内部类实例可以访问外部类的所有成员,即使是private的成员。

常规的(非static、非匿名的、方法是本地的)内部类:
class Outer{
class Inner{
 //public static void main(String[] args){ } // 如果加上这一句会出现编译错误,因为不能有静态方法
}
}


如果使用java命令 :javac Outer.java
会生成两个类文件:Outer.class,Outer$Inner.class
但是普通方法不能访问这个内部类文件,如不能使用java Outer$Inner来运行这个内部类的main方法,因为常规内部类不能有任何类型的静态声明(包括静态方法和静态变量)。访问内部类的唯一方法是通过外部类的一个活实例!!
为了创建内部类的实例。必须有一个与这个内部类相关的外部类实例。这一规则没有例外!!

public class Outer{
private int x = 7;
public static void main(String[] args){ //从外部类实例代码外(包括外部类的静态方法),内部类

名称必须包含外部类名称
Outer o = new Outer();
Outer.Inner i = o.new Inner();
i.seeOuter();
}

public void makeInner(){ //从外部类实例方法内,以正常方式使用内部类名称
Inner in = new Inner();
in.seeOuter();
}

class Inner{
public void seeOuter(){
System.out.println("Outer x is "+x);
System.out.println("Inner is "+this); //内部类引用自身实例
System.out.println("Outer is "+Outer.this); //内部类引用外部类当前实例
}
}
} //执行结果:Outer x is 7


正常情况下,一个对象如何引用它自己?使用this引用。
1,this只能从实例代码内使用,也就是说它不能出现在static代码内
2,this引用是对当前执行对象的引用。
3,this引用是对象把对其自己的引用作为方法参数传递给其他代码的一种方法。
应用域内部类的成员修饰符:可以有final,abstract,public,private,protected,static,strictfp


方法本地内部类:
常规内部类的范围限制在另一个类的大括号之内,但在任何方法代码之外(也就是与被声明的实例变量有相同的级别),但是,也可以在方法内定义内部类:也叫做方法本地内部类
public class Outer{
private String x = "Outer";
public static void main(String[] args){
Outer o = new Outer();
o.doStuff();
}

public void doStuff(){

int a = 0;
class Inner{  //如果加public,会出现compile error

public void seeOuter(){
System.out.println("Outer x is "+x); //可以访问外部类的变量
System.out.println("doStuff a is "+a); //编译错误,不能访问本地方法的局部变量,必须声明为final类型才可以,可以想象一下监听器

}

} //inner class

Inner i = new Inner();
i.seeOuter();

} //dostuff

} //outer class
//执行结果:Outer x is Outer

方法本地内部类只能在定义该内部类的方法内实例化。换句话说,运行在任何其他方法内的其他任何代码都不能实例化方法本地内部类。

内部类的对象不能访问该内部类所在本地方法内的局部变量。为什么?因为方法中的局部变量是放在栈内的,只存活在方法中,当方法调用结束,变量也就被删除。
但是,即使方法调用结束,在其中创建的内部类对象仍然可能存活于堆上,因此不能保证它们的生命周期一样长,所以不能访问。除非将局部变量声明为final类型。

不能把方法本地内部类标识为public、private、protected、static、transient等。
唯一能应用于方法本地内部类的修饰符是abstract和final。而且永远它两不能同时使用。

匿名内部类:

被声明的内部类没有任何类名。不仅能在方法内,而且能够在方法的参数内定义这些类。
第一种形式的普通旧匿名内部类:
请看下面代码
class Popcorn{

public void pop(){
System.out.println("popcorn");
}
}
class Food{

Popcorn p = new Popcorn(){
public void pop(){
System.out.println("anonymous popcorn");
}
};

}

Food具有实例变量,声明为Popcorn类型。Food没有任何方法。要注意的关键一点:Popcorn引用变量不是引用Popcorn实例,而是Popcorn匿名(未命名)子类的实例。
匿名类代码:

2 Popcorn p = new Popcorn(){
3 public void pop(){
4 System.out.println("anonymous popcorn");
5 }
6 };

第二行,Popcorn类型的实例变量声明,不同于Popcorn p = new Popcorn();在第二行就结束,通常分号所在位置有一个大括号:
声明了Popcorn 的一个心累,它没有名字,但是是Popcorn 的子类,并重写了Popcorn 父类中的pop方法。

建立匿名内部类的关键点:重写父类的一个或多个方法!!


第二种形式的普通旧匿名内部类:

第一种与第二种的唯一区别是,第一种形式创建指定类 类型的匿名子类,而第二种形式则创建指定接口类型的实现类。
interface
Cookable{
	public void cook();
}
public class Food {
	Cookable c= new Cookable(){

		@Override
		public void cook() {
		}
		
	};
	
}

参数定义的匿名内部类:
interface Foo{
	public void foof();
}
class Bar{
	void doStuff(Foo f){
		f.foof();
	}
}
public class Food {
	void go(){
		Bar b = new Bar();
		b.doStuff(new Foo(){

			@Override
			public void foof() {
				System.out.println("hello");
			}
			
		});
	}
	
	public static void main(String[] args){
	                new Food().go();
	}
	
}
执行结果:hello

静态嵌套类(静态内部类):

按照内部类的标准定义,它们根本不是内部类。对于静态类,更重要的是名称空间解析,而不是两个类之间的隐含关系。
class BigOuter {

	static class Nested{  //static 修饰符只是说这个嵌套类是外部类的静态成员。这意味着没有

外部类实例,也能够访问。
		
	}
}

例子:
class BigOuter {

	static class Nested{  //static 修饰符只是说这个嵌套类是外部类的静态成员。这意味着没有

外部类实例,也能够访问。
		void go(){
			System.out.println("hi");
		}
	}
}
 
 public class Broom{
	 static class B2{
		 void goB2(){
			 System.out.println("hi 2");
		 }
	 }
	 
	 public static void main(String[] args){
		 BigOuter.Nested n = new BigOuter.Nested();  //两个类名
		 n.go();
		 
		 B2 b= new B2();
		 b.goB2();
		 
	 }
 }


练习题:
public class TestObj {

	public static void main(String[] args) {

		Object o = new Object(){
			public boolean equals(Object o){
				return true;
			}
		}
		
		System.out.println(o.equals("he"));
		
	}

}

这个程序会出现编译错误,一定要小心。注意少量个分号

public class TestObj {

	public static void main(String[] args) {
		
		class Horse{
			public String name;
			public Horse(String name){
				this.name = name;
			}
		}
		

		Object o = new Horse("zippo");
		Horse h = (Horse) o;
		
		System.out.println(h.name);
		
	}

}

执行结果:输出zippo。

public abstract class AbstractTest {
	
	public int getNum(){
		return 45;
	}
	
	public abstract class Bar{
		public int getNum(){
			return 38;
		}
	}

	public static void main(String[] args) {
		AbstractTest t = new AbstractTest(){
			public int getNum(){
				return 22;
			}
		};
		
		AbstractTest.Bar f = t.new Bar(){
			public int getNum(){
				return 57;
			}
		};
		
		
		System.out.println(f.getNum()+"  "+t.getNum());
	}

}

执行结果:57  22
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics