Java 中的内部类

Java 中的内部类

参考资料:

《Java SE 6.0 编程指南》 作者:吴亚峰 纪超    出版社:人民邮电出版社

《Thinking in Java Fourth Edition》 作者:Bruce Eckel

1、非静态内部类

1.1、语法规则

public class Outer {
    
    /**
     * 非静态内部类
     */
    class Inner {
        //内部类的成员
        int i = 1;
    }

    //外部类的普通成员
    int count = 2;

}

package innerclasses;

// Creating inner classes.

public class Parcel1 {
	
	class Contents {
	    private int i = 11;
	    public int value() { 
	    	return i; 
	    }
	}
	
	class Destination {
		private String label;
		Destination(String whereTo) {
			label = whereTo;
		}
		String readLabel() { 
			return label; 
		}
	}	
	
	// Using inner classes looks just like
	// using any other class, within Parcel1:
	public void ship(String dest) {
	    Contents c = new Contents();
	    Destination d = new Destination(dest);
	    System.out.println(d.readLabel());
	}
	
	public static void main(String[] args) {
		Parcel1 p = new Parcel1();
		p.ship("Tasmania");
	}
} /* Output:
Tasmania
*///:~

□ 内部类和外部类中的其他成员是一个级别的,其也是外部类的一个成员。

□ 在内部类也是一个单独的类,也有自己的成员变量和方法。
□ 内部类可以加上访问限制修饰符,包括 private、protected 和 public

1.2、外部类之内创建内部类对象

package com.aimartt.innerclass;

/**
 * 外部类
 */
class Outer {
	
	/**
	 * 内部类
	 */
	class Inner {
		
		/**
		 * 打印输出
		 */
		public void show() {
			System.out.println("调用内部类的show方法");
		}
		
	}
	
	/**
	 * 外部类的方法,创建内部类对象
	 */
	public void createInner() {
		//外部类中创建内部类对象
		Inner inner = new Inner();
		//调用内部类的方法
		inner.show();
	}
	
}

/**
 * 主类
 */
public class Demo {

	/**
	 * 主方法
	 * @param args
	 */
	public static void main(String[] args) {
		//创建外部类对象
		Outer outer = new Outer();
		//调用创建内部类对象的方法
		outer.createInner();
	}

}

□ 外部类中创建内部类对象的语法与普通创建对象的方法相同,使用 new 操作符调用构造器。

□ 对内部类而言,在其类体中也可以拥有类所能拥有的一切成员。

1.3、外部类之外创建内部类对象

package com.aimartt.innerclass;

/**
 * 外部类
 */
class Outer {
	
	/**
	 * 内部类
	 */
	class Inner {
		/**
		 * 打印输出
		 */
		public void show() {
			System.out.println("调用内部类的show方法");
		}
	}
	
}

/**
 * 主类
 */
public class Demo {

	/**
	 * 主方法
	 * @param args
	 */
	public static void main(String[] args) {
		//创建外部类对象
		Outer outer = new Outer();
		//创建内部类对象
		Outer.Inner inner = outer.new Inner();
		Outer.Inner inner2 = new Outer().new Inner();
		//调用内部类中的方法
		inner.show();
		inner2.show();
	}

}

□ 在外部类之外声明内部类引用时,需用外部类名加以标识,不能直接使用内部类类名,而创建内部类对象时,需先创建外部类对象,再创建内部类对象。

1.4、内部类与外部类之间的成员互访

1.4.1、内部类中访问外部类成员

package com.aimartt.innerclass;

/**
 * 外部类
 */
class Outer {
	
	/** 外部类的私有成员变量 */
	private int o = 1;
	
	/**
	 * 内部类
	 */
	class Inner {
		/**
		 * 打印输出外部类的私有成员
		 */
		public void show() {
			System.out.println("外部类的私有成员变量o = " + o);
		}
	}

	public int getO() {
		return o;
	}

	public void setO(int o) {
		this.o = o;
	}
	
}

/**
 * 主类
 */
public class Demo {

	/**
	 * 主方法
	 * @param args
	 */
	public static void main(String[] args) {
		//创建内部类对象
		Outer.Inner inner = new Outer().new Inner();
		//调用内部类中的方法
		inner.show();
	}

}

1.4.2、外部类中访问内部类成员

package com.aimartt.innerclass;

/**
 * 外部类
 */
class Outer {
	
	/**
	 * 内部类
	 */
	class Inner {
		/**
		 * 打印输出
		 */
		private void show() {
			System.out.println("成功访问内部类的私有方法");
		}
	}
	
	/**
	 * 创建内部类对象并调用其方法
	 */
	public void getInner() {
		//创建内部类对象
		Inner inner = new Inner();
		//访问内部类私有方法
		inner.show();
	}

}

/**
 * 主类
 */
public class Demo {

	/**
	 * 主方法
	 * @param args
	 */
	public static void main(String[] args) {
		//创建外部类对象,并调用创建内部类方法
		Outer outer = new Outer();
		outer.getInner();
	}

}

1.5、内部类与外部类的预定义对象引用 this

□ 内部类中需要使用外部类对象的 this,语法如下:<外部类名>.this.<外部类中需要被访问的成员名>。

package com.aimartt.innerclass;

/**
 * 外部类
 */
class Outer {
	
	/** 外部类成员变量 */
	int i = 1;
	
	/**
	 * 内部类
	 */
	class Inner {
		
		/** 内部类与外部类同名成员变量 */
		int i = 10;
		
		/**
		 * 输出外部类和内部类的成员变量
		 */
		public void show() {
			//访问外部类的成员变量
			System.out.println("外部类的成员变量 i = " + Outer.this.i);
			//访问内部类的成员变量
			System.out.println("内部类的成员变量 i = " + this.i);
		}
		
	}
	
}

/**
 * 主类
 */
public class Demo {

	/**
	 * 主方法
	 * @param args
	 */
	public static void main(String[] args) {
		//创建内部类对象
		Outer.Inner innerr = new Outer().new Inner();
		//调用内部类方法
		innerr.show();
	}

}

package innerclasses;

// Qualifying access to the outer-class object.

public class DotThis {
	void f() { 
		System.out.println("DotThis.f()"); 
	}
	
	public class Inner {
		public DotThis outer() {
			return DotThis.this;	// A plain "this" would be Inner's "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();
	}
} /* Output:
DotThis.f()
*///:~

1.6、内部类的继承

package innerclasses;

// Inheriting an inner class.

class WithInner {
	class Inner {}
}

public class InheritInner extends WithInner.Inner {
	public InheritInner(WithInner inner) {
		inner.super();	//若跳过外部类直接继承内部类,必须使用此语法才能编译通过
	}
	
	public static void main(String[] args) {
		WithInner wi = new WithInner();
		InheritInner ii = new InheritInner(wi);
	}
}

2、局部内部类

2.1、局部内部类的定义及创建

package com.aimartt.innerclass;

/**
 * 外部类
 */
class Outer {
	
	/**
	 * 声明并创建内部类对象
	 */
	public void getInner() {
		
		/**
		 * 内部类
		 */
		class Inner {
			/**
			 * 输出
			 */
			public void show() {
				System.out.println("内部类的show()方法");
			}
		}
		
		//创建内部类对象并调用其方法
		Inner inner = new Inner();
		inner.show();
		
	}
	
}

/**
 * 主类
 */
public class Demo {

	/**
	 * 主方法
	 * @param args
	 */
	public static void main(String[] args) {
		//创建外部类对象
		Outer outer = new Outer();
		//调用外部类方法
		outer.getInner();
	}

}

2.2、局部变量与局部内部类

package com.aimartt.innerclass;

/**
 * 外部类
 */
class Outer {
	
	/**
	 * 声明并创建内部类对象
	 */
	public void getInner() {
		
		/** 定义局部变量 */
		final int i = 2;
		
		/**
		 * 内部类
		 */
		class Inner {
			/**
			 * 输出
			 */
			public void show() {
				System.out.println("方法中的局部变量 i = " + i);
			}
		}
		
		//创建内部类对象并调用其方法
		Inner inner = new Inner();
		inner.show();
		
	}
	
}

/**
 * 主类
 */
public class Demo {

	/**
	 * 主方法
	 * @param args
	 */
	public static void main(String[] args) {
		//创建外部类对象
		Outer outer = new Outer();
		//调用外部类方法
		outer.getInner();
	}

}

□ 局部变量与局部内部类。普通局部变量随着语句块的结束而消亡,而创建的局部类对象则不会。如果在语句块结束后,调用了局部内部类对象中访问普通局部变量的方法,就会出现问题,因为要访问的局部变量已经不存在了。
□ final 的局部变量不会因为语句块的结束而消失,因此可以被局部内部类访问。

2.3、静态方法中的局部内部类

/**
 * 
 */
package com.aimartt.innerclass;

/**
 * 外部类
 */
class Outer {
	
	/** 外部类的静态成员变量 */
	static int i = 7;
	
	/**
	 * 声明并创建内部类对象
	 */
	public static void getInner() {
		/**
		 * 内部类
		 */
		class Inner {
			/**
			 * 输出
			 */
			public void show() {
				System.out.println("方法中的局部变量 i = " + i);
			}
		}
		//创建内部类对象并调用其方法
		Inner inner = new Inner();
		inner.show();
	}
	
}

/**
 * 主类
 */
public class Demo {

	/**
	 * 主方法
	 * @param args
	 */
	public static void main(String[] args) {
		//调用外部类静态方法
		Outer.getInner();
	}

}

□ 若局部类位于静态方法中,则只能访问外部类的静态成员,这与静态方法访问成员的规则是一致的。

3、静态内部类

3.1、创建静态内部类的对象

/**
 * 
 */
package com.aimartt.innerclass;

/**
 * 外部类
 */
class Outer {
	
	/**
	 * 静态内部类
	 */
	static class Inner {
		/**
		 * 输出
		 */
		public void show() {
			System.out.println("静态内部类的show()方法");
		}
	}
	
	/**
	 * 声明并创建内部类对象
	 */
	public void getInner() {
		//创建内部类对象并调用其方法
		Inner inner = new Inner();
		inner.show();
	}
	
}

/**
 * 主类
 */
public class Demo {

	/**
	 * 主方法
	 * @param args
	 */
	public static void main(String[] args) {
		//外部类之外创建静态内部类对象
		Outer.Inner inner = new Outer.Inner();
		inner.show();
		//外部类中使用静态内部类对象
		new Outer().getInner();
	}

}

□ 外部类之外创建静态内部类对象的语法如下:<外部类类名>.<内部类类名> 引用变量 = new <外部类类名>.<内部类构造器>;
□ 静态内部类也可以称为静态嵌套类,或顶级嵌套类。由于创建静态内部类的对象已不需要外部类对象的存在,静态内部类其实只是一个在别的类中的一个普通类而已。static 关键字只是说明其创建对象时不依赖于外部类对象,并不表示这个类是静态的。

4、匿名内部类

□ 匿名内部类没有类名,因此匿名内部类在声明的同时也创建了对象。
□ 匿名内部类的声明要么是基于继承的,要么是基于接口实现的。

4.1、基于继承的匿名内部类

/**
 * 
 */
package com.aimartt.innerclass;

/**
 * 父类
 */
class Father {
	public void show() {
		System.out.println("父类中的show()方法");
	}
}

/**
 * 主类
 */
public class Demo {

	/**
	 * 主方法
	 * @param args
	 */
	public static void main(String[] args) {
		//定义匿名内部类并创建其对象,并重写父类中的方法
		Father father = new Father() {
			public void show() {
				System.out.println("重写父类的show()方法");
			}
		};
		//访问匿名内部类中重写的方法
		father.show();
	}

}

□ 访问匿名内部类成员均是通过多态完成的,因为匿名内部类无法创建自身类型的引用。

4.2、基于接口实现的匿名内部类

/**
 * 
 */
package com.aimartt.innerclass;

/**
 * 定义接口
 */
interface MyInterface {
	void show();
}

/**
 * 主类
 */
public class Demo {

	/**
	 * 主方法
	 * @param args
	 */
	public static void main(String[] args) {
		//定义匿名内部类并创建其对象,并实现接口中的方法
		MyInterface mi = new MyInterface() {
			@Override
			public void show() {
				System.out.println("实现接口的show()方法");
			}
		};
		//访问匿名内部类中实现的方法
		mi.show();
	}

}

□ 匿名内部类要么实现一个接口,要么继承一个类,不能同时既实现接口又进行继承。

4.3、匿名内部类的初始化

/**
 * 
 */
package com.aimartt.innerclass;

/**
 * 定义抽象类
 */
abstract class Father {
	int i;
	abstract void show();
}

/**
 * 主类
 */
public class Demo {

	/**
	 * 主方法
	 * @param args
	 */
	public static void main(String[] args) {
		//定义匿名内部类并创建其对象
		Father mi = new Father() {
			
			//使用非静态块初始化成员
			{
				i = (int) (Math.random() * 100);
			}
			
			//重写抽象类中的方法
			@Override
			public void show() {
				System.out.println("初始化的成员i = " + i);
			}
		};
		
		//访问匿名内部类中实现的方法
		mi.show();
	}

}

□ 匿名内部类对象的初始化代码写在非静态语句块中。

package innerclasses;

// An anonymous inner class that performs initialization. 

interface Destination {
	String readLabel();
} 

public class Parcel9 {
 	// Argument must be final to use inside anonymous inner class:
	public Destination destination(final String dest) {
		return new Destination() {
			private String label = dest;
			
			@Override
			public String readLabel() { 
				return label; 
			}
		};
	}
	
	public static void main(String[] args) {
		Parcel9 p = new Parcel9();
		Destination d = p.destination("Tasmania");
	}
} 
□ 从外部传递给匿名内部类的参数,必须是 final 的。

5、内部接口

5.1、定义在类中的内部接口

/**
 * 
 */
package com.aimartt.innerclass;

/**
 * 外部类
 */
class Outer {
	
	/**
	 * 非静态内部接口
	 */
	public interface InnerInterface {
		void show();
	}
	
	/**
	 * 实现内部接口的内部类
	 */
	public class Inner implements InnerInterface {
		@Override
		public void show() {
			System.out.println("内部类实现内部接口的show()方法");
		}
	}
	
	/**
	 * 获取内部类对象的方法
	 * @return
	 */
	public InnerInterface getInner() {
		return new Inner();
	}
	
}

/**
 * 实现内部接口的普通类
 */
class Normal implements Outer.InnerInterface {
	@Override
	public void show() {
		System.out.println("普通类实现了内部接口的show()方法");
	}
}

/**
 * 主类
 */
public class Demo {

	/**
	 * 主方法
	 * @param args
	 */
	public static void main(String[] args) {
		Outer outer = new Outer();	//创建外部类对象
		Outer.InnerInterface oic = outer.getInner();	//获取内部类对象
		oic.show();	//访问内部类的show()方法
		oic = new Normal();		//获取普通类的对象
		oic.show();	//访问普通类的show()方法
	}

}

□ 内部接口无论是否使用 static 修饰,扮演的都是静态成员。

5.2、定义在接口中的内部接口

/**
 * 
 */
package com.aimartt.innerclass;

/**
 * 外部接口
 */
interface OuterInterface {
	
	/**
	 * 内部接口
	 */
	public interface InnerInterface {
		void inShow();
	}
	
	/**
	 * 外部接口的方法
	 */
	void outShow();
	
}

/**
 * 实现外部接口的类
 */
class OuterInterfaceImpl implements OuterInterface {
	@Override
	public void outShow() {
		System.out.println("实现外部接口的outShow()方法");
	}
}

/**
 * 实现内部接口的类
 */
class InnerInterfaceImpl implements OuterInterface.InnerInterface {
	@Override
	public void inShow() {
		System.out.println("实现内部接口的inShow()方法");
	}
}

/**
 * 主类
 */
public class Demo {

	/**
	 * 主方法
	 * @param args
	 */
	public static void main(String[] args) {
		//创建实现内部接口和外部接口的类的对象
		OuterInterface.InnerInterface inner = new InnerInterfaceImpl();
		OuterInterface outer = new OuterInterfaceImpl();
		//调用两个对象的方法
		inner.inShow();
		outer.outShow();
	}

}

□ 内部接口只是把普通接口放到了一个接口内部,在使用上没有很大的不一样,实现内部接口与普通接口的具体方法完全一样。


你可能感兴趣的:(java,编程,String,Class)