• 推荐!搬瓦工官方代理,自动更换被封IPJust My Socks

ad

第10章 内部类

可以将一个类的定义放在另一个类的定义内部,这就是内部类。它了解外围类,并能与之通信。

  • 10.1 创建内部类
    1. 如果想从外部类的非静态方法之外的任意位置创建某个内部类的对象(如静态方法中),必须具体致命这个对象的类型:OuterClassName.InnerClassName。如Outter.Inner inner = outter.getInner();
  • 10.2 链接到外部类
    1. 当生成一个内部类的对象时,此对象与制造它的外围对象(enclosing object)之间就有了一种联系(一个指向那个外围类对象的引用),所有它能访问其外围对象的所有成员(包括private),而不需要任何特殊条件。
    2. “迭代器”设计模式。(代码)
    3. 内部类的对象只能在与其外围类的对象相关联的情况下才能被创建(非static类),构建内部类对象时,需要一个指向其外围类对象的引用。
interface Selector{
    boolean end();
    Object current();
    void next();
}

public class Swquence{
    private Object[] items;
    pirvate int next = 0;
    public Sequence(int size){
        items = new Object[size];
    }
    public void add(Object x){
        if(next < items.length){
            items[next++] = x;
        }
    }
    
    private class SequenceSelector implements Selector{
        private int i = 0;
        public boolean end(){
            return i== items.length;
        }
        public Object current(){
            return items[i];
        }
        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();
        whilt(!selector.end){
            System.out.print(selector.current());
            selector.next();
        }
    }
}
  • 10.3 使用.this与.new
  1. 内部类调用Outter.this获得其持有的外部类的对象。
  2. 创建的内部类的对象中必须持有其外部类对象的引用,所以要用到.new语法:外部类实例.new InnerClass();。(非嵌套类(静态内部类))
public class DotThis{
    void f(){
        //...
    }
    public class Inner{
        public DotThis outer(){
            return DotThis.this;
        }
    }
}

/*-------------------------------------------------*/

public class DotNew{
    public class Inner {}
    public static void  main(String[] args){
        DotNew dn = new DotNew();
        DotNew.Inner inner = dn.new Inner();
    }
}
  • 10.6 匿名内部类
  1. 如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,必须要将其参数引用设置成final的。(这个经测试不正确,不用final编译器并没有报错
  2. 匿名类没有命名构造器,只能通过实例初始化(在内存中开辟一个类的对象 new Class())达到一样的效果。
  3. 匿名内部类与正规的继承相比:前者不能同时extends类和implements接口,也不能implements两个接口。
interface Contents{
    int value();
}
class Parcel{
    public Contents contents(){
        return new Contents(){
            private int i = 11;
            public int value(){
                return i;
            }
        };
    }
}

//应用了匿名内部类,效果相当于:

interface Contents{
    int value();
}
class Parcel{
    class MyContents implements Contents{
        private int i = 11;
        public int value(){
            return i;
        }
    }
    public Contents contents(){
        return new MyContents();
    }
}
```

```
interface Destination{
	String readLabel();
}
public class test{
// 不用匿名类的方法
//	    class MyDestination implements Destination{
//		private String mString;
//		public MyDestination(String i) {
//			// TODO Auto-generated constructor stub
//			mString = i;
//		}
//		@Override
//		public String readLabel() {
//			// TODO Auto-generated method stub
//			return mString;
//		}
//		
//	}
	public Destination destination(String dest){//TIJ书中说这里必须用final String dest
//		return new MyDestination(dest);
		return new Destination() {
			private String label = dest;
			@Override
			public String readLabel() {
				// TODO Auto-generated method stub
				return label;
			}
		};
	}
	
	public static void main(String args[]){
		test test = new test();
		Destination destination = test.destination("ss");
		System.out.println(destination.readLabel());
	}
}

//再看工厂模式
interface Service{
    void method1();
    void method2();
}
interface ServiceFactory{
    Service getService();
}
class Implementation1 implements Service{

    @Override
    public void method1() {

    }

    @Override
    public void method2() {

    }
    public static ServiceFactory factory =
            new ServiceFactory() {
                @Override
                public Service getService() {
                    return new Implementation1();
                }
            };
}
class Implementation2 implements Service{

    @Override
    public void method1() {

    }

    @Override
    public void method2() {

    }
    public static ServiceFactory factory =
            new ServiceFactory() {
                @Override
                public Service getService() {
                    return new Implementation2();
                }
            };
}

public class Facotories{
    public static void serviceConsumer(ServiceFactory factory){
        Service s = factory.getService();
        s.method1();
        s.method2();
    }
    public static void main(String[] args){
        serviceConsumer(Implementation1.factory);
        serviceConsumer(Implementation2.factory);
    }
}
  • 10.7 嵌套类
    1. 如果不需要内部类对象与其外围类对象之间有联系,那么可以将内部类声明为static。通常被称为嵌套类。
    2. 创建嵌套类的对象,不需要外围类的对象。
    3. 不能从嵌套类的对象中访问非静态的外围对象。
    4. 普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类中不能有static数据和static字段,也不能有嵌套类。(static变量声明要求静态环境或者顶层环境。而final static变量可以试因为Java在编译时把这个常量放在常量池中。
    5. 一个内部类被嵌套多少层并不重要,它能透明的访问所有它所嵌入的外围类的所有成员。
  • 10.8 为什么需要内部类
    1. 每个内部类都能独立的继承自一个接口的实现,因此内部类使得多重继承的解决方案变得完整。
    2. 内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外围类对象的信息相互独立。
    3. 可以让多个内部类以不同的方式实现同一个接口或者继承同一个类。(GreenhouseControls)
    4. 应用程序框架:被设计用以解决某类特定问题的一个类或者一组类。
  • 10.9 内部类的继承
    1. 内部类的构造器必须连接到指向其外围类对象的引用,所以要传递一个指向外围类对象的引用,并调用enclosingClassReference.super()。
//内部类继承
class Outter{
	public Outter(){
		System.out.println("Outter constructor");
	}
	class Inner{
		public Inner(){
			System.out.println("Inner constructor");
		}
	}
}

public class test extends Outter.Inner{
	test(Outter outter){
		outter.super();//调用父类的构造函数
		System.out.println("test constructor");
	}
	
	public static void main(String args[]){
		Outter outter = new Outter();
		test test = new test(outter);
	}
}

output:

Outter constructor
Inner constructor
test constructor
  • 10.10 内部类可以被覆盖吗
  1. 直接定义个基类中的内部类是不会覆盖的(互不影响),必须要指明。
class Egg{
	protected class Yolk{
		public Yolk(){
			System.out.println("Egg.Yolk()");
		}
		public void f(){
			System.out.println("Egg.Yolk.f()");
		}
	}
	public static void get(){
		Yolk toYolk = new Egg().new Yolk();
	}
	private Yolk yolk = new Yolk();
	public Egg(){
		System.out.println("new Egg()");
	}
	public void insertYolk(Yolk y){
		yolk = y;
	}
	public IBigEgg testIn(String s){
		return new IBigEgg(){
			private String string = s;

			@Override
			public void getEgg() {
				// TODO Auto-generated method stub
				System.out.println(string);
			}
			
		};
	}
	public void g(){
		yolk.f();
	}
}

public class test extends Egg{
	public class Yolk extends Egg.Yolk{
		public Yolk(){
			System.out.println("test.Yolk()");
		}
		public void f(){
			System.out.println("test.Yolk.f()");
		}
	}
	public test(){
		insertYolk(new Yolk());
	}
	
	public static void main(String args[]){
		Egg egg = new test();
		egg.g();
	}
}

output:

Egg.Yolk()
new Egg()
Egg.Yolk()
test.Yolk()
test.Yolk.f()
  • 10.12 内部类标识符
  1. 外围类的名字,加上“$”,再加上内部类的名字。如果是匿名内部类,编译器会简单的产生一个数字作为其标识符。
test$Yolk.class
test$1.class
点赞