黑马程序员技术交流社区

标题: 求内部类的讲解 [打印本页]

作者: 雷云红    时间: 2012-5-12 23:07
标题: 求内部类的讲解
求内部类的讲解???:loveliness:
作者: 金肖    时间: 2012-5-12 23:14
内部类访问特点:
1,内部类可以直接访问外部类中的成员
2,外部类访问内部类,必须建立内部类的对象
规则:当内部类中有静态成员,那么该类也必须是静态的 。
应用:
一般用于设计
分析事物时,发现该事物描述中还有事物,而且这个事物还在访问被描述事物的内容。
这时就把还有的事物定义成内部类来描述。
直接访问内部类中的成员:
为什么外部类能直接访问外部类中的成员?
因为内部类持有了外部类的引用。

细节:
1,内部类可以存放在局部位置上:
2,内部类在局部位置上只能访问局部被final修饰的局部变量
细节:(访问格式)
1,如果直接访问外部类中的内部类中的成员
Outer.Inner in = new Outer().new Inner();//外部类名. 内部类名  名称 = new 外部名().new 内部名
2,如果内部类是静态的,相当与一个外部类
Outer.Inner in = new Outer.Inner();
3,如果内部类是静态的,成员是静态的//如果内部类中定义了静态成员,该内部类也必须是静态的
Outer.Inner.function();

作者: 匿名    时间: 2012-5-12 23:14
1、内部类访问数据变量
当在某些时候,内部类中定义的变量与外部类中变量名称相同时,如何确保正确地访问每一个变量呢?

1.1在main中直接从外部类调用内部类的方法

class Outer
{
    private int index = 10;
    class Inner
    {
        private int index = 20;
        void print()
        {
            int index = 30;
            System.out.println(this); // the object created from the Inner
            System.out.println(Outer.this); // the object created from the Outer
            System.out.println(index); // output is 30
            System.out.println(this.index); // output is 20
            System.out.println(Outer.this.index); // output is 10
        }
    }

    void print()
    {
        Inner inner = new Inner();//得到内部类的引用
        inner.print();
    }
}

class Test
{
    public static void main(String[] args)
    {
        Outer outer = new Outer();
        outer.print();
    }
}
在这里内部类Inner中关键字this指向内部类Inner的对象,如果要想指向外部类的对象,必须在this指针前加上外部类名称,表示this是指向外部类构造的碎屑,如Outer.this 。

1.2在main中显式返回内部类引用

class Outer
{
    private int index = 10;
    class Inner
    {
        private int index = 20;
        void print()
        {
            int index = 30;
            System.out.println(index);
            System.out.println(this.index);
            System.out.println(Outer.this.index);
        }
    }

    Inner getInner()
    {
        return new Inner();//返回一个内部类的引用
    }
}

class Test
{
    public static void main(String[] args)
    {
        Outer outer = new Outer();
        Outer.Inner inner = outer.getInner();
        inner.print();
    }
}
Inner是Outer的内部类,所以在类Test中必须用属性引用符来标识出内部类。

1.3当main方法在Outer类内部

class Outer
{
        private int index = 10;
        class Inner
        {
             private int index = 20;
             void print()
             {
                  int index = 30;
                  System.out.println(index);
                  System.out.println(this.index);
                  System.out.println(Outer.this.index);
             }
        }

        Inner getInner()
        {
             return new Inner();//返回一个内部类的引用
        }

        public static void main(String[] args)
        {
             Outer outer = new Outer();
             Inner inner = outer.getInner(); // 注意此处变化
             inner.print();
        }
}
因为main方法在Outer内部,故可以直接引用,不需要属性引用符。


1.4在main方法中直接产生内部类对象

class Test
{
        public static void main(String[] args)
        {
             Outer outer = new Outer();
             Outer.Inner inner = outer.new Inner(); // 注意此处变化
             inner.print();
        }
}
在利用new构造方法构造一个外部类对象时,并没有连带着构造一个内部类对象,故需要访问内部类方法时,必须使用new操作符为这个外部类对象再构造一个内部类对象。

2、局部内部类
在方法中定义的内部类是局部内部类,它只能访问方法中的final类型的局部变量,因为用final定义的局部变量相当于是一个常量,延长了其生命周期,使得方法在消亡时,其内部类仍可以访问该变量。另外,它同样也可以引用定义在外部类的变量和方法。而且方法体中的局部内部类不允许有访问修饰符。

class Outer
{
        int num=10;
        public void print(final int aArgs)
        {
             class Inner
             {
                 int num=20;
                 public Inner()
                 {
                     System.out.println("This is Inner.");//此句可看出它与匿名内部类用法的不同。
                 }

                 public void print()
                 {     
                     int num=30;
                     System.out.println(this); // the object created from the local Inner
                     System.out.println(num);
                     System.out.println(this.num);
                     System.out.println(Outer.this.num);
                     System.out.println(aArgs);
                 }
             }
             Inner inner=new Inner();//此句必须放在定义类Inner的后面
             inner.print();
        }

        public static void main(String[] args)
        {
             Outer outer=new Outer();
             outer.print(40);
        }
}
对于局部类的命名,不管是在一个方法中定义多个类还是在几个方法中分别定义类,其编译后命名是:OuterClass$1InnerClass.class

3、匿名内部类
匿名内部类作为一种特殊的内部类,除了具有普通内部类的特点,还有自己的一些独有特性:
匿名内部类必须扩展一个基类或实现一个接口,但是不能有显式的extends和implements子句;
匿名内部类必须实现父类以及接口中的所有抽象方法;
匿名内部类总是使用父类的无参构造方法来创建实例。如果是实现了一个接口,则其构造方法是Object();
匿名内部类编译后的命名为:OuterClass$n.class,其中n是一个从1开始的整数,如果在一个类中定义了多个匿名内部类,则按照他们的出现顺序从1开始排号。

abstract class A
{
    abstract public void sayHello();
}

class Outer
{
    public static void main(String[] args)
    {
         new Outer().callInner(new A()
         {
               public void sayHello()
               {
                     System.out.println(this); // the object created from the anonymous Inner
                     System.out.println("Hello!");
               }
         });
    }

    public void callInner(A a)
    {
        a.sayHello();
    }
}

4、静态内部类
和非静态内部类相比,区别就在于静态内部类没有了指向外部类的引用。除此之外,在任何非静态内部类中,都不能有静态数据,静态方法或者又一个静态内部类(内部类的嵌套可以不止一层)。不过静态内部类中却可以拥有这一切。这也算是两者的第二个区别吧。一个静态的内部类,才可以声明一个static成员,静态内部类可以访问外围类的静态方法、成员(包括private static的成员)。静态内部类实例化的时候不必先实例化外围类,可以直接实例化内部类。而对于非静态内部类则必须先实例化其外部类,才能再实例化本身。

5.内部类的继承
当一个类继承自一个内部类时,缺省的构造器不可用。必须使用如下语法:
class WithInner
{
    class Inner
    {
        public void sayHello()
        {
            System.out.println("Hello.");
        }
    }
}

public class Test extends WithInner.Inner
{
    Test(WithInner wi)
    {
        wi.super();
    }
    public static void main(String[] args)
    {
        WithInner wi=new WithInner();
        Test test=new Test(wi);
        test.sayHello();
    }
}
因为每一个内部类都有一个指向外部类的引用,在继承一个内部类,必须先创建一个外部类,通过这个外部类引用来调用其内部类的构造方法。如果继承的内部类是一个静态内部类,则就不需要这样,直接super()调用即可;

6、内部类的2种特殊用法
一个类从另一个类派生出来,又要实现一个接口。但在接口中定义的方法与父类中定义的方法的意义不同,则可以利用内部类来解决这个问题。
interface Machine
{
    void run();
}

class Person
{     
    void run()
    {
        System.out.println("run");
    }
}

class Robot extends Person
{
    private class MachineHeart implements Machine
    {
        public void run()
        {
            System.out.println("heart run");
        }
    }

    Machine getMachine()
    {
        return new MachineHeart();
    }
}

class Test
{
    public static void main(String[] args)
   {
        Robot robot = new Robot();
        Machine m = robot.getMachine();
        m.run();
        robot.run();
    }
}
在Robot类内部使用内部类MachineHeart来实现接口Machine的run方法。同时Robot类又继承了父类Person的run方法。如果不使用内部类MachineHeart而使Robot直接实现接口Machine,则该如何调用父类的run方法?

利用内部类可解决c++中多重继承所解决的问题
class A
{
    void fn1()
    {
        System.out.println("It' s fn1.");
    }
}

abstract class B
{
    abstract void fn2();
}

class C extends A
{
    B getB()
    {
        return new B()
        {
            public void fn2()
            {
                System.out.println("It' s fn2.");
            }
        };
    }
}

class Test
{
    public static void main(String[] args)
    {
        C c = new C();
        c.fn1();
        c.getB().fn2();
    }
}
类C既要继承类A又要继承类B,则可将类B的定义放入类C内部,使之成为内部类。


一般情况下 当我们需要在某一情形下实现一个接口,而在另一情形下又不需要实现这个接口时,我们可以使用内部类来解决这一问题。让内部类来实现这个接口。另外一个很好的理由是java内部类加上接口可以有效地实现多重继承。
作者: 郭振    时间: 2012-5-12 23:14
1、内部类访问数据变量
当在某些时候,内部类中定义的变量与外部类中变量名称相同时,如何确保正确地访问每一个变量呢?

1.1在main中直接从外部类调用内部类的方法

class Outer
{
    private int index = 10;
    class Inner
    {
        private int index = 20;
        void print()
        {
            int index = 30;
            System.out.println(this); // the object created from the Inner
            System.out.println(Outer.this); // the object created from the Outer
            System.out.println(index); // output is 30
            System.out.println(this.index); // output is 20
            System.out.println(Outer.this.index); // output is 10
        }
    }

    void print()
    {
        Inner inner = new Inner();//得到内部类的引用
        inner.print();
    }
}

class Test
{
    public static void main(String[] args)
    {
        Outer outer = new Outer();
        outer.print();
    }
}
在这里内部类Inner中关键字this指向内部类Inner的对象,如果要想指向外部类的对象,必须在this指针前加上外部类名称,表示this是指向外部类构造的碎屑,如Outer.this 。

1.2在main中显式返回内部类引用

class Outer
{
    private int index = 10;
    class Inner
    {
        private int index = 20;
        void print()
        {
            int index = 30;
            System.out.println(index);
            System.out.println(this.index);
            System.out.println(Outer.this.index);
        }
    }

    Inner getInner()
    {
        return new Inner();//返回一个内部类的引用
    }
}

class Test
{
    public static void main(String[] args)
    {
        Outer outer = new Outer();
        Outer.Inner inner = outer.getInner();
        inner.print();
    }
}
Inner是Outer的内部类,所以在类Test中必须用属性引用符来标识出内部类。

1.3当main方法在Outer类内部

class Outer
{
        private int index = 10;
        class Inner
        {
             private int index = 20;
             void print()
             {
                  int index = 30;
                  System.out.println(index);
                  System.out.println(this.index);
                  System.out.println(Outer.this.index);
             }
        }

        Inner getInner()
        {
             return new Inner();//返回一个内部类的引用
        }

        public static void main(String[] args)
        {
             Outer outer = new Outer();
             Inner inner = outer.getInner(); // 注意此处变化
             inner.print();
        }
}
因为main方法在Outer内部,故可以直接引用,不需要属性引用符。


1.4在main方法中直接产生内部类对象

class Test
{
        public static void main(String[] args)
        {
             Outer outer = new Outer();
             Outer.Inner inner = outer.new Inner(); // 注意此处变化
             inner.print();
        }
}
在利用new构造方法构造一个外部类对象时,并没有连带着构造一个内部类对象,故需要访问内部类方法时,必须使用new操作符为这个外部类对象再构造一个内部类对象。

2、局部内部类
在方法中定义的内部类是局部内部类,它只能访问方法中的final类型的局部变量,因为用final定义的局部变量相当于是一个常量,延长了其生命周期,使得方法在消亡时,其内部类仍可以访问该变量。另外,它同样也可以引用定义在外部类的变量和方法。而且方法体中的局部内部类不允许有访问修饰符。

class Outer
{
        int num=10;
        public void print(final int aArgs)
        {
             class Inner
             {
                 int num=20;
                 public Inner()
                 {
                     System.out.println("This is Inner.");//此句可看出它与匿名内部类用法的不同。
                 }

                 public void print()
                 {     
                     int num=30;
                     System.out.println(this); // the object created from the local Inner
                     System.out.println(num);
                     System.out.println(this.num);
                     System.out.println(Outer.this.num);
                     System.out.println(aArgs);
                 }
             }
             Inner inner=new Inner();//此句必须放在定义类Inner的后面
             inner.print();
        }

        public static void main(String[] args)
        {
             Outer outer=new Outer();
             outer.print(40);
        }
}
对于局部类的命名,不管是在一个方法中定义多个类还是在几个方法中分别定义类,其编译后命名是:OuterClass$1InnerClass.class

3、匿名内部类
匿名内部类作为一种特殊的内部类,除了具有普通内部类的特点,还有自己的一些独有特性:
匿名内部类必须扩展一个基类或实现一个接口,但是不能有显式的extends和implements子句;
匿名内部类必须实现父类以及接口中的所有抽象方法;
匿名内部类总是使用父类的无参构造方法来创建实例。如果是实现了一个接口,则其构造方法是Object();
匿名内部类编译后的命名为:OuterClass$n.class,其中n是一个从1开始的整数,如果在一个类中定义了多个匿名内部类,则按照他们的出现顺序从1开始排号。

abstract class A
{
    abstract public void sayHello();
}

class Outer
{
    public static void main(String[] args)
    {
         new Outer().callInner(new A()
         {
               public void sayHello()
               {
                     System.out.println(this); // the object created from the anonymous Inner
                     System.out.println("Hello!");
               }
         });
    }

    public void callInner(A a)
    {
        a.sayHello();
    }
}

4、静态内部类
和非静态内部类相比,区别就在于静态内部类没有了指向外部类的引用。除此之外,在任何非静态内部类中,都不能有静态数据,静态方法或者又一个静态内部类(内部类的嵌套可以不止一层)。不过静态内部类中却可以拥有这一切。这也算是两者的第二个区别吧。一个静态的内部类,才可以声明一个static成员,静态内部类可以访问外围类的静态方法、成员(包括private static的成员)。静态内部类实例化的时候不必先实例化外围类,可以直接实例化内部类。而对于非静态内部类则必须先实例化其外部类,才能再实例化本身。

5.内部类的继承
当一个类继承自一个内部类时,缺省的构造器不可用。必须使用如下语法:
class WithInner
{
    class Inner
    {
        public void sayHello()
        {
            System.out.println("Hello.");
        }
    }
}

public class Test extends WithInner.Inner
{
    Test(WithInner wi)
    {
        wi.super();
    }
    public static void main(String[] args)
    {
        WithInner wi=new WithInner();
        Test test=new Test(wi);
        test.sayHello();
    }
}
因为每一个内部类都有一个指向外部类的引用,在继承一个内部类,必须先创建一个外部类,通过这个外部类引用来调用其内部类的构造方法。如果继承的内部类是一个静态内部类,则就不需要这样,直接super()调用即可;

6、内部类的2种特殊用法
一个类从另一个类派生出来,又要实现一个接口。但在接口中定义的方法与父类中定义的方法的意义不同,则可以利用内部类来解决这个问题。
interface Machine
{
    void run();
}

class Person
{     
    void run()
    {
        System.out.println("run");
    }
}

class Robot extends Person
{
    private class MachineHeart implements Machine
    {
        public void run()
        {
            System.out.println("heart run");
        }
    }

    Machine getMachine()
    {
        return new MachineHeart();
    }
}

class Test
{
    public static void main(String[] args)
   {
        Robot robot = new Robot();
        Machine m = robot.getMachine();
        m.run();
        robot.run();
    }
}
在Robot类内部使用内部类MachineHeart来实现接口Machine的run方法。同时Robot类又继承了父类Person的run方法。如果不使用内部类MachineHeart而使Robot直接实现接口Machine,则该如何调用父类的run方法?

利用内部类可解决c++中多重继承所解决的问题
class A
{
    void fn1()
    {
        System.out.println("It' s fn1.");
    }
}

abstract class B
{
    abstract void fn2();
}

class C extends A
{
    B getB()
    {
        return new B()
        {
            public void fn2()
            {
                System.out.println("It' s fn2.");
            }
        };
    }
}

class Test
{
    public static void main(String[] args)
    {
        C c = new C();
        c.fn1();
        c.getB().fn2();
    }
}
类C既要继承类A又要继承类B,则可将类B的定义放入类C内部,使之成为内部类。


一般情况下 当我们需要在某一情形下实现一个接口,而在另一情形下又不需要实现这个接口时,我们可以使用内部类来解决这一问题。让内部类来实现这个接口。另外一个很好的理由是java内部类加上接口可以有效地实现多重继承。
作者: 张成龙    时间: 2012-5-12 23:21
内部类  :就是指在类中在定义一个类   
2  内部类有四种各自创建内部类的对象的方式不一样
  a   静态内部类(static inner class ):只能访问外部类的静态成员变量与静态方法,生成静态内部类对象的方式为:  例如  :OuterClass.InnerClass inner = new OuterClass.InnerClass();
   b   成员内部类(member inner class ):可以访问外部类的静态与非静态的方法与成员变量。生成成员内部类对象的方式为: 例如 :OuterClass.InnerClass inner = new OuterClass().new InnerClass();
   c   局部内部类(Local Inner Class):定义在方法当中,只能访问方法中声明的final 类型的变量。生成成员内部类对象的方式是  先new出外部类的对象然后在调用内部类所在外部类的那个方法;
  d  匿名内部类(Anonymous Inner Class ):匿名内部类会隐式地继承一个父类或实现一个接口。

匿名内部类:
1,匿名内部类其实就是内部类的简写格式。
2,定义匿名内部类的前提:
        内部类必须是继承一个类或者实现接口。
3,匿名内部类的格式:  new 父类或者接口(){定义子类的内容}
4,其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。        可以理解为带内容的对象。
5,匿名内部类中定义的方法最好不要超过3个。

作者: 雷云红    时间: 2012-5-13 21:25
呵呵,受教了。拜谢{:soso_e183:}
作者: 赵文杰    时间: 2012-5-13 22:19
                 class Outer
{
        int num = 20;
}

class Inner
{
        //想访问Outer里面的num。创建对象来实现。
}

内部类:将类A定义在另一个类B中。则类A就是内部类。

方法方式:
        A:内部类可以直接访问外部类中的成员,包括私有成员。
        B:而外部类要访问内部类中的成员必须要建立内部类的对象。


总结:有Outer和Inner两个类,当Inner想要直接访问Outer中的成员,
      而Outer需要建立Inner对象来访问Inner中的成员。这个时候,
      我们就可以把Inner定义为Outer的内部类。

如何定义一个内部类呢:把Inner放于Outer里边。

Inner可以放在Outer什么地方呢?
        A:内部类定义在成员位置上
                **可以被private,static成员修饰符修饰。

                clas Body
                {
                       
                        private class Heart()
                        {
                       
                        }

                        public Heart getHeart()
                        {
                                //可控
                                if(你是外科医生){
                                        Heart h = new Heart();
                                        return h;
                                }
                                else
                                {
                                       
                                }
                        }
                }
               
                **被static修饰的内部类只能访问外部类中的静态成员。
        B:内部类定义在局部位置上
                **也可以直接访问外部类中的成员。
                **同时可以访问所在局部中的局部变量,但必须是被final修饰的。
                Outer$Inner.class:$表示成员内部类。
                Outer$1Inner.class:$1表示它是一个局部内部类。
                        ***为什么会出现编号呢?因为局部内部类可以不写名字,所以带编号。

匿名内部类:没有名字的内部类。它是内部类的简化写法。
前提:内部类可以继承或实现一个外部类或者接口。
格式为:new 外部类名或者接口名(){覆盖类或者接口中的代码,(也可以自定义内容。)}
简单理解:就是建立一个带内容的外部类或者接口的子类匿名对象。

什么时候使用匿名内部类呢?
通常在使用方法是接口类型参数,并该接口中的方法不超过三个时,可以将匿名内部类作为参数传递。
增强阅读性。                       
作者: 赵方明    时间: 2012-5-13 22:22
内部类是定义在其它类内部的类。包含内部类的类就被称为外部类。
内部类的优点:
1,提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其它类访问该类。
2,内部类可以直接访问外部类的私有数据,因为内部类被当成外部类成员,同一个类的成员之间可以互相访问。
作者: 高鑫    时间: 2012-5-13 22:24
  1. class  Outer
  2. {
  3.         int x=3;
  4.         void method(final int a)       
  5.         {
  6.                 int y=5;                               
  7.                 class Inner                                                        //内部类定义在局部时
  8.                 {
  9.                         void function()
  10.                         {
  11.                                 System.out.println(x);                //这里局部变量的y和a都必须为final型才能打印
  12.                                                                                         //x可以直接打印
  13.                         }                               
  14.                  }
  15.         }
  16. }

  17. class Demo
  18. {
  19.         public static void main(String args[])
  20.         {
  21.             new Outer ().method(7);
  22.         }
  23. }
复制代码
1, 当内部类在外部类成员位置上且为非私有,可以在外部其他类中直接建立内部类对象,格式: 外部类名.内部类名  变量名=外部类对象.内部类对象;
              eg: Outer.Inner in=new Outer().new Inner();
          2, 当内部类在成员位置上,就可以被成员修饰符修饰
               比如,private:将内部类在外部类中进行封装
               当内部类被satatic修饰就只能访问外部类中的static成员
          3,在外部其他类中,如何访问static内部类的非静态成员
               new Outer.Inner().function();
          4 ,  在外部其他类中,如何访问static内部类的static成员
               Outer.Inner.fuction();
          注意:当内部类中定义了static成员,该内部类必须是static的
          当外部类中的static方法访问内部类时,内部类也必须是static的(静态不能访问非静态)





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2