笔记_from_Java编程思想(第九章 接口&&第十章 内部类)

第九章

可以选择在接口中显示地将方法声明为public,但即使不这样做它们也是public
放入接口域(成员)为static和final,在定义时必须初始化(编译器不会给默认值)也可以非常量表达式初始化,这些域不是接口的一部分,它们的值被存储在该接口的静态存储区域内。
**

组合接口时的名字冲突

**

interface CanFight{void fight();}
interface CanSwim{void swim();}
interface CanFly{void fly();}
class ActionCharacter
{
    public void fight(){}
}
class Hero extends ActionCharacter implements CanFight,CanSwim,CanFly
{
    public void swim(){}
    public void fly(){}
}

CanFight和ActionCharacter都有一个相同的void fight()方法,这并不会引起错误,即使Hero没有显式地提供fight()的定义,其定义也因ActionCharacter而随之而来,这样使得创建Hero对象成为可能。当然返回类型不同时,也自然报错。
如果参数列表不同,显然也是不被允许的,因为覆盖、实现和重载交织在一起,重载方法又不能通过返回类型区分。实践时,请尽量避免这种情况。

嵌套接口

class A
{
    interface B{ void f();}
    public class BImp implements B{ public void f(){}}
    private class BImp2 implements B{ public void f(){}}

    public interface C{ public void f();}
    class CImp implements C{ public void f(){}}
    private class CImp2 implements C{ public void f(){}}

    private interface D{ public void f();}
    private  class DImp implements D{ public void f(){}}
    public class DImp2 implements D{ public void f(){}}
    public D getD(){ return new DImp2();}
    private D dRef;
    public void receiveD(D d){ dRef=d; dRef.f();}
}
interface E
{
    interface G{ void f();}
    public interface H{ void f();}      //Redundant"public" 可省略”public“
    void g();
    //"The interface member type I can only be public", 接口内的接口只能为”public“
    //private interface I{}
}
public class test
{
    public class BImp implements A.B{ public void f(){}}
    class CImp implements A.C{ public void f(){}}
    //Cannot implement a private interface except within that interface's defining class
    //除了定义该私有接口的类以外,不能使用私有接口
    //class DImp implements A.D{ public void f(){}}
    class EImp implements E{ public void g(){}}
    class EGImp implements E.G{ public void f(){}}
    public static void main(String[] args) 
    {
        A a=new A();
        //A.D ad= a.getD();    //Can't access A.D  不能定义
       
        //A.DImp2 di2= a.getD();   //返回值为A.D类型

        //a.getD().f();         //Cannot access a member of the interface  返回类型D为private
        a.receiveD(a.getD());
    }
}

作为嵌套接口,接口也可以被实现为private。
Private接口可以强制接口中的方法定义不能添加任何类型信息(也就是说,不允许向上转型)

第十章

链接到外部类
内部类自动拥有对其外部类所有成员的访问权。因为,当某个外围类的对象创建了一个内部类的对象时,此内部类对象必定会秘密捕捉一个指向那个外围类对象的引用。然后,在访问此外围类成员时就用该引用访问外围类成员(编译器会处理所有细节)。
使用.this与.new
如果需要生成对外部类的引用,可以使用外部类的名字后紧跟“.this”(有圆点,下同),这样产生的引用自动地具有正确的类型。

public class test
{
    void f(){ System.out.println("test.f()");}
    public class Inner
    {
        public test outer()
        {
            return test.this;
        }
    }
    public Inner inner(){ return new Inner();}
    public static void main(String[] args) {
        test t= new test();
        test.Inner ti=t.inner();
        ti.outer().f();
    }
}

//运行结果:
//test.f()

有时可能需要告知其他对象,去创建某个内部类对象。要实现此目的,需要用new表达式中提供对其他外部类对象的引用,这需要“.new”语法。

public class test
{
    public class Inner{}
    public static void main(String[] args) {
        test t= new test();
        test.Inner ti= t.new Inner();
    }
}

想要直接创建内部类对象,不能直接去引用外部类的名字,而是必须使用外部类的对象来创建该内部类对象。
在拥有外部类对象之前是不可能创建内部类对象的。因为内部类对象会暗暗地连接到创建它的外部类对象上(但是嵌套类,即静态内部类,是不需要对外部类的引用的)。
匿名内部类
Contents()方法将返回值的生成与表示这个返回值的类的定义结合在一起。注释部分为“取名”了的“匿名类”

interface Contents{}
public class test
{
    public Contents contents()
    {
        return new Contents(){
            private int i=11;
            public int value(){  return i;}
        };
    }
    public static void main(String[] args) {
        test t= new test();
        Contents c= t.contents();       //c为test类
        //System.out.println(c.toString());
    }
}
/*
public class test
{
    class MyContents implements Contents
    {
        private int i=11;
        public int value(){ return i;}
    }
    public Contents contents(){ return new MyContents();}
    public static void main(String[] args) 
    {
        test t= new test();
        Contents c= t.contents();    
    }
}*/

嵌套类
如果不需要内部类对象与外围类对象之间的联系,那么可以将内部类声明为static
嵌套类意味着:
要创建嵌套类的对象,并不需要其外围类的对象
不能从嵌套类的对象中访问非静态的外围类对象
接口内部类
正常情况下,不能在接口内部放置任何代码,但嵌套类可以作为接口一部分。放入接口中的任何类都自动地是public和static的,因为类是static的,只是将嵌套类置于接口的命名空间内,并不违反接口的规则。甚至在内部类都可以实现外围接口。

public interface test
{
    void howdy();
    class Test implements test
    {
        public void howdy()
        {
            System.out.println("Howdy!");
        }
        public static void main(String[] args) {
            new Test().howdy();
        }
    }
}
//输出:
//Howdy!

如果想要创建某些公共代码,使得它们可以被某个接口的所有不同实现所共用,那么使用内部接口的嵌套类将会很方便。
一个内部类被嵌套多少层并不重要,它能透明地访问所有它所嵌入的外围类的所有成员。
内部类的继承
因为内部类的构造器必须连接到指向其外围类对象的引用,所以在继承内部类的时候,情况会变得复杂。即,指向外围类对象的“秘密的“引用必须被初始化,而在导出类中不再存在可连接的默认对象,因此需要特殊的语法:

class outer
{
    class inner{}
}
public class test extends outer.inner
{
    //test(){}  编译错误!
    test(outer o)
    {
        o.super();
    }
}

内部类可以被覆盖吗

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 test extends Egg
{
    public class Yolk{ public Yolk(){ System.out.println("test.Yolk()");}}
    public static void main(String[] args) {
        new test();    
    }
}
//输出:
/*
    new Egg()
    Egg.Yolk()
*/

默认构造器是编译器自动生成的,这里调用基类的默认构造器。可能大家会觉得,既然创建了test的对象,所使用的应该是“覆盖后“的Yolk版本(和之前的方法覆盖对比看),但从输出结果来看并非如此。
原因是,继承某个外围类的时候,内部类并没有发生特别的变化。这两个内部类是安全独立的两个实体,各自在各自的命名空间。当然,也可以明确继承某类的内部类。

class Egg
{
    protected class Yolk
    {
        public Yolk(){ System.out.println("Egg.Yolk()");}
        public void f(){ System.out.println("Egg.f()");}
    }
    private Yolk y= new Yolk();
    public Egg(){ System.out.println("new Egg()");}
    public void insertYolk(Yolk yy){ y=yy;}
    public void g(){ y.f();}
}
public class test extends Egg
{
    public class Yolk extends Egg.Yolk      //明确继承Egg的内部类
    {
        public Yolk(){ System.out.println("test.Yolk()");}      //覆盖内部的方法
        public void f(){ System.out.println("test.f()");}
    }
    public test(){  insertYolk(new Yolk());}
    public static void main(String[] args) {
        Egg e= new test();  //向上转型
        e.g();      //调用的g()是覆盖后的方法
    }
}
//输出结果:
/*
    Egg.Yolk()
    new Egg()  
    Egg.Yolk() 
    test.Yolk()
    test.f() 
*/

局部内部类
典型的代表就是方法题内创建,局部类不能有访问说明符,因为不是外围类的一部分,但可以访问当前代码块内的常量,以及此外围类的所有成员。

interface Counter{ int next();}
public class test
{
    private int count=0;
    Counter getCounter(final String name)
    {
        class LocalCounter implements Counter
        {
            //局部内部类可以有构造方法
            public LocalCounter(){ System.out.println("LocalCounter()");}
         
            public int next()
            {
                System.out.println(name);
                return count++;
            }
        }    
        return new LocalCounter();
    }
    //用匿名类展示
    Counter getCounter2(final String name)
    {
        return new Counter(){          //匿名类
            { System.out.println("Counter()");}
            public int next()
            {
                System.out.println(name);
                return count++;
            }
        };
    }
    public static void main(String[] args) {
        test temp= new test();
        Counter
            c1=temp.getCounter("Local Inner"),
            c2=temp.getCounter2("Anonymous");
        for(int i=0;i<5;i++)    System.out.println(c1.next());
        for(int i=0;i<5;i++)    System.out.println(c2.next());
        
    }
}
//输出:
/*
    LocalCounter()
    Counter()
    Local Inner
    0
    Local Inner
    1
    Local Inner
    2
    Local Inner
    3
    Local Inner
    4
    Anonymous
    5
    Anonymous
    6
    Anonymous
    7
    Anonymous
    8
    Anonymous
    9
*/

选用局部内部类的理由:
1、我们需要一个已命名的构造器,或重载构造器,而匿名内部类只能用于实例化。2、需要不止一个该内部类的对象。

[1] Bruce Eckel.Java编程思想[M].陈昊鹏,北京:机械工业出版社出版社.2007

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值