------- android培训、java培训、期待与您交流! ----------
大部分时候,类被定义成一个独立的程序单元。在某些情况下,也会把一个类放在另一个人类的内部定义,这个定义在其他类内部的类就被称为内部类,包含内部类的类也被称为外部类,内部类主要有如下作用:
1:内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类。
2:内部类成员可以直接访问外部类的私有数据,因为内部类被当成其成员,同一个类的成员之间可以互相访问。但外部类不能访问内部类的实现细节,例如内部类的成员变量。
3:匿名内部类适合用于创建那些仅需要一次使用的类。
从语法角度来看,定义内部类与定义外部类的语法大致相同,内部类除了需要定义在其他类里面之外,还存在如下两点区别。
1:内部类比外部类可以多使用三个修饰符:private,protected,static 外部类不可以使用这三个修饰符。
2:非静态内部类不能拥有静态成员。
非静态内部类
定义内部类非常简单,只要把一个类放在另一个类内部定义即可。此处的“类内部”包括类中的任何位置,甚至在方法中也可以定义内部类(方法里定义的内部类被称为局部内部类)。
大部分时候,内部类都被作为成员内部类定义,而不是作为局部内部类。成员内部类是一种与成员变量,方法,构造器和初始化块相似的类成员:局部内部类和匿名内部类则不是类成员。
成员内部类分为两种:静态内部类和非静态内部类,使用static修饰的成员内部类是静态内部类,没有使用static修饰的成员内部类是非静态内部类。
下面程序在Cow类里定义了一个CowLeg非静态内部类,并在CowLeg类的实例方法中直接访问Cow的private访问权限的实例变量。
1 public class Cow 2 { 3 private double weight; 4 5 //外部类的两个重载的构造器 6 public Cow(){} 7 public Cow(double weight) 8 { 9 this.weight = weight; 10 } 11 12 //定义一个非静态内部类 13 private class CowLeg 14 { 15 //非静态内部类的两个实例变量 16 private double length; 17 private String color; 18 //非静态内部类的两个重载的构造器 19 public CowLeg(){} 20 public CowLeg(double length, String color) 21 { 22 this.length = length; 23 this.color = color; 24 } 25 26 //省略set和get方法 27 28 29 //非静态内部类的实例方法 30 public void info() 31 { 32 System.out.println("当前牛腿的颜色是:" + color + ", 高: " +length); 33 34 //直接访问外部类的private修饰的成员变量 35 System.out.println("本牛腿所在的奶牛重:" + weight); 36 } 37 } 38 39 public void test() 40 { 41 CowLeg c = new CowLeg(1.12, "黑白相间"); 42 c.info(); 43 } 44 45 public static void main(String[] args) 46 { 47 Cow cow = new Cow(378.9); 48 cow.test(); 49 } 50 }
当在非静态内部类的方法内访问某个变量时,系统优先在该方法内查找是否存在该名字的局部变量,如果存在就使用该变量;如果不存在,则到该方法所在的内部类中查找是否存在该名字的成员变量,如果存在则使用该成员变量;如果不存在,则到该内部类所在的外部类中查找是否存在该名字的成员变量,如果存在则使用该成员变量;如果依然不存在,系统将出现编译错误:提示找不到该变量。
因此,如果外部类成员变量,内部类成员变量与内部类里方法的局部变量同名,则可通过使用外部类类名.this作为限定来区分。如下程序所示:
1 public class DiscernVariable 2 { 3 private String prop = "外部类的实例变量"; 4 5 private class InClass 6 { 7 private String prop = "内部类的实例变量"; 8 9 public void info() 10 { 11 String prop = "局部变量"; 12 //通过外部类类名.this.VarName访问外部类实例变量 13 System.out.println("外部类的实例变量值: " + DiscernVariable.this.prop); 14 //通过this.varName访问内部类实例的变量 15 System.out.println("内部类的实例变量值: " + this.prop); 16 //直接访问局部变量 17 System.out.println("局部变量的值: " + prop); 18 } 19 } 20 public void test() 21 { 22 InClass in = new InClass(); 23 in.info(); 24 } 25 public static void main(String[] args) 26 { 27 // DiscernVariable dv = new DiscernVariable(); 28 // dv.test(); 29 new DiscernVariable().test(); 30 } 31 }
非静态内部类的成员可以访问外部类的private成员,但反过来就不成立了。非静态内部类的成员只在非静态内部类范围内是可知的,并不能被外部类直接使用。如果外部类需要访问非静态内部类的成员,则必须显式创建非静态内部类对象来调用访问其实例成员。下面程序示范了这个规则。
1 public class Outer 2 { 3 private int outProp = 9; 4 5 class Inner 6 { 7 private int inProp = 5; 8 public void acessOuterProp() 9 { 10 //非静态内部类可以直接访问外部类的private成员变量 11 System.out.println("外部类的outProp值:" + outProp); 12 } 13 } 14 public void accessInnerProp() 15 { 16 //外部类不能直接访问非静态内部类的实例变量 17 //下面代码编译错误 18 // System.out.println("内部类的值:" + inProp); 19 20 //如需访问内部类的实例变量,必须显式创建内部类对象 21 System.out.println("内部类的inProp值:" + new Inner().inProp); 22 } 23 24 public static void main(String[] args) 25 { 26 //执行下面代码,只创建了外部类对象,还未创建内部类对象 27 Outer out = new Outer(); 28 out.accessInnerProp(); 29 } 30 }
根据静态成员不能访问非静态成员的规则,外部类的静态方法,静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量,创建实例等,总之,不允许在外部类的静态成员中直接使用非静态内部类。如下程序所示:
1 public class StaticTest 2 { 3 //定义一个非静态的内部类,是一个空类 4 private class In 5 { 6 7 } 8 9 //外部类的静态方法 10 public static void main(String[] args) 11 { 12 //下面代码引发编译异常,因为静态成员main方法 13 //无法访问非静态成员In类 14 15 new In(); 16 } 17 }
java不允许在非静态内部类里定义静态成员。
非静态内部类里不能有静态方法,静态成员变量,静态初始化块。