【Java】【重要特性】详解内部类

举报
huahua.Dr 发表于 2022/09/28 23:56:48 2022/09/28
【摘要】 一、什么内部类在一个类中定义另外一个类内部,称之为内部类,作用范围可以在类成员中、类方法中,所以存在两种:成员内部类和方法内部类二、为什么使用内部类?使用内部类最吸引人的原因是:(1)能够非常好的解决多重继承的问题,(2)每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现, 对于内部类都没有影响三、使用内部类的特点(1)内部类可以用多个实例,每个实例都...

一、什么是内部类

在一个类中定义另外一个类内部,称之为内部类,作用范围可以在类成员中、类方法中,所以存在两种:成员内部类和方法内部类

二、为什么使用内部类?

使用内部类最吸引人的原因是:

(1)能够非常好的解决多重继承的问题,

(2)每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现, 对于内部类都没有影响

三、使用内部类的特点

(1)内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。

(2)在单个外部类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。

(3)创建内部类对象的时刻并不依赖于外部类对象的创建。

(4)内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。

(5)内部类提供了更好的封装,除了该外部类,其他类都不能访问。

四、内部类分类

(1)成员内部类:属于外部类的一个成员属性

public class Outer{

        private int age = 99;

        String name = "Coco";

        public class Inner{

            String name = "Jayden";

            public void show(){

                System.out.println(Outer.this.name);

                System.out.println(name);

                System.out.println(age);

            }

        }

        public Inner getInnerClass(){

            return new Inner();

        }

        public static void main(String[] args){

            Outer o = new Outer();

            Inner in = o.new Inner();

            in.show();

        }

    }

1)Inner 类定义在 Outer 类的内部,相当于 Outer 类的一个成员变量的位置,Inner 类可以使用任意访问控制符,如 public 、 protected 、 private 等

2)Inner 类中定义的 show() 方法可以直接访问 Outer 类中的数据,而不受访问控制符的影响,如直接访问 Outer 类中的私有属性age

3)定义了成员内部类后,必须使用外部类对象来创建内部类对象,而不能直接去 new 一个内部类对象,即:内部类 对象名 = 外部类对象.new 内部类( );

4)编译上面的程序后,会发现产生了两个 .class 文件: Outer.class,Outer$Inner.class{}

5)成员内部类中不能存在任何 static 的变量和方法,可以定义常量,原因有两点:

  • 因为非静态内部类是要依赖于外部类的实例,而静态变量和方法是不依赖于对象的,仅与类相关,简而言之:在加载静态域时,根本没有外部类,所在在非静态内部类中不能定义静态域或方法,编译不通过;非静态内部类的作用域是实例级别
  • 常量是在编译器就确定的,放到所谓的常量池了

6)外部类是不能直接使用内部类的成员和方法的,可先创建内部类的对象,然后通过内部类的对象来访问其成员变量和方法;

7)如果外部类和内部类具有相同的成员变量或方法,内部类默认访问自己的成员变量或方法,如果要访问外部类的成员变量,可以使用 this 关键字如:Outer.this.name

(2)静态内部类: 是 static 修饰的内部类

public class Outer{

            private int age = 99;

            static String name = "Coco";

            public static class Inner{

                String name = "Jayden";

                public void show(){

                    System.out.println(Outer.name);

                    System.out.println(name);                  

                }

            }

            public static void main(String[] args){

                Inner i = new Inner();

                i.show();

            }

        }

1)静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问

2)如果外部类的静态成员与内部类的成员名称相同,可通过“类名.静态成员”访问外部类的静态成员;

3)如果外部类的静态成员与内部类的成员名称不相同,则可通过“成员名”直接调用外部类的静态成员

4)创建静态内部类的对象时,不需要外部类的对象,可以直接创建 内部类 对象名 = new 内部类();

(3)方法内部类:其作用域仅限于方法内,方法外部无法访问该内部类


        public class Outer{

            public void Show(){

                final int a = 25;

                int b = 13;

                class Inner{

                    int c = 2;

                    public void print(){

                        System.out.println("访问外部类:" + a);

                        System.out.println("访问内部类:" + c);

                    }

                }

                Inner i = new Inner();

                i.print();

            }

            public static void main(String[] args){

                Outer o = new Outer();

                o.show();

            }

        }    

1)局部内部类就像是方法里面的一个局部变量一样,是不能有 public、protected、private 以及 static 修饰符的

2)只能访问方法中定义的 final 类型的局部变量,因为:

  • 当方法被调用运行完毕之后,局部变量就已消亡了。但内部类对象可能还存在,直到没有被引用时才会消亡。这就无法使用非final局部变量了,使用final修饰符不仅会保持对象的引用不会改变,而且编译器还会持续维护这个对象在回调方法中的生命周期.
  • 局部内部类并不是直接调用方法传进来的参数,而是内部类将传进来的参数通过自己的构造器备份到了自己的内部,自己内部的方法调用的实际是自己的属性而不是外部类方法的参数;这样可以防止被篡改数据,而导致内部类得到的值不一致

 3)在JDK8版本之中,方法内部类中调用方法中的局部变量,可以不需要修饰为 final,匿名内部类也是一样的,主要是JDK8之后增加了 Effectively final 功能 ,反编译jdk8编译之后的class文件,发现内部类引用外部的局部变量都是 final 修饰的

(4)匿名内部类: 没有名字的内部类

public class OuterClass {

            public InnerClass getInnerClass(final int   num,String str2){

                return new InnerClass(){

                    int number = num + 3;

                    public int getNumber(){

                        return number;

                    }

                };        /* 注意:分号不能省 */

            }

            public static void main(String[] args) {

                OuterClass out = new OuterClass();

                InnerClass inner = out.getInnerClass(2, "chenssy");

                System.out.println(inner.getNumber());

            }

        }

        interface InnerClass {

            int getNumber();

        }     

1)匿名内部类是直接使用 new 来生成一个对象的引用;

2)对于匿名内部类的使用它是存在一个缺陷的,就是它仅能被使用一次,创建匿名内部类时它会立即创建一个该类的实例,该类的定义会立即消失,所以匿名内部类是不能够被重复使用;

3)使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口;

4)匿名内部类中是不能定义构造函数的,匿名内部类中不能存在任何的静态成员变量和静态方法;

5)匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法

6)匿名内部类初始化:使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。