我们都知道,java说白了就是由一个一个类组成的,但是java的类又可以相互嵌套,甚至一个.java文件中最外层可以并行的定义多个类,这些类的关系是什么呢?
今天就来捋顺一下。
java中的类无非就是放在.java文件中,然后进过编译后生成.class文件。我们先来看下.java文件中有一个类的情况,这种情况比较好理解。
我们定义一个TextA的类,在java文件中它是这样存放的(如下图),同时.java文件名需要与TextA同名。
好了,这是我们最熟悉的一种情况。如果我们想在这个.java文件中包含多个类怎么办呢?
我们先来分析下,如果再加其他类,它可以放在什么位置,我总结了一共有三个位置,如图的位置1-3.
为了便于理解,我们主要从以下三个角度来分析,类放在这几个位置的不同:
问题1.可以用什么修饰符,即类名前边可以加public、private、protected,static中的那几个?
问题2.这些位置的类对外部类的访问权限是什么?是都可以访问,还是只能访问外部类的静态成员和方法?
问题3.在这些类中可不可以设置静态成员和静态方法?
好了,干货来了。
对于位置1:
问题1.可以用什么修饰符,即类名前边可以加public、private、protected,static中的那几个?
一个.java文件中,最外层的类最多只能有一个public的类,可以令其作为入口类执行(重写main方法)且.java文件名称需要与被public修饰的类相同。如果一个.java文件中的class都没有public修饰,那这个.java文件的类名就可以随便定义了。其他类不可以加任何其他修饰符。除这点区别之外,这些最外层的类在使用上没有任何其他区别,如果这个.java文件中有多个位置1的最外层类,经过编译之后,每个类都可以单独的生成.class文件,所以区别仅在编译之前。除了public之外,private、protected,static都不可以加。
问题2.这些位置的类对外部类的访问权限是什么?是都可以访问,还是只能访问外部类的静态成员和方法?
访问权限与两个独立的类互相访问相同。
问题3.在这些类中可不可以设置静态成员和静态方法?
静态成员和静态方法的设置与单独写一个.java,然后设置静态成员和静态方法相同。
总结一句话,位置1中放入的类,对这个程序的影响,仅仅在编译之前,编译之后,无区别。
对于位置2:
问题1.可以用什么修饰符,即类名前边可以加public、private、protected,static中的那几个?
位置2实际上是成员变量和方法并行放置的位置,所以这里定义的类具有与成员变量、成员方法相同的特性,可以用public、private、protected,static中的任何一个修饰。
通过加不加static进行分类,不加static时 ,为非静态成员内部类 ,加static为静态成员内部类
关于他们的区别,我们可以利用普通成员变量和静态成员变量的区别来理解。
非静态成员内部类:
在TextA内部定义时,无论用public、private、protected哪种修饰符修饰,都能通过外部类的对象new出来
在TextA外部定义时,用public修饰符修饰能通过外部类的对象或者其子类对象new出来;用private修饰符修饰能不能通过外部类的对象new出来;用protected修饰符修饰,在包内能通过外部类的对象new出来,在包外不能访问。
静态成员内部类:
在TextA内部定义时,无论用public、private、protected哪种修饰符修饰,都能直接使用
在TextA外部定义时,用public修饰符修饰能能直接使用,也通过外部类点出来;用private修饰符修饰不能直接使用,也不能通过外部类点出来;用protected修饰符修饰在包内能直接使用,也能通过外部类点出来,包外无法访问。
问题2.这些位置的类对外部类的访问权限是什么?是都可以访问,还是只能访问外部类的静态成员和方法?
非静态成员内部类:
对外部类的访问没有限制。
静态成员内部类:
可以访问外部类的静态成员和静态方法。PS:道理就如同静态方法内部只能调用静态方法,使用静态变量一样。
问题3:在这些类中可不可以设置静态成员和静态方法?
非静态成员内部类:
不可以,因为内部类必须在外部类加载之后才能加载,而设成静态的,就能在编译后直接加载了,与前边的加载顺序冲突。
静态成员内部类:
可以,因为类设置成了静态的,所以可以单独加载。设置静态成员和静态方法,不影响。
对于位置三:可以把这里面定义的类理解为局部变量,我们暂且叫它局部内部类
问题1.可以用什么修饰符,即类名前边可以加public、private、protected,static中的那几个?
局部变量是不能用public、private、protected,static修饰的,public、private、protected,static只能用来修饰成员变量和成员方法,所以这个问题可以不用考虑了。
问题2.这些位置的类对外部类的访问权限是什么?是都可以访问,还是只能访问外部类的静态成员和方法?
还是把它作为局部变量来理解,它只能访问局部变量,和非静态的静态成员和方法。
PS:如果这个方法是静态的,那么就都可以访问了外部类的静态成员和方法。
问题3:在这些类中可不可以设置静态成员和静态方法?
不可以,还是通过局部变量来理解,方法中存放的都是局部变量,不管方法是不是static的,局部变量都不可以被static修饰,因为static是在类加载的时候,提前分配内存的到方法区的,而这个方法中局部变量的是放在栈区的,这本身就与java的内存配置矛盾了。
不知不觉,我们已经讨论了四种类的用法:与原类并行的类、非静态成员内部类、静态成员内部类、局部内部类(都是非静态的)。
然而还不够完美,还有一种类,不能用位置去限定它来划分种类,它就是匿名内部类:
我们先来捋一下什么交匿名内部类,顾名思义,就是没有名字的类,没有名字的类我们怎么使用呢?这里就必须要明确一点了,匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类,或实现一个接口。然后重写接口或者父类的方法,用父类引用或者接口引用指向他。因为没有名字,他只能被定义好后,被接收它的那个对象使用,之后再也不能通过它来new其他的对象了,一般用在多线程里面,来new多线程。
下面依次回答上边的问题:
问题1.可以用什么修饰符,即类名前边可以加public、private、protected,static中的那几个?
因为匿名内部类不能单独的存在,无法修饰,只能修饰接收匿名内部类的对象。
问题2.这些位置的类对外部类的访问权限是什么?是都可以访问,还是只能访问外部类的静态成员和方法?
可以随便访问,但是访问局部变量时,局部变量必须加final关键字。愿意如下:
是变量的作用域的问题,因为匿名内部类是出现在一个方法的内部的,如果它要访问这个方法的参数或者方法中定义的变量,则这些参数和变量必须被修饰为final。因为虽然匿名内部类在方法的内部,但实际编译的时候,内部类编译成Outer.Inner,这说明内部类所处的位置和外部类中的方法处在同一个等级上,外部类中的方法中的变量或参数只是方法的局部变量,这些变量或参数的作用域只在这个方法内部有效。因为编译的时候内部类和方法在同一级别上,所以方法中的变量或参数只有为final,内部类才可以引用。
问题3:在这些类中可不可以设置静态成员和静态方法?
不可以,还是加载顺序的问题,非静态内部类必须等外部类加载完毕后才能加载(为什么?因为内部类要用外部类的数据),如果可以设静态成员和静态方法就能单独加载了,会打破这种限制。