Java内部类的定义与使用

1. 内部类是什么?为什么存在内部类?

  将一个类放到另一个类 内部嵌套操作,这个类就称为内部类。
  大家可能和我有同样的疑问,为什么要有内部类的产生呢?经过时代的发展,我们都会发现,每一样的新东西的出现,都是是我们的操作更加便利,所以,我们在不看任何的资料前提下,就可以菜刀,内部类的产生是为了某种操作的便利。
  下面我们将看一段代码来分析,使用内部类和不使用内部类实现相同功能代码的优缺点。

1.1 不使用内部类
// 没有采用内部类
class Outter{
    private String msg = "Outter中的字符串";
    public String getMsg(){
        return this.msg;
    }
    public void test(){//2
        //生产内部类对象
        Inner in = new Inner(this);//3
        in.fun();//5
    }
}
class Inner{
    private String inMsg = "Inner中的字符串";
    private Outter out;
    //构造注入
    public Inner(Outter out){//3
        this.out = out; //4 为Inner中的out变量初始化
    }
    public void fun(){//6
        //直接调用外部类的私有属性
        System.out.println(out.getMsg());//7
    }
}
public class Test{
    public static void main(String[] args){
        Outter out = new Outter();//1
        out.test();//2
    }
}

  通过分析代码可以知道,我们创建Outter类的对象out,然后调用out类的对象调用了test()方法,我们进入到test()方法中会发现它里面通过构造注入将该对象传入到Inner类中创建in对象,然后in对象调用了fun()方法,fun()方法又调用了通过out对象调用了getMsg()方法才打印了out方法的msg属性。在几次折腾下终于成功的调用了此方法。
  分析到这里我们就会想到,我们其实事项访问Outter类的私有属性,那么我们会想到一个身体上的实例,心脏是在人身体内部工作的,血液可以在心脏内部进行流动,那么我们把Outter类看作是身体,把Inner类看作为心脏会有什么效果产生呢?

1.2 使用内部类
// 采用了内部类
class Outter{
    private String msg = "Outter中的字符串";
    //-------------------------------------
    //内部类
    class Inner{
        private String inMsg = "Inner中的字符串";
        public void fun(){
            // 发现内部类可以直接调用外部类的私有属性
            System.out.println(msg);
        }
    }
    //-------------------------------------
    //在外部类中定义一个方法,该方法负责产生内部类对象,并调用fun()方法
    public void test(){
        // 生产内部类对象
        // 与之前不使用内部类不同的是,不用通过构造注入的方法将当前的out对象传入Inner类就可以实现直接调用out对象的属性及方法
        Inner in = new Inner();
        in.fun();
    }
}
public class Test{
    public static void main(String[] args){
        Outter out = new Outter();
        out.test();
    }
}

  我们可以发现两种代码实现相同的功能,不适用内部类的代码比较难以分析,调来调去,还需要构造注入外部对象才可以访问其public权限的属性和方法,但是内部类就比较简洁,最根本的原因是内部类可以直接访问外部类的私有属性。
  如果你想不明白的话,可以想像,有一间房为Outter,它里面的厕所对外部人员不可见,但是你身处在房子里面为Inner,这个厕所你就可以进去操作。这种的就可以看作是封装,内部操作对外部而言不可见,实现封装;内部类可以直接访问外部类的私有属性。

2. 内部类实现多继承

Java的单继承局限:只能继承一个类,但可以实现多个接口。 如果我要打破这个局限,除了使用多层继承之外,还可以使用内部类进行操作。

// 内部类实现多继承
class A
{
    private String name="A类私有域";
    public String Getname(){
        return name;
    }
}
class B
{
    private int age=18;
    public int Getage(){
        return age;
    }
}

class C
{
    //ExtendA 继承A
    class ExtendA extends A{
        public String Name()
        {
            return new A().Getname();  // 返回父类A的属性name
        }
    }
    // ExtendB 继承B
    class ExtendB extends B{
        public int Age(){
            return new B().Getage();//返回父类B的属性年龄
        }
    }
    public String name(){
        return new ExtendA().Name();  //返回内部类的Name,相当于A的name
    }
    public int age(){
        return new ExtendB().Age(); //返回内部类的Age,相当于B的age
    }
    //C类现在既有A的属性name,也有B的属性age,模拟实现了多继承
}
public class Test{
    public static void main(String[] args)
    {
        C c=new C();
        System.out.println(c.name()); // A类的私有域
        System.out.println(c.age());  //18
    }
}

3. 内部类的优缺点

优点:

  • 内部类和外部类可以方便的访问彼此的私有域(包括私有方法、私有属性)。
  • 内部类是另外一种封装(保护性),对外部的其他类隐藏 —>例如:心脏包在人体内部
  • 内部类可以实现Java单继承的局限

缺点: 结构较为复杂,破坏了类的结构性。

4.内部类与外部类的关系

  • 对于非静态内部类,内部类的创建需要依赖外部类对象,在没有外部类实例之前无法创建非静态内部类。
  • 内部类是一个相对独立的个体,与外部类没有is-a关系
  • 内部类可以直接访问外部类的元素(包含私有域),但是外部类不可以直接访问内部类元素,需要通过内部类的引用间接访问。

5. 创建内部类

5.1 在外部类内部创建内部类语法
外部类.内部类 内部类引用 = new 外部类().new 内部类();

Outter.Inner in = new Outter().new Inner();
5.2 在外部类内部创建内部类语法

在外部类内创建内部类,就像普通对象一样直接创建。

Inner in = new Inner();

6. 内部类的分类

在Java中内部类主要分为成员内部类静态内部类方法内部类匿名内部类

6.1成员内部类

成员内部类同成员方法一样。
注意:

  • 成员内部类不能存在任何static变量或方法,可以访问外部类的静态域。
  • 成员内部类是依附外部类的,所以只有先创建了外部类才能创建内部类。
    举例:
class Outter{
    private String name = "test";
    private int age = 20;
    class Inner{
        //成员内部类内部不允许出现静态变量,它类似于成员方法,
        //而静态变量的生命周期与类相同,不需要创建实例便可引用,
        //但成员方法必须先创建实例才可使用
        // private static int num = 50;    //本行代码错误
        public void fun(){
            System.out.println(name);
            System.out.println(age);
        }
    }
}

在这里插入图片描述

6.2 静态内部类

  关键字static可以修饰成员变量、方法、代码块,其实它还可以修饰内部类。使用static修饰的内部类,称为静态内部类。
静态内部类与非静态内部类的区别: 非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围,但是静态内部类没有。因为没有这个引用,所以隐含着下面两条信息。
重点:

  • 静态内部类的创建不需要依赖外部类,可以直接创建。
  • 静态内部类不可以使用任何外部类的非static域(包含属性与方法),但可以存在自己的成员变量。
    静态内部类的创建语法:
外部类.内部类 内部类对象 = new 外部类.内部类();

Outter.Inner in = new Outter.Inner();

举例:

class Outter{
    private String name = "test";
    private int age = 20;
    static class Inner{
        public void fun(){
            //下面两句话均错误,静态内部类类似于静态方法,它的声明周期类似于一个类
            //静态方法不需要实例化对象,便可通过类名引用,
            //但成员变量必须实例化对象后,通过对象才可引用。
            System.out.println(name);
            System.out.println(age);
        }
    }
}

在这里插入图片描述

6.3 方法内部类

  方法内部类定义在外部类的方法中,局部内部类和成员内部类基本一致,只是它们的作用域不同,方法内部类只能在该方法中被使用,出了该方法就会失效。 对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类。

  • 方法内部类不允许访问权限修饰符public、private、protected均不允许。
class Outter{
    private int num = 5;
    public void display(int temp){
        //方法内部类:方法内部定义的
        //下面这行代码(关于方法内部类的定义):方法内部类不能使用任何的访问修饰权限
        public class Inner{

        }
    }
}

在这里插入图片描述

  • 方法内部类对外部完全隐藏,除了创建这个类的方法可以访问它以外,其他地方均不能访问。
  • 方法内部类如果想要使用方法形参,该形参必须使用final声明(JDK8将形参变为隐式final声明)。
class Outter{
    private int num = 5;
    //方法内部类如果想要使用方法形参,该形参必须使用final声明
    //(JDK8将形参变为隐式final声明)。
    public void display(int temp){
        //方法内部类:方法内部定义的
        class Inner{
            public void fun(){
                System.out.println("外部类中的程序变量:" + num);
                System.out.println("方法的形参:" + temp);
            }
        }
        //使用方法内部类:只能在方法内部,外部根本不知道方法内部存在一个类
        new Inner().fun();
    }
}
//测试
public class Test{
    public static void main(String[] args){
        Outter out = new Outter();
        out.display(18);
    }
}

在这里插入图片描述
如何判断方法的形参为final声明的?—> final被称为终结器,修饰的变量为常量,不能修改。

class Outter{
    private int num = 5;
    public void display(int temp){
        //方法内部类:方法内部定义的
        class Inner{
            public void fun(){
                temp++;
                System.out.println("外部类中的程序变量:" + num);
                System.out.println("方法的形参:" + temp);
            }
        }
        //使用方法内部类:只能在方法内部,外部根本不知道方法内部存在一个类
        new Inner().fun();
    }
}
public class Test{
    public static void main(String[] args){
        Outter out = new Outter();
        out.display(18);
    }
}

在这里插入图片描述

6.4 匿名内部类

匿名内部类其实就是一个没有名字的方法内部类。因此特点与方法内部类完全一样,除此之外,还有两个自己的特点。

  • 匿名内部类必须继承一个抽象类或者实现一个接口。
  • 匿名内部类没有构造方法(因为没有类名)
//声明定义一个接口
interface MyInterface{
    void test();
}

class Outter{
    private int num = 5;

    public void display(int temp){
        //匿名内部类,匿名的实现了MyInterface接口
        new MyInterface(){
            public void test(){
                System.out.println("匿名内部类实现了MyInterface接口");
                System.out.println(temp);
            }
        }.test();
    }
}
public class Test{
    public static void main(String[] args){
        Outter out = new Outter();
        out.display(18);
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值