java-面向对象编程-内部类

一、概述:
今天要介绍的是一个在面向对象编程中比较烧脑的一个知识点,叫做内部类。意思就是在一个类的内部再重新定义一个新的类,作为外部类的一个属性而存在。那么,我们常说:存在即合理,那么,既然有内部类的存在,就必定会有内部类存在的理由,也就是我们为什么要使用内部类。再这里,我们需要澄清的一点是:
在我们说到继承的时候,其实有一个注意点并没有说,就是java中的继承机制不支持多重继承。什么意思呢?就好比你只有一个父亲,那么当你继承了你父亲的财产之后,自然就不能继承其他人的财产了。当然,如果你父亲本身就已经继承了更上一辈及财产的话,那么也就相当于你也继承了上一辈的财产。只是从形式上而言,你只是继承了一个父类,也就是我们常说的单继承机制。这样的机制能够有效防止多重继承带来的二义性及钻石型问题。但缺点也就是不能重复继承多个基类,使得程序的可拓展性降低。比如:你想定义一个人,他既是一个程序员,也是一个厨师。那么对于多继承来说,只需要创建一个类,同时继承程序员类和厨师类即可。但因为java不支持多进程,所以他只能通过其他的办法去实现这个需求。常见的几个方法是:

1.利用接口:

2.利用内部类:

3.多次单继承(不推荐)

4.其他

而今天要讲的,就是这个内部类。关于内部类的特性,《Think in java》中对其进行了归纳:

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

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

  3、创建内部类对象的时刻并不依赖于外围类对象的创建

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

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

我们前面说到,内部类可以看做是作为外部类的一个属性存在,也就是说内部类可以访问外部类中定义的变量。但例外在与,当内部类定义为static,即静态类型时,不能访问外部类中的非static成员,关于这个问题的原因会在以后的介绍中进行介绍。同时,我们需要知道的是,我们的内部类是写在外部类中的,但在编译时,就会将其分开,内部类的命名方式为:外部类名字$内部类名字.class。而使用内部类的典型情景为:

内部类继承自某个类或实现某个接口,内部类的代码操作创建其的外围类的对象。所以你可以认为内部类向外部类提供了某种进入其外围类的窗口。

二、内部类的分类(重点)

内部类的实现方式大致分为四类,分别是:成员内部类、局部内部类,静态内部类,以及匿名内部类。下面是关于这四种类型的详细介绍:

1.成员内部类

成员内部类是最普通的内部类,依赖于外部类对象而存在,充当的是外部类中一个成员变量的角色。所以它可以无限制的访问外围类的所有成员属性和方法,但是当外部类要访问内部类的成员属性和方法时,则需要通过内部类实例来访问。
在成员内部类中要注意两点:

第一:成员内部类中不能存在任何static的变量和方法;
第二:成员内部类是依附于外部类的,所以只有先创建了外部类才能够创建内部类。

例子如下:

//成员内部类demo代码
class OutClass {

     class InnerClass {

      }
 }

//调用成员内部类的方式
   OutClass outclass = new OutClass();
   outclass.InnerClass innerclass = OutClass.new InnerClass();

2.局部内部类

顾名思义,局部内部类是指局限于一定代码块中的内部类,包括方法、构造方法、局部块或静态初始化块等也就是说,在外部类的一个方法体中定义的内部类就叫做局部外部类。它与成员内部类相比,最大的区别在于:成员内部类作为外部类的成员存在,而局部内部类作为外部类的某一成员的元素而存在。注意的是:局部内部类中不可定义静态变量,但可以访问外部类的局部变量(即方法内的变量),但是这个变量必须是被final关键字所定义的。而关于final关键字的描述,我们会在以后进行介绍。而如果外部类与局部类中存在共同的元素名时,若要在内部类中调用外部类的元素,这需使用外部类.this.元素名的方式进行调用

关于局部类的例子如下:

public class InnerClassTest {   
 //外部类成员变量
private String outClass_member_var = "outClass_member_var"; 
//外部类中与内部类存在的相同的元素名
private int sameName_var = 24; 

 public void show(){   
    //final 关键字修饰的数据,局部常量
    final int local_var = 54;   
    /**
    局部内部类
    /*
    class InnerClass{      
    //内部类中与外部类存在的相同的元素名
        int sameName_var = 12;   

    //注意!: 内部类中不能定义static变量. ,比如:static String s = "name";  

        /**
        测试方法
        /*
        public void printTest(){   
            System.out.println("局部常量local_var的值为: "+local_var);   
            System.out.println("外部类成员变量outClass_member_var的值: "+outClass_member_var);   
            System.out.println("外部类中与内部类同名的成员变量sameName_var的值: "+InnerClassA.this.sameName_var);   
            System.out.println("内部类中与外部类同名的成员变量sameName_var的值: "+sameName_var;   
        }   
    }   
    new InnerClass().printTest();   
 }   

    public static void main(String[] args) {   
     InnerClassTest test = new InnerClassTest();   
    test.show();   
    }   
}  

3.静态内部类:
静态内部类是指用static关键字修饰的内部类,关于static关键字的作用有很多,以后会另开章节进行介绍。
在这章里,只需知道static是代表“静态的”的意思。意味着被static关键字所修饰的变量,方法或者其他形式的数据会在类加载时首先被加载到jvm中。并且在以后的程序中都不会再次加载进去。这就指出了静态内部类的一大特点:静态内部类只能使用外部类中被static修饰的元素,而不能使用不被static修饰的元素。为什么呢?试想:我们的静态内部类是会在外部类准备加载的时候就已经被加载至jvm中了,而在这个时候,外部类中其他未被static修饰的元素都还没进行初始化呢。在这种情况下,又怎么能够被已经加载的内部类所使用呢?这里就涉及了一个普遍适用的原则:静态的只能访问静态的,因为它们在对象没创建前就存在了。 而基于这个原因,我们也可以得出静态内部类的另一个特色:静态内部类是不依赖于外部类而存在的。什么意思呢?即外部类与静态内部类之间并不存在过强的依赖关系,表现为当我们需要使用静态内部类时,不需要像成员内部类那般先经过初始化外部类对象,再通过外部类对象来初始化内部类对象,而是直接通过以下方式获得:

OutClass.InnerClass inner = new OutClass.InnerClass();

那么,既然静态内部类不依赖于外部类而存在,为什么我们不直接把它独立出来,形成一个普通的非静态内部类呢?这个问题其实已经有人做出了回答:这里不再多说,传送门打开:
Vange: JAVA 内部静态类–解析静态内部类的使用目的与限制

4.匿名内部类:
内部类已经是很是烧脑的部分了,而匿名内部类则是烧脑中的烧脑。需要反复去斟酌。从名字我们可以知道,所谓匿名内部类,就是一种没有类名的内部类,它既不使用关键字class,extends,implements,也不存在构造方法,但它又必须继承其他类或者其他接口才能实现。在这里可能会让人晕掉了。既不能用关键字,又必须进行继承。这都是些什么玩意!别怕,我们接下来就详细讲述匿名内部类的语法,基本如下(以继承一个父类为例):

new 父类构造方法{
    所需要实现的代码块
};

例子:

    new Person(){
        void eat();
    }

你看,在这里,我们发现,我们并没有创建出一个实名的对象去初始化类,同时相比传统的“new一个对象”的操作而言,代码更为简洁,紧凑。但带来的问题也不少,主要表现在可读性下降,对于新手而言,或许连什么是匿名
内部类都不清楚。为此,准备了两道有人在csdn上问过的题目可供理解:

问题1:
匿名内部类继承类的同时可以实现接口吗?

问题2:
关于java中匿名内部类的问题

至此。java-面向对象编程-内部类一章结束。如对博文有疑问,请在下方评论区指出,以便查证修改。我们下一章的内容是:java-面向对象编程-接口。敬请期待~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值