内部类
将一个类定义到另一个类的内部则该类称为内部类。在外部类的非静态方法之外的任何位建造某个内部类的对象必须通过 外部类名称.内部类名称 来指明该对象的类型。
链接到内部类
当生成一个内部类对象时,该对象与外部类对象有一种联系,因此内部类对象可以访问任何外部类的元素。
范例:
interface Selector {
public boolean end();
public Object current();
public void next();
}
public class Sequence {
private Object[] items;
private int next = 0;
public Sequence(int size) {// 构造方法
items = new Object[size];
}
public void add(Object x) {
if (next < items.length) {
items[next++] = x;
}
}
/**
* 私有内部类
* @author LJQ
*
*/
private class SequenceSelector implements Selector {
private int i = 0;
@Override
public boolean end() {
return i == items.length;//访问外部类的私有成员
}
@Override
public Object current() {
return items[i];
}
@Override
public void next() {
if (i < items.length)
i++;
}
}
public Selector selector(){
return new SequenceSelector();
}
public static void main(String[] args) {
Sequence sequence=new Sequence(10);
for(int i=0;i<10;i++)
sequence.add(Integer.toString(i));
Selector selector=sequence.selector();
while(!selector.end()){
System.out.print(selector.current()+" ");
selector.next();
}
}
}
使用.this与.new
有时需要生成对外部类对象的引用,可以使用.this
范例:
public class DotThis {
void f(){
System.out.println("DotThis.f()");
}
public class Inner{
public DotThis outer(){
return DotThis.this;//this内部类的当前对象 生成外部类的引用
}
}
public Inner inner(){
return new Inner();
}
public static void main(String[] args) {
DotThis dotThis=new DotThis();
DotThis.Inner dtiInner=dotThis.inner();
dtiInner.outer().f();
}
}
在外部类对象之前不能创建内部类对象,因为内部类对象与外部类对象有关联。
范例:
public class Parcel3 {
class Contents {
private int i = 11;
public int value() {
return i;
}
}
class Destination {
private String lable;
public Destination(String whereTo) {
lable = whereTo;
}
String readLable() {
return lable;
}
}
public static void main(String[] args) {
Parcel3 parcel3 = new Parcel3();// 外部类对象
Parcel3.Contents contents = parcel3.new Contents();// 生成内部类对象
Parcel3.Destination destination = parcel3.new Destination("beijing");
}
}
将内部类向上转型成基类或接口时可以隐藏内部类的实现细节。
范例:
interface Destination{
String readLable();
}
interface Contents{
int value();
}
public class Parcel4 {
private class PContents implements Contents{//私有内部类,仅外部类可见
int i=11;
@Override
public int value() {
return i;
}
}
protected class PDestination implements Destination{//protected修饰的内部类
private String Label;
public PDestination(String Lable) {
Label=this.Label;
}
@Override
public String readLable() {
return Label;
}
}
public Destination destination(String s){
return new PDestination(s);//将内部类向上转型为接口类型
}
public Contents contents(){
return new PContents();
}
}
public class TestParcel {
public static void main(String[] args) {
Parcel4 parcel4=new Parcel4();
Contents contents=parcel4.contents();//内部类PContents的被实现接口的引用
Destination destination=parcel4.destination("beijing");//被实现接口的引用
}
}
在方法和作用域内的内部类:可以在一个方法或者在任意的作用域内定义内部类。
范例:
interface Destination{
String readLabel();
}
interface Contents{
int value();
}
public class Parcel5 {
public Destination destination(String s){//在destination方法的外部不能访问PDestination
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 parcel5=new Parcel5();
Destination destination=parcel5.destination("beijing");
}
}
作用域内嵌套内部类(嵌套在作用域中的内部类在作用域之外不能使用)
范例:
public class Parcel6 {
private void internalTracking(boolean b){
if(b){//在该作用域之外不能访问TrackSlip
class TrackSlip{//作用域内嵌套内部类
private String id;
TrackSlip(String s) {
id=s;
}
String getSlip(){ return id;}
}
TrackSlip trackSlip=new TrackSlip("slip");
String s=trackSlip.getSlip();
System.out.println(s);
}
}
public void track(){ internalTracking(true);}
public static void main(String[] args) {
Parcel6 parcel6=new Parcel6();
parcel6.track();
}
}
匿名内部类
interface Contents{
int value();
}
public class Parcel7 {
public Contents contents(){
return new Contents(){//插入一个匿名类的定义 并且向上转型成Contents类型
private int i=11;
@Override
public int value() {
return i;
}
};
}
public static void main(String[] args) {
Parcel7 parcel7=new Parcel7();
Contents contents=parcel7.contents();
System.out.println(contents.value());
}
}
上述匿名类的简化形式:
public class Parcel7b {
class MyContents implements Contents {
private int i = 11;
@Override
public int value() {
return i;
}
}
public Contents contents() {
return new MyContents();
}
public static void main(String[] args) {
Parcel7b parcel7b = new Parcel7b();
Contents contents = parcel7b.contents();
System.out.println(contents.value());
}
}
带有参数的匿名内部类
class Wrapping{
private int i;
public Wrapping(int x){
i=x;
}
public int value(){
return i;
}
}
public class Parcel8 {
public Wrapping wrapping(int x){
return new Wrapping(x){
public int value(){
return super.value()*47;
}
};//分号必要
}
public static void main(String[] args) {
Parcel8 parcel8=new Parcel8();
Wrapping wrapping=parcel8.wrapping(10);
System.out.println(wrapping.value());
}
}
如果想做一些构造器行为,在匿名类中不可能有命名构造器(因为它根本没有名字),但通过实例初始化,就能够达到为匿名内部类创建一个构造器效果。
范例:
abstract class Base {
public Base(int i) {
System.out.println("Base Constructor,i=" + i);
}
public abstract void f();
}
public class AnonymousConstructor {
public static Base getBase(int i) {
return new Base(i) {//调用基类的带一个参数的构造方法。
{
System.out.println("Inside instance initializer");
}
@Override
public void f() {
System.out.print("In anonymous f()");
}
};
}
public static void main(String[] args) {
Base base = getBase(47);
base.f();
}
}
说明:在此例中,不要求变量i一定是final的,因为i被传递给匿名类的基类的构造器,它并不会在匿名类内部被直接使用。
范例:
interface Destination {
String readLable();
}
public class Parcel10 {
public Destination destination(final String dest, final float price) {//dest和price的必须是final的。
return new Destination() {
private int cost;
{
cost = Math.round(price);
if (cost > 100) {
System.out.println("Over budget");
}
}
private String lable = dest;
@Override
public String readLable() {
return lable;
}
};
}
public static void main(String[] args) {
Parcel10 parcel10 = new Parcel10();
parcel10.destination("beijing", 101.395F);
}
}
匿名内部类与正规的继承有些受限,因为匿名内部类既可以扩展类也可以实现接口但不能两者兼备,而且若果实现接口则只能实现一个接口。
通过匿名内部类实现工厂方法
范例:
interface Service{//服务接口
void method1();
void method2();
}
interface ServiceFactory{//生产服务的工厂方法
Service getService();
}
class Implementation1 implements Service{
public 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{
public Implementation2(){}
public static ServiceFactory factory=new ServiceFactory() {
public Service getService() {
return new Implementation2();
}
};//通过匿名内部类定义获取服务方法
public void method1() {
System.out.println("Implementation2 method1");
}
public void method2() {
System.out.println("Implementation2 method2");
}
}
public class Factories {
public static void serviceConsumer(ServiceFactory factory){//服务消费方法
Service service=factory.getService();
service.method1();
service.method2();
}
public static void main(String[] args) {
serviceConsumer(Implementation1.factory);
serviceConsumer(Implementation2.factory);
}
}
嵌套类
如果不需要内部类对象与其外围类对象之间有联系,那么可以将内部类声明为static。这常称为嵌套类。普通的内部类对象隐式地保存了一个引用,指向创建它的外围类对象。要创建嵌套类的对象,并不需要其外围类的对象;不能从嵌套类的对象中访问非静态的外围类对象。
注:普通内部类不能包含静态数据、静态字段并且不能包含嵌套类。在Java中static不能修饰顶级类,只有内部类可以用static修饰。
范例:
interface Contents {
public int value();
}
interface Destination {
public String readLabel();
}
public class Parcel11 {
class aa {
void f() {
System.out.println("aa");
}
}
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;
}
@Override
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 str) {
return new ParcelDestination(str);
}
public static Contents contents() {
return new ParcelContents();
}
public static void main(String[] args) {
Parcel11 parcel11 = new Parcel11();
Parcel11.aa a = parcel11.new aa();//非静态内部类的实例化与外部类对象实例化有关
a.f();
Parcel11.ParcelContents content = new Parcel11.ParcelContents();//静态内部类的实例化与外部类对象无关
Contents c = contents();
Destination d = destination("beijing");
}
}
接口内部的类
嵌套类可以放置在接口中,接口中的任何类都为public static修饰的。如果你想创建某些公共代码,使他们可以被该接口的所有不同的实现类所共用就可以使用该方法。
范例:
public interface ClassInInterface {
void howdy();
class Test implements ClassInInterface {
@Override
public void howdy() {
System.out.println("howdy");
}
public static void main(String[] args) {
new Test().howdy();
}
}
}
注:嵌套类不论嵌套多少层它都能透明的访问所有嵌套类的成员。
内部类的继承
内部类的构造器必须连接到指向其外围类对象的引用,所以在继承内部类的时候那个指向外围类的对象的引用必须进行初始化。而在在导出类中不再存在可连接的默认对象,必须显式指出他们之间的关联。
范例:
class WithInner {
class Inner {
}
}
public class InheritInner extends WithInner.Inner {
public InheritInner(WithInner wi) {
wi.super();// 指向外部类的引用
}
public static void main(String[] args) {
WithInner withInner = new WithInner();
InheritInner inheritInner = new InheritInner(withInner);// InheritInner不是内部类而是继承自内部类。
}
}
注意:当一个外部类继承一个类时并不能覆盖该类中的内部类。
范例:
package overrideInner;
class Egg {
private Yolk y;
protected class Yolk {
public Yolk() {
System.out.println("Egg.Yolk()");
}
}
public Egg() {
System.out.println("New Egg");
y = new Yolk();
}
}
public class BigEgg extends Egg {
public class Yolk {//该内部类与父类内部类完全独立实体各自在自己的命名空间中。
public Yolk() {
System.out.println("BigEgg.Yolk()");
}
}
public static void main(String[] args) {
new BigEgg();
}
}
执行结果:
New Egg
Egg.Yolk()
局部内部类
局部内部类不能有访问修饰符,因为他不是外部类的一部分,但是他可以访问当前代码块中的常量,以及外围类的所有成员。
内部类标识符:
每个类都会产生一个.class文件,其中包含了如何创建该类型的对象的全部信息。同样内部类也必须生成一个.class文件同时命名有严格的规则:外围类名$内部类名称 。如果是匿名内部类则编译器会简单产生一个数字作为标识符。