引言
大部分时候,类被定义为一个独立的单元。在某些时候,也会把一个类放在另一个类的内部定义,这个定义在其他类内部的类就被称为内部类(有的地方也叫嵌套类),包含内部类的类也被称为外部类(有的地方也叫宿主类〉。
Java从JDK1.1开始引入内部类,内部类主要有如下作用:
内部类提供更好地封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问。
内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员,同一个类的成员之间可以互相访问。但外部类不能访问内部类的实现细节,例如内部类的成员变量。
定义内部类的方法:
从语法角度来看,定义内部类与定义外部类的语法大致相同,内部类除了需要定义在其他类里面之外,还存在如下两点区别:内部类比外部类可以多使用三个修饰符:private、protected、static一一外部类不可以使用这三个修饰符。
- 非静态内部类不能拥有静态成员。
- 在编译完之后,会出现(外部类.class)和(外部类$内部类.class)两个类文件名。
- 内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量
内部类的分类
java内部类分为: 成员内部类、静态嵌套类、方法内部类、匿名内部类 。
成员内部类
成员内部类可以等同于外部类的成员变量。
class Outer {
class Inner{}
}
//编译上述代码会产生两个文件:Outer.class和Outer$Inner.class
成员内部类的特点如下:
- 可以用访问控制权限的修饰符修饰,public,protected,private,缺省(默认,default)。
- 不能在成员内部类里面声明静态方法和静态变量。
- 如果内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量
代码实例
public class _01_OuterClass{
//静态变量
private static String s1 = "A";
//成员变量
private String s2 = "B";
//静态方法
private static void m1(){
System.out.println("static's m1 method execute!");
}
//成员方法
private void m2(){
System.out.println("m2 method execute!");
}
//成员内部类
class InnerClass{
//静态变量
//static int i = 9999;
//静态方法
//public static void m3(){}
//成员方法
public void m4(){
System.out.println(s1);
m1();
System.out.println(s2);
m2();
}
}
//相当于: InnerClass ...
//入口
public static void main(String[] args){
//创建外部类对象
_01_OuterClass oc = new _01_OuterClass();
//怎么访问一个成员内部类
//外部类对象的引用名.new 内部对象
InnerClass inner = oc.new InnerClass();
inner.m4();
}
}
方法内部类 (局部内部类)
顾名思义,就是把类放在方法里。
class Outer {
public void doSomething(){
class Inner{
public void seeOuter(){
}
}
}
}
方法内部类的特点如下:
- 局部内部类不能用访问控制权限修饰符修饰。
- 能访问外部方法的局部变量,但是局部变量必须用final修饰 , java8以后,可以不写final修饰。
- 局部内部类中,不能声明静态变量和静态方法,只能声明成员变量和成员方法。
- 如果外部方法是静态方法,那内部类中就不能访问外部类的成员变量和成员方法。
- 局部内部类等同于局部变量。
代码实例
public class _03_OuterClass{
int i1 = 222;
static int i2 = 255;
//方法
//-------------------------成员方法里面的内部类测试------------
public void m1(){//成员方法
//局部变量
final int i = 10;//java8以后,局部内部类访问方法的局部变量,可以不加final修饰
//局部内部类
class InnerClass{
//局部内部类不能有静态声明
//public static void m1(){}
//成员方法
public void m2(){
System.out.println(i); // 10 访问局部变量
System.out.println( i1 );//访问外类的成员变量
System.out.println( i2 );//访问外类的静态变量
}
}
//调用m2
InnerClass inner = new InnerClass();
inner.m2();
}
//-----------------------------静态方法里面的内部类测试--------
public static void m11(){//静态方法
//局部变量
final int i = 10;//java8以后,局部内部类访问方法的局部变量,可以不加final修饰
//局部内部类;
//局部内部类不能用访问控制权限修饰符修饰。
//局部内部类
class InnerClass{
//局部内部类不能有静态声明
//public static void m1(){}
//成员方法
public void m22(){
System.out.println(i); // 10 访问局部变量
// System.out.println( i1 );//访问外类的成员变量
System.out.println( i2 );//访问外类的静态变量
}
}
//调用m2
InnerClass inner = new InnerClass();
inner.m22();
}
//入口
public static void main(String[] args){
_03_OuterClass oc = new _03_OuterClass();
oc.m1();
oc.m11();
}
}
另一个简洁示例:
class Outer {
public void doSomething(){
final int a =10;
class Inner{
public void seeOuter(){
System.out.println(a);
}
}
Inner in = new Inner();
in.seeOuter();
}
//入口
public static void main(String[] args) {
Outer out = new Outer();
out.doSomething();
}
}
匿名内部类
顾名思义,没有名字的内部类。表面上看起来它们似乎有名字,实际那不是它们的名字。在方法调用时,方法需要传入某个类对应的对象实参,但是也可以直接new一个某个类型的一个对象,这个对象没有名字。
匿名内部类的特点如下:
- 没有构造方法(因为匿名内部类是没有类名的)。
- 不能定义任何变量(静态,成员),不能定义任何方法(静态,成员),不能定义任何类。
- 匿名内部类不能使public,protected,private,static。
- 只能创建匿名内部类的一个实例。
- 匿名类和内部类中的中的this : 有时候,我们会用到一些内部类和匿名类。当在匿名类中用this时,这个this则指的是匿名类或内部类本身。这时如果我们要使用外部类的方法和变量的话,则应该加上外部类的类名。
- 匿名内部类能访问外部的静态变量和静态方法,私有的也能,但是不能访问成员变量和成员方法。
- 一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
继承式的匿名内部类
public class Car {
public void drive(){
System.out.println("Driving a car!");
}
//入口
public static void main(String[] args) {
Car car = new Car(){ //匿名内部类,Car的匿名子类
public void drive() {
System.out.println("Driving another car!");
}
};
car.drive();
}
}
结果输出的是:Driving another car!
car是Car匿名子类的对象
接口式的匿名内部类
interface Vehicle {
public void drive();
}
class Test{
public static void main(String[] args) {
Vehicle v = new Vehicle(){
public void drive(){
System.out.println("Driving a car!");
}
}; //使用匿名内部类的特点,大括号后有分号作为结尾
v.drive();
}
}//接口式的匿名内部类是实现了一个接口的匿名类,而且只能实现一个接口。
参数式的匿名内部类
class Bar{
void doStuff(Foo f){
f.foo();
}
}
interface Foo{
void foo();
}
class Test{
static void go(){
Bar b = new Bar();
b.doStuff(new Foo(){
public void foo(){
System.out.println("foofy");
}
});
}
}
静态嵌套类
可以等同看做静态变量,可以访问外部类的静态变量和静态方法,但是不能直接访问外部类的成员变量和成员方法(要有对象引用,如同main(),也是静态的,有引用,就什么都能调用),并且,能声明任意变量和任意方法。
静态前套类的特点:
- 可以用访问控制权限的修饰符修饰
- 内部可以声明静态变量和成员变量,静态方法和成员方法
- 可以访问外部的静态变量和静态方法,不能直接访问成员变量和成员方法(需要有对象引用)
- 在静态方法中定义的内部类也是静态内部类
class Outer{
static class Inner{}
}
class Test {
public static void main(String[] args){
Outer.Inner n = new Outer.Inner();
}
}
另一个示例:
public class _02_OuterClass{
//静态变量
private static String s1 = "A";
//成员变量
private String s2 = "B-------";
//静态方法
private static void m1(){
System.out.println("static's m1 method execute!");
}
//成员方法
private void m2(){
System.out.println("m2 method execute!");
}
//静态内部类
static class InnerClass{
//静态方法
public static void m3(){
System.out.println(s1);
m1();
//也有外部静态类,性质一样
//成员变量和成员方法:无法从静态上下文中引用非静态 变量 s2
_02_OuterClass a = new _02_OuterClass();
System.out.println(a.s2+"kkkkkkkkkkkkk");//调用成员属性,有对象引用就行
//m2();
}
//成员方法
public void m4(){
System.out.println(s1);
m1();
//System.out.println(s2);
//m2();
}
}
//入口
public static void main(String[] args){
//执行m3
_02_OuterClass.InnerClass.m3();
//执行m4
InnerClass inner = new _02_OuterClass.InnerClass();
inner.m4();
}
}