当前位置:首页 » 《资源分享》 » 正文

【Java 学习】:内部类详解

4 人参与  2024年09月06日 09:26  分类 : 《资源分享》  评论

点击全文阅读


详谈Java内部类

??本文将通过Java内部类 是什么,为什么被广泛使用,以及又该如何去使用这三个方面来详细讲解其相关知识。

文章目录

1. 内部类是什么

2. 为什么要使用内部类

3. 如何使用内部类

?成员内部类

?静态内部类

?局部内部类

?‍?匿名内部类

?总结


1. 内部类是什么

???当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么这个内部的完整结构最好使用内部类。在 Java 中,可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。内部类也是封装的一种体现。

/*** 外部类*/public class Outer {//.../*** 内部类*/class Inner {//...}}

注:

我们一般将内部类分为四种:成员内部类静态内部类局部(方法内部类)匿名内部类外部类的定义是相对于内部类而言的

2. 为什么要使用内部类

?使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。——《Think in java》

?也就是说内部类拥有类的基本特征。(eg:可以继承父类,实现接口)在实际问题中我们会遇到一些接口无法解决或难以解决的问题,此时我们可以使用内部类继承某个具体的或抽象的类,间接解决类无法多继承引起的一系列问题。

注:内部类可以嵌套内部类,但是这极大的破坏了代码的结构,但是这里不推荐使用。

举个例子?

/** 1. OuterClass类继承了 A,实现了IFunctionA*/public class OuterClass extends A implements IFunctionA{ /***Inner类继承了 B,实现了IFunctionB*/public class InnerClass extends B implements IfunctionB{//} }

除此之外,内部类还可以:

内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。内部类提供了更好的封装,除了该外围类,其他类都不能访问。创建内部类对象的时刻并不依赖于外围类对象的创建。

3. 如何使用内部类

?成员内部类

 ??也叫作实例内部类,是最普通的内部类,它的定义为位于另一个类的内部,形如下面的形式:

// 实例内部类class OuterClass {    public int data1 = 1;    public static int data2 = 2;    private int data3 = 3;    /*成员方法*/    public void OuterMethod() {        System.out.println("外部类的outerMethod方法");    }    /*静态方法*/    public static void OuterStaticMethod() {        System.out.println("外部类的outerStaticMethod静态方法");    }    /*同名方法*/    public void test() {        System.out.println("OutClass:: test()");        InnerClass innerClass = new InnerClass();    }    class InnerClass{        public int data1 = 10;        public int data4 = 4;        //public static int data5 = 5; // jdk8 不支持这样用,jdk17 支持        public static final int data5 = 5;        private int data6 = 6;        public void InnerShow() {            //访问内部类属性            System.out.println("data4:" + data4);            //内部类访问外部属性            System.out.println("data3:" + data3); //私有权限的外部类也可以访问            //当和外部类冲突时,直接引用属性名,是内部类的成员属性            System.out.println("data1:" + this.data1); // 默认为this            //当和外部类属性名重叠时,可通过外部类名.this.属性名            System.out.println("data1:" + OuterClass.this.data1); //访问外部类成员            // 访问外部类方法            OuterMethod();            OuterStaticMethod();        }        public void test(){            System.out.println("InnerClass:: test()");        }    }    /* 外部类访问内部类信息 */    public void OuterShow() {        InnerClass inner = new InnerClass();        inner.InnerShow();    }}public class Test {    /*其他类使用成员内部类*/    public static void main(String[] args) {        //创造内部类对象,两种实例化方法        OuterClass outer = new OuterClass(); //外部类对象        OuterClass.InnerClass inner1 = outer.new InnerClass();        OuterClass.InnerClass inner2 = new OuterClass().new InnerClass();        inner1.test();        inner1.InnerShow();    }}

运行结果如下:

注:成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。

总结:【抓住关键字——实例,作为实例成员存在】

内部类可以是任何的访问修饰符。由于成员内部类看起来像是外部类的一个成员,所以可以像类的成员一样拥有多种权限修饰符。内部类的内部不能有静态信息。内部类也是类,该继承的继承、该重写的重写、该重载的重载,this和super随便用。外部类访问内部类的信息,必须先实例化内部类,然后 . 访问。内部类可以直接使用外部类的任何信息,如果属性或者方法发生冲突(重名),使用Outer.this.成员其他类访问内部类:成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在外部类的对象。

?静态内部类

 ??Java中的静态内部类是指在一个类的内部定义的另一个类,并且该内部类被声明为静态(static)的。静态内部类与普通内部类的区别在于,静态内部类不依赖于外部类的实例,可以直接通过外部类名访问

// 静态内部类class Outer{    public int data1 = 1;    /*外部类定义的属性(重名)*/    public static int data2 = 2;    public static int data3 = 3;    static {        System.out.println("外部类静态块");    }    /*成员方法*/    public void outerMothod() {        System.out.println("外部类的成员方法");    }    /*静态方法*/    public static void outerStaticMethod() {        System.out.println("外部类的静态方法");    }    public void test(){        System.out.println("Out:: test()");    }    static class Inner{        public int data4 = 4;        public static int data5 = 5;        public static int data3 = 33; //与外部类同名        public void InnerShow(){            // 访问内部类成员属性            System.out.println("内部类data4:"+data4);            //访问外部类成员属性            //不重名访问 非静态成员属性            //System.out.println(data1); //无法直接访问外部非静态成员            System.out.println("data1:" + new Outer().data1); // 间接访问            //不重名直接访问 静态成员属性            System.out.println("外部类data2:" + data2);            System.out.println("内部的data3:"+ data3);            System.out.println("外部的data3:"+ Outer.data3);        }        public static void InnerStaticShow() {            //调用时会先加载Outer类,类加载的时候执行静态代码块            outerStaticMethod();        }    }    /*外部类的内部如何和内部类打交道*/    public static void callInner() {        System.out.println(Inner.data3);        //System.out.println(Inner.data4); //内部类的非静态成员属性无法直接访问        System.out.println(new Inner().data4);                Inner.InnerStaticShow();        new Inner().InnerShow();  //调用内部类非静态成员方法    }}public class Test {    /* 其他类访问静态内部类 */    public static void main(String[] args) {        //访问静态内部类的静态方法,Inner类被加载(类加载的时候执行静态代码块),此时外部类未被加载,独立存在,不依赖于外部类。        Outer.Inner.InnerStaticShow();        // 静态内部类实例化,不用(),相比于实例内部类优点:不需要外部类的引用        Outer.Inner in = new Outer.Inner();        in.InnerShow();    }}

总结:【抓住关键字——static,作为静态成员存在】

静态内部类可以包含任意的信息,可以被任意访问权限修饰符修饰。静态内部类的方法只能访问外部类的static关联的成员。静态内部类可以独立存在,不依赖于其他外围类。其他类访问内部类的静态信息,直接 Outer.Inner.static成员信息 就可以了。其他类实例化内部类 Outer.Inner instance = new Outer.Inner();,然后 instance. 成员信息(属性、方法)即可。

?局部内部类

?? Java局部内部类是指在一个方法或代码块内部定义的内部类。与成员内部类不同,局部内部类只能在定义它的方法或代码块内部使用,无法在外部访问。

public class Out {    /*属性和方法*/    private int outVariable = 1;    /*外部类定义的属性*/    private int commonVariable = 2;    /*静态的信息 */    private static int outStaticVariable = 3;    /*成员外部方法*/    public void outerMethod() {        System.out.println("我是外部类的outerMethod方法");    }    /*静态外部方法*/    public static void outerStaticMethod() {        System.out.println("我是外部类的outerStaticMethod静态方法");    }    /*成员方法,内部定义局部内部类*/    public void outerCreatMethod(int value) {        //public int a = 1; // 不行,局部内部类不能有访问权限修饰符        //static int a = 1; // 也不能有static 修饰        final int a = 1;        int a1 = 1; // 默认为final        /*女性*/        boolean sex = false;        //sex = true; // 有且仅有赋值一次        /*局部内部类,类前不能有访问修饰符*/        class In {            private int inVariable = 10;            private int commonVariable = 20;            /*局部内部类方法*/            public void InnerShow() {                System.out.println("innerVariable:" + inVariable);                //局部变量                System.out.println("是否男性:" + sex);                System.out.println("参数value:" + value);                //调用外部类的信息                System.out.println("outerVariable:" + outVariable);                System.out.println("内部的commonVariable:" + commonVariable);                System.out.println("外部的commonVariable:" + Out.this.commonVariable);                System.out.println("outerStaticVariable:" + outStaticVariable);                outerMethod();                outerStaticMethod();            }        }        //局部内部类只能在方法内使用        In in = new In();        in.InnerShow();    }    /* 开始程序 */    public static void main(String[] args) {        Out out = new Out();        out.outerCreatMethod(100);    }}

总结:【抓住关键——作用域,作为方法的局部成员存在】

局部内部类不能有访问权限修饰符,无法创建静态信息。                                                局部内部类就像是方法里面的一个局部变量一样,是不能有访问权限修饰符和static修饰符的。只能在方法内部使用。可以直接访问方法内的局部变量和参数。【存在限制,需要 final 或有效的final修饰的】,但是不能更改。 
①直接被final修饰的变量。
②已被赋值且始终未改变的变量(有且仅有赋值一次),引用指向不能改变。注:JDK8以前(不包括8)只能访问被final修饰的变量。编译器也有自己独立的字节码文件,命名格式:外部类名字$数字内部类名字.class

注:当局部内部类的变量修改时,就会产生如下错误:

Variable ‘xxx’ is accessed from within inner class, needs to be final or effectively final

传入局部内部类所在方法的参数同理,如果一直不变则可使用,反之则会报错。

局部内部类使用的很少,了解即可.

?‍?匿名内部类

 ?? Java匿名内部类是一种特殊的内部类,它没有类名,直接在创建对象时定义并实现。通常用于创建只需要使用一次的类对象,可以简化代码,提高代码的可读性和可维护性。

原本我们需要创建子类或实现类,去继承父类或实现接口,才能重写其中的方法。但是有时候我们这样做了,然而子类和实现类却只使用了一次(定义了一个对象)。这个时候我们就可以使用匿名内部类,不用去写子类和实现类,起到简化代码的作用。这样做,把子类继承父类,重写父类中的方法,创建子类对象,合成了一步完成,减少了其中创建子类的过程。或者实现类实现接口,重写接口中的方法,创建实现类对象,合成了一步完成,减少了其中创建实现类的过程。

?匿名内部类是不能有名字的类,他们不能被引用,只能在创建是用 new 语句来声明他们。

// 匿名内部类interface IA{    void test(); //接口的方法不能有具体实现}public class Test {    public static void main(String[] args) {        // 匿名内部类对象,下面两种方法都可以        /*new IA(){            @Override            public void test() {                System.out.println("重写了接口的方法");            }        };*/        IA a = new IA(){            @Override            public void test() {                System.out.println("重写了接口的方法");            }        };        a.test();    }}

总结:【匿名内部类通常继承一个类或实现一个接口】

匿名内部类没有访问权限修饰符。匿名内部类要实现父类或接口的所有抽象方法,其他方法可以根据自己的情况进行重写。匿名内部类不应当添加自己的成员,因为匿名类没有类名无法向下转型,父类型的引用无法访问。匿名内部类访问方法参数时也有和局部内部类同样的限制。匿名内部类没有构造方法。匿名类是表达式形式定义的,所以末尾以分号;来结束。


?总结

具体来说,内部类信息(属性、方法)可以和外部类重名;内部类是具有类的基本特征的独立实体;可以利用访问修饰符隐藏内部类的实施细节,提供了更好的封装;静态内部类使用时可直接使用,不需先创造外部类。

? ? ?那么本篇到此就结束,希望我的这篇博客可以给你提供有益的参考和启示,感谢大家支持!!!祝大家天天开心

 


点击全文阅读


本文链接:http://zhangshiyu.com/post/156026.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1