广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。下面就先来了解一下这四种内部类的用法。
一、 成员内部类:成员内部类是最普通的内部类,它的定义为位于另一个类的内部 ,成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。//外部类 class Out { private int age = 12; //内部类 class In { public void print() { System.out.println(age); } } } public class Demo { public static void main(String[] args) { Out.In in = new Out().new In(); in.print(); //或者采用下种方式访问 /* Out out = new Out(); Out.In in = out.new In(); in.print(); */ } }运行结果:12
如同心脏可以直接访问身体的血液,而不是通过医生来抽血
程序编译过后会产生两个.class文件,分别是Out.class和Out$In.class
其中$代表了上面程序中Out.In中的那个 .
Out.In in = new Out().new In()可以用来生成内部类的对象,这种方法存在两个小知识点需要注意
1.开头的Out是为了标明需要生成的内部类对象在哪个外部类当中
2.必须先有外部类的对象才能生成内部类的对象,因为内部类的作用就是为了访问外部类中的成员变量
内部类中的变量访问形式:
class Out { private int age = 12; class In { private int age = 13; public void print() { int age = 14; System.out.println("局部变量:" + age); System.out.println("内部类变量:" + this.age); System.out.println("外部类变量:" + Out.this.age); } } } public class Demo { public static void main(String[] args) { Out.In in = new Out().new In(); in.print(); } }运行结果:
注意:
1、成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。
2、当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量 外部类.this.成员方法3、虽然成员内部类可以无条件地访问外部类的成员,而外部类想访问成员内部类的成员却不是这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问
5、内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。如果成员内部类Inner用private修饰,则只能在外部类的内部访问,如果用public修饰,则任何地方都能访问;如果用protected修饰,则只能在同一个包下或者继承外部类的情况下访问;如果是默认访问权限,则只能在同一个包下访问。这一点和外部类有一点不一样,外部类只能被public和包访问两种权限修饰。由于成员内部类看起来像是外部类的一个成员,所以可以像类的成员一样拥有多种权限修饰。
二、静态内部类:静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
public class Test { public static void main(String[] args) { Outter.Inner inner = new Outter.Inner(); } } class Outter { public Outter() { } static class Inner { public Inner() { } } }静态类的使用场景:
public class Person{ //姓名 private String name; //家庭 private Home home; //构造函数设置属性值 public Person(String _name){ name = _name; } /* home、name的getter/setter方法省略 */ public static class Home{ //家庭地址 private String address; //家庭电话 private String tel; public Home(String _address,String _tel){ address = _address; tel = _tel; } /* address、tel的getter/setter方法省略 */ } }把Home放在Person内部,一看便知道Home是Person的一个属性。使用的时候也很方便,如下代码:
public static void main(String[] args) { Home home = new Person.Home("上海", "021"); Person p1 = new Person("张三"); Person p2 = new Person("李四"); p1.setHome(home); p2.setHome(home); }这里创建一个home对象,p1和p2都使用这个home对象,p1和p2共享同一个home对象。
public static void main(String[] args) { Person p1 = new Person("张三"); Home home = p1.new Home("上海", "021"); p1.setHome(home); Person p2 = new Person("李四"); p2.setHome(home); }