chapter8 面向对象之内部类

内部类的介绍及分类

在类内部可定义成员变量和方法,且在类内部也可以定义另一个类。如果在类 Outer 的内部再定义一个类 Inner,此时类 Inner 就称为内部类(或称为嵌套类),而类 Outer 则称为外部类(或称为宿主类)。

内部类可以很好地实现隐藏,一般的非内部类是不允许有 private 与 protected 权限的,但内部类可以。内部类拥有外部类的所有元素的访问权限

内部类可以分为:实例内部类(没有被static修饰)、静态内部类(被static修饰)和成员内部类(定义在外部类中的方法中),每种内部类都有它特定的一些特点。

内部类的特点如下:
①内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号

②内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的任何的成员变量

内部类声明成静态的,就不能随便访问外部类的成员变量,仍然是只能访问外部类的静态成员变量。内部类依旧是外部类的一个成员,不过这个成员是静态成员罢了,那么根据静态方法只能访问静态成员,那么这个同理,静态内部类只能访问外部类的静态成员变量(即使这个静态变量是private修饰),如果要访问其他的成员,那么先建立一个外部类对象,然后再让这个外部类对象调用即可

内部类与外部类不能重名

外部类要访问内部类的成员,那么需要先新建内部类的实例,然后通过这个实例进行访问、调用

实例:

public class DemoOutter {
    private int a = 8,b = 2;
    public static int c = 5, d = 8;
    //定义一个实例内部类 -- 没有被static修饰
    public class DemoInner{
        public int add(){
            //内部类直接访问私有变量(由于这个内部类是外部类的一个成员,因此也可以直接访问这个私有变量)
            return a + b;
        }

        public int subject(){
            //内部类直接访问私有变量(由于这个内部类是外部类的一个成员,因此也可以直接访问这个私有变量)
            return a - b;
        }

        public int multiply(){
            return c * d;//内部类访问外部类中的static变量
        }

        public int divide(){
            if(b == 0)
                throw new RuntimeException("除数不可以为0");
            return a / b;
        }
    }

    public static void main(String[] args){
        DemoOutter.DemoInner inner = new DemoOutter().new DemoInner();//外部类通过完整的类名访问内部类,由于这个内部类是一个实例内部类,因此再主函数中必须是这样
        //外部类当然可以DemoInner inner = new DemoInner();这样定义内部类
        try{
        //如果除数为0,那么就抛出异常
            System.out.println(inner.divide());//输出4
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        //实例内部类直接访问静态变量
        System.out.println(inner.multiply());//输出40
        System.out.println(inner.add());//输出10
        System.out.println(inner.subject());//输出6
    }
}

实例内部类

实例内部类:没有被static修饰的内部类,也叫做非静态内部类。

特点:
在外部类的静态方法中,不可以直接创建实例内部类,即不可以是InnerClass inner = new InnerClass();,因为实例内部类并没有被static修饰,那么根据static修饰的方法,即静态方法只能直接访问静态成员,如果要访问非静态成员,那么需要创建这个类的对象,然后通过这个对象进行访问、调用。因此我们得出结论了在外部类的静态方法中,不可以直接创建实例内部类,而是需要通过创建外部类的实例,然后再进行创建内部类的实例。即
InnerClass inner = new OutterClass().new InnerClass();

在外部类的非静态方法中,可以直接创建实例内部类的实例,即可以InnerClass inner = new InnerClass();,因为非静态方法既可以直接访问非静态成员,也可以直接访问静态成员。

在外部类以外的类中,如果需要访问创建它的内部类,那么就需要通过完整的类名进行创建。即
OutterClass.InnerClass inner = new OutterClass().new InnerClass();

实例内部类可以访问外部类的所有成员,不管他是否为静态的static的(非静态成员既可以访问静态成员,也可以访问非静态成员)、私有的private(因为实力内部类就是这个外部类的一个成员,当然可以访问这个私有成员了)。
④在外部类中不能直接访问内部类的成员,而必须通过内部类的实例去访问。如果类 A 包含内部类 B,类 B 中包含内部类 C,则在类 A 中不能直接访问类 C,而应该通过类 B 的实例去访问类 C。

⑤如果实例内部类 B 与外部类 A 包含有同名的成员 t,在内部类中要访问这个变量的时候,则在类 B 中 t 和 this.t 都表示 B 中的成员 t,如果而 外部类类名.this.t 表示 外部类A 中的成员 t

在实例内部类中不能定义 static 成员,除非同时使用 final 和 static 修饰

public class InnerClassTest1 {
    int num = 4;
    class Inner{
        int num = 9;
        void show(){
            int num = 8;
            System.out.println(num);//输出8
            System.out.println(this.num);//输出9(这个的区别就是普通类中局部变量、全局变量的写法)
//内部类中的成员和外部类的成员同名,那么内部类要访问外部类这个成员的时候,则应写 外部类类名.this.成员
            System.out.println(InnerClassTest1.this.num);//输出4
        }
        public void display(){
            show();//调用内部类中的方法
            InnerClassTest1.this.show();//内部类中调用外部类的静态成员
        }
    }
    
    public static void show(){
        System.out.println("学习内部类");
    }
    public void method(){
        //外部类的非静态方法要访问内部类的成员,那么可以直接新建一个内部类对象,然后才可以调用内部类的成员方法
        Inner in = new Inner();//直接新建内部类对象
        /*
        在外部类非静态方法中要访问内部类成员,构建内部类的第二种形式
        Inner in1 = new InnerClassTest1().new Inner();//先构建外部类对象,然后再通过这个对象新建内部类对象,之后再访问
        第三种形式:完整的类名进行访问
        InnerClassTest1.Inner in2 = new InnerClassTest1().new Inner();//只有这一种是外部类以外的类要访问内部类时构建内部类对象的形式
         */
        in.show();
    }
    public static void main(String[] args){
        new InnerClassTest1().method();
        //在静态方法中,那么不可以直接新建内部类,需要通过外部类的实例进行建立
        Inner in = new InnerClassTest1().new Inner();//通过外部类的实例进行创建内部类
        System.out.println(in.num);//输出9(外部类访问内部类成员,新建内部类实例进行访问)
        System.out.println(new InnerClassTest1().num);//外部类的静态成员访问外部类非静态成员
        in.display();
    }
}

在这里插入图片描述

静态内部类

静态内部类:被static修饰的内部类。

特点:
在外部类中创建静态内部类的实例时,不需要创建外部类的实例。因为静态成员只能访问静态成员,非静态成员既可以访问非静态成员,也可以访问静态成员。因此创建静态内部类的实力的时候,不需要创建外部类的实例。即
1)OutterClass.InnerClass inner = new OutterClass.InnerClass();
2)InnerClass inner = new InnerClass();
3)OutterClass.InnerClass inner = new InnerClass();

外部类以外的其他类需要通过完整的类名访问静态内部类中的静态成员,同样不需要创建外部类的实例
OutterClass.InnerClass inner = new OutterClass.InnerClass();,这时候我们发现和上面的实例内部类的创建有区别了,这里并没有创建外部类的实例,即不是new OutterClass().new InnerClass()。如果像实力内部类那样创建的话,发现会发生报错。

③静态内部类可以直接访问外部类的静态成员,如果要访问外部类的实例成员,则需要通过外部类的实例去访问

④静态内部类B和它的外部类A有一些同名成员t,那么 1) t , 2) 静态内部类类名.t (在外部类中要访问静态内部类中的静态成员可以是这样只,也可以是下面那一种方式), 3) 外部类类名.静态内部类类名.t (这个适用于外部类以外的类直接访问静态内部类的静态成员)都是静态内部类的

外部类类名.t 是外部类A的访问这个类的**静态成员****。

对于静态成员,可以直接通过类名进行访问,非静态成员,则要新建对象进行访问。

⑤静态内部类中可以含有静态成员static,也可以含有非静态成员。外部类如果要访问这个静态内部类的非静态成员,那么就要通过这个静态内部类的实例进行访问,如果访问的是静态成员,那么可以通过这个静态内部类的类名直接访问,也可以通过完整的类名进行访问,也可以新建这个内部了的实例进行访问
外部类以外的其他类需要通过完整的类名访问静态内部类中的静态成员,如果要访问静态内部类中的非静态成员,则需要通过静态内部类的实例

public class InnerClassTest2 {
    public int num = 2;
    public static int x = 3;
    static class Inner{
        int x = 4;
        static int y = 9;
        void show(){
            int x = 5;
            System.out.println(x);//输出5
            System.out.println(this.x);//输出4
            //内部类中访问外部类的静态成员,通过外部类的类名直接访问,也可以新建对象,然后通过这个对象进行访问
            System.out.println(InnerClassTest2.x);
            //静态内部类中访问外部类的非静态成员,要新建外部类对象,然后通过这个对象实例进行访问
            System.out.println(new InnerClassTest2().num);
        }
    }

    public void method(){
        //外部类中的静态方法要访问静态内部类的成员时,那么需要新建这个内部类的对象,然后才可以访问
       Inner in = new InnerClassTest2.Inner();
       in.show();
    }

    public static void main(String[] args){
        Inner in = new Inner();//外部类中静态方法中可以直接新建静态内部类的对象
        /*
        静态方法中新建静态内部类对象的第二种方式:
        Inner in = new InnerClassTest2.Inner();
        第三种:完整类名进行构建(外部类以外的类只有这一种方式构建外部类的静态内部类)
        InnerClassTest2.Inner in = new InnerClassTest2.Inner();
         */
        in.show();
        new InnerClassTest2().method();//静态方法要调用非静态成员,那么需要新建对象,然后再进行调用
        //外部类访问静态内部类的静态成员,可以直接通过类名进行访问,也可以新建这个类的对象进行访问
        System.out.println(InnerClassTest2.Inner.y);//输出9
        //外部类访问当前这个外部类的静态成员,可以直接通过类名进行访问,也可以新建这个类的对象进行访问
        System.out.println(InnerClassTest2.x);//输出3
    }
}

在这里插入图片描述

局部内部类

局部内部类是指在一个方法中定义的内部类。

特点:
1)局部内部类与局部变量一样,不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰

2)局部内部类只在当前方法中有效

3)局部内部类中不能定义 static 成员

4)局部内部类中还可以包含内部类,但是这些内部类也不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。

5)在局部内部类中可以访问外部类的所有成员

6)在局部内部类中只可以访问当前方法中*final 类型的参数与变量,或者如果这个方法中这个变量在被赋值之后没有再修改,那么就相当于常数,所以局部内部类同样可以访问如果方法中的成员与外部类中的成员同名,如果这个方法没有被static修饰(即这个方法不是静态方法),那么可以以 外部类名.this.成员名 / new 外部类名().成员名 的形式访问外部类中的成员,否则,如果这个方法是一个静态方法,那么只能通过 new 外部类名().成员名 来访问外部类中的成员,因为静态方法中不可以出现this、super关键字

public class InnerClassTest3 {
    int x =2;
    static int  g = 9;
    public static void method(){
    //静态方法中不可以出现this\super关键字
        int y = 3; //尽管没有被final修饰,但是只要这个数在进行赋值之后没有在进行修改,这个数就相当于常数,所以可以被局部内部类访问
        int z = 4;
        final  int a = 5;
        final int b = 6;
        class Inner{
            int x;
            int c = a + b;//局部内部类中只可以访问当前方法中的final参数
            int d = new InnerClassTest3().x;//这个方法时一个静态方法,所以不是 InnerClassTest3.this.x访问外部类的x,而应该时创建外部类实例来访问
            int e = g;//外部类的静态成员
            int f = y;//当前方法中的没有被final修饰的成员,但是这个成员赋值之后没有再被修改
            int add(){
               return a + this.x;//内部类的x,尽管这个方法是一个静态方法,但是内部类的x可以用this关键字和方法或者外部类的x区分
            }
        }
        Inner in = new Inner();
        System.out.println(in.f);
        System.out.println(in.c);
        System.out.println(in.d);
        System.out.println(in.e);
        //哪怕再上面的方法执行完毕之后,这时候更新y时,那么同样会出现错误提示
    }

    public static void main(String[] args){
        new InnerClassTest3().method();
    }
}

结果:
在这里插入图片描述

package extend.dao;
/*
局部内部类可以访问外部类的所有成员,但是只能访问所在方法的被final修饰的常量,或者尽管
没有被final修饰,但是这个变量只被赋值一次,否则就会抛出错误
 */
public class InnerClassTest {
    int x = 2;
    public static void main(String[] args) {
          testInner();
    }
    public static void testInner(){
        int x = 9;
        final int a = 138;
        int b = 6;//只被赋值一次,所以局部内部类可以访问
        int c = 2;//被赋值之后又被修改,所以局部内部类不可以访问
        //c = 10000;//无论时再内部类方法执行完毕之前,还是完毕之后进行修改,同样会发生报错
        class Inner{
            int x = 100;
            int add(){
                return a + b;//局部内部类访问当前所在方法的被final修饰的变量以及只进行一次赋值的变量
            }
            int subject(){
                /*
                //访问外部类的x
                如果这个方法不是静态方法,那么获取外部类的x的时候,可以时new InnerClassTest().x
                也可以是 InnerClassTest.this.x
                如果是静态方法,只能是new InnerClassTest().x
                 */
                return a -  new InnerClassTest().x;
            }
            int mul(){
                return b * this.x;//访问内部类的x(尽管这个方法是一个静态方法)
            }
            /*
            int divide(){
                if(a == 0)
                    throw new RuntimeException("除数不可以是0");
                return c / a; //c不只一次被赋值,所以局部内部类不可以访问,因此会出现报错
            }
            */

        }
        Inner inner = new Inner();
        System.out.println(a + " + " + b + " = " + inner.add());
        System.out.println(a + " - " + new InnerClassTest().x + " = " + inner.subject());
        System.out.println(b + " * " + inner.x + " = " + inner.mul());
        //发生报错,因为局部内部类可以访问不被final修饰,但是只被赋值一次的变量,一旦修改就出现错误提示
        //b = 9000;
    }
}

运行结果:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值