论坛首页 Java企业应用论坛

java内部类

浏览 14591 次
锁定老帖子 主题:java内部类
精华帖 (0) :: 良好帖 (3) :: 新手帖 (18) :: 隐藏帖 (1)
作者 正文
   发表时间:2009-10-21   最后修改:2009-10-21
外创建内部类就是把类定义至于外围类的里面
public class Parcel1 {
	class Destination {
		private String label;

		Destination(String whereTo) {
			label = whereTo;
		}

		String readLabel() {
			return label;
		}
	}

	//在类的的函数中使用内部类,与使用普通类没多大区别
	public void ship(String dest) {
		Destination d = new Destination(dest);
		System.out.println(d.readLabel());
	}

	public static void main(String[] args) {
		Parcel1 p = new Parcel1();
		p.ship("Tasmania");
	}
}

如果想从外部类的非静态方法之外的任意位置创建某个内部类的对象,必须具体地知名这个对象饿类型(OuterClassName.InnerClassName),比如
public class Parcel2 {
	class Contents {
		private int i = 11;

		public int value() {
			return i;
		}
	}

	public Contents contents() {
		return new Contents();
	}

	public void ship(String dest) {
		Contents c = contents();
		Destination d = to(dest);
		System.out.println(d.readLabel());
	}

	public static void main(String[] args) {
		Parcel2 p = new Parcel2();
		p.ship("Tasmania");
		Parcel2 q = new Parcel2();
		// Defining references to inner classes:
		Parcel2.Contents c = q.contents();
	}
}

外部类拥有其外围类的所有元素的访问权
如果你需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟圆点和this,如下:
public class DotThis {
	void f() {
		System.out.println("DotThis.f()");
	}

	public class Inner {
		public DotThis outer() {
			//通过外部类名字后面紧跟远点和this获取外部类对象			//的引用
			return DotThis.this;
		}
	}

	public Inner inner() {
		return new Inner();
	}

	public static void main(String[] args) {
		DotThis dt = new DotThis();
		DotThis.Inner dti = dt.inner();
		//通过获取到的外部类调用外部类中的方法
		dti.outer().f();
	}
}

如果你要在main函数中创建一个内部类对象,你必须在new表达式中提供对其他外部类对象的引用,这是需要使用.new语法,比如上例代码在main中修改创建内部类Inner对象的方法改为DotThis.Inner dti = dt.new Inner()后效果一样
在拥有外部类对象之前是不可能创建内部类对象,因为内部类对象会暗暗地连接到创建它的外部类对象上,但是如果你创建的是嵌套类(静态内部类),就不需要对外部类对象的引用

在方法的作用域内(而不是在其他类的作用域内)创建一个完整的类.这被称作局部内部类:
public interface Destination {
  String readLabel();
}

public class Parcel5 {
	public Destination destination(String s) {
		class PDestination implements Destination {
			private String label;

			private PDestination(String whereTo) {
				label = whereTo;
			}

			public String readLabel() {
				return label;
			}
		}
		return new PDestination(s);
	}

	public static void main(String[] args) {
		Parcel5 p = new Parcel5();
		Destination d = p.destination("Tasmania");
	}
}

PDestination类是destination()方法的一部分,所以在destination()之外不能访问,在return语句中的向上转型,返回的是Destination的引用,是一个基类
你也可以再同一个子目录下的任意类中对某个内部类使用类标示符PDestination,因为定义在方法内部,所以不会出现命名冲突.

在任意的作用域内嵌入一个内部类,比如在if语句的作用域内:
public class Parcel6 {
	private void internalTracking(boolean b) {
		if (b) {
			class TrackingSlip {
				private String id;
				TrackingSlip(String s) {
					id = s;
				}
				String getSlip() {
					return id;
				}
			}
			TrackingSlip ts = new TrackingSlip("slip");
			String s = ts.getSlip();
		}
	}
	public void track() {
		internalTracking(true);
	}
	public static void main(String[] args) {
		Parcel6 p = new Parcel6();
		p.track();
	}
}

这并不是说该类的创建时有条件的,它其实与别的类一起编译过了,然而,在定义TrackingSlip的作用域之外,它是不可用的,除此之外,与普通的类一样

匿名内部类,一直看起来有点奇怪
public interface Contents {
  int value();
}
public class Parcel7 {
	public Contents contents() {
		return new Contents() {
			private int i = 11;
			public int value() {
				return i;
			}
		}; 	
	}
	public static void main(String[] args) {
		Parcel7 p = new Parcel7();
		Contents c = p.contents();
		System.out.println(c.value());
	}
}

将返回值的生成与表示这个返回值的类的定义结合在一起,另外这个类是匿名的, 它没有名字.其实匿名类是非匿名类,然后去实现一个接口的简化形式

如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数引用时final的
public interface Destination {
  String readLabel();
}

public class Parcel9 {
	//参数dest必须定义成final的,才能在匿名内部类中使用
	public Destination destination(final String dest) {
		return new Destination() {
			private String label = dest;
			public String readLabel() {
				return label;
			}
		};
	}
	public static void main(String[] args) {
		Parcel9 p = new Parcel9();
		Destination d = p.destination("Tasmania");
		System.out.println(d.readLabel());
	}
}


匿名内部类不可能有命名构造器(因为它根本没名字),但通过实例初始化,能够达到为匿名内部类创建一个构造器的效果
abstract class Base {
	public Base(int i) {
		System.out.print("Base constructor, i = " + i);
	}
	public abstract void f();
}
public class AnonymousConstructor {
	//这里i不用声明为final,因为不会再匿名内部类被直接使用
	public static Base getBase(int i) {
		return new Base(i) {
			{
				System.out.print("Inside instance initializer");
			}
			public void f() {
				System.out.print("In anonymous f()");
			}
		};
	}
	public static void main(String[] args) {
		Base base = getBase(47);
		base.f();
	}
}


下面来看一段代码
public class Parcel10 {
	public Destination destination(final String dest, final float price) {
		return new Destination() {
			private int cost;
			// 这里的if语句不能作为字段初始化的一部分来执行
			{
				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) {
		Parcel10 p = new Parcel10();
		Destination d = p.destination("Tasmania", 101.395F);
	}
}

对于匿名类而言,实例初始化的实际效果就是构造器,当然它受到了限制-----不能重载实例化方法,所以你仅有一个这样的构造器
匿名内部类与正规的继承相比有些受限,因为匿名内部类既可以扩展类,也可以实现接口,但是不能两者兼备.而且如果是实现接口,也只能实现一个接口

利用匿名内部类,定义工厂方法
interface Service {
	void method1();

	void method2();
}

interface ServiceFactory {
	Service getService();
}

class Implementation1 implements Service {
	private Implementation1() {
	}

	public void method1() {
		System.out.println("Implementation1 method1");
	}

	public void method2() {
		System.out.println("Implementation1 method2");
	}

	public static ServiceFactory factory = new ServiceFactory() {
		public Service getService() {
			return new Implementation1();
		}
	};
}

class Implementation2 implements Service {
	private Implementation2() {
	}

	public void method1() {
		System.out.println("Implementation2 method1");
	}

	public void method2() {
		System.out.println("Implementation2 method2");
	}
	//利用匿名内部类的方式实现一个接口,实现工厂的方式得到当前类
	public static ServiceFactory factory = new ServiceFactory() {
		public Service getService() {
			return new Implementation2();
		}
	};
}

public class Factories {
	public static void serviceConsumer(ServiceFactory fact) {
		Service s = fact.getService();
		s.method1();
		s.method2();
	}

	public static void main(String[] args) {
		serviceConsumer(Implementation1.factory);
		serviceConsumer(Implementation2.factory);
	}
}


建议:优先实用类而不是接口,如果你的设计中需要某个接口,你必须了解它,否则.不到迫不得已,不要将其放到你的设计中

如果不需要内部类对象与其外围类对象之间有联系,那么可以讲内部类声明为static.通常称为嵌套类,当内部类是static时,意味着:

    [1]要创建嵌套类的对象,并不需要其外围类的对象
    [2]不能从嵌套类的对象中访问非静态的外围类对象

嵌套类与普通的内部类还有一个区别:普通内部类的字段的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段,也不能包含嵌套类.但是在嵌套类里可以包含所有这些东西
public class Parcel11 {
	private static class ParcelContents implements Contents {
		private int i = 11;
		public int value() {
			return i;
		}
	}
	protected static class ParcelDestination implements Destination {
		private String label;
		private ParcelDestination(String whereTo) {
			label = whereTo;
		}
		public String readLabel() {
			return label;
		}
		// 嵌套类可以包括其他静态元素
		public static void f() {
		}
		static int x = 10;
		static class AnotherLevel {
			public static void f() {
			}
			static int x = 10;
		}
	}
	public static Destination destination(String s) {
		return new ParcelDestination(s);
	}
	public static Contents contents() {
		return new ParcelContents();
	}
	public static void main(String[] args) {
		Contents c = contents();
		Destination d = destination("Tasmania");
	}
}


正常情况下,不能在接口内部放置任何代码,但嵌套类可以作为接口的一部分,你放到接口中的任何类都自动的是public和static.因为类是static,只是将嵌套类至于接口的命名空间内.你甚至可以再内部类中实现其外围接口
public interface ClassInInterface {
	void howdy();

	class Test implements ClassInInterface {
		public void howdy() {
			System.out.println("Howdy!");
		}

		public static void main(String[] args) {
			new Test().howdy();
		}
	}
}


以前一直不知道,嵌套类竟然可以这样用
public class TestBed {
  public void f() { System.out.println("f()"); }
  public static class Tester {
    public static void main(String[] args) {
      TestBed t = new TestBed();
      t.f();
    }
  }
}

就是可以把main方法放在嵌套类中

一个内部类被嵌套多少层不重要,它能透明地访问所有它所嵌入的外围类的所有成员,如下
class MNA {
	private void f() {
	}
	class A {
		private void g() {
		}
		public class B {
			void h() {
				//访问A对象的g方法
				g();
				//访问MNA对象的f方法
				f();
			}
		}
	}
}

public class MultiNestingAccess {
	public static void main(String[] args) {
		MNA mna = new MNA();
		MNA.A mnaa = mna.new A();
		MNA.A.B mnaab = mnaa.new B();
		mnaab.h();
	}
}
   发表时间:2009-10-23  
内部类是个好东西,关键是如何运用它!!!
0 请登录后投票
   发表时间:2009-10-23  
看到最后,有些失望,内隐类的很大的用处是使java从功能上实现多重继承。没看到这个说明...
lz的例子《thinking in Java》中都讲过的....
0 请登录后投票
   发表时间:2009-10-23  
内部类使用起来还是比较难以驾驭!
0 请登录后投票
   发表时间:2009-10-23  
对内部类说的很详细...不过内部类从维护的层面上来说,个人建议能少用就少用...
0 请登录后投票
   发表时间:2009-10-23  
写得很好,平时我不怎么用到类部类 同意husai对于内部类的看法
学习了
0 请登录后投票
   发表时间:2009-10-23  
基本上没怎么用到内部类
0 请登录后投票
   发表时间:2009-10-23  
内部类不好重用  使用本身还这么复杂   唯一用过的是在测试类中做一些mock类
0 请登录后投票
   发表时间:2009-10-23  
这个think in Java 里面写的很详细,这本书很强大
0 请登录后投票
   发表时间:2009-10-23  
静态内部类和匿名内部类用的稍多。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics