在java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:非静态内部成员类、静态内部成员类、局部内部类和匿名内部类。下面就先来了解一下这四种内部类的用法。
内部类是指在一个外部类的内部再定义一个类。类名不需要和文件夹相同。内部类可以是静态static的,也可用public,default,PRotected和private修饰。(而外部顶级类即类名和文件名相同的只能使用public和default)。
注意:内部类是一个编译时的概念,一旦编译成功,就会成为与外部类完全不同的两个类。对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。所以内部类的成员变量及方法名可以和外部类的相同。
非静态成员内部类即普通成员内部类,就是作为外部类的成员,可以直接使用外部类的所有成员和方法,即使是private的。同时外部类如果要访问内部类的所有成员变量与方法,则需要通过内部类的实例对象来获取。要注意的是,普通成员内部类不能含有static的变量和方法。因为普通成员内部类需要先创建了外部类,才能创建它自己,了解这一点,就可以明白更多事情,在此省略更多的细节了。在普通成员内部类要引用外部类对象时,使用outer.this来表示外部类对象;而需要创建内部类对象时,可以使用outer.inner obj = outerobj.new inner()来创建,在创建内部类实例之前需要先创建外部类的实例对象。测试代码如下:
public class OuterNestedClass { private int x = 100; class MyInner { private String y = "Hello!"; public void innerMethod() { System.out.println("内部类中 String = " + y); System.out.println("外部类中的x = " + x);//直接访问外部类变量x outerMethod(); System.out.println("内部类调用外部类方法执行x++后,x = " + OuterNestedClass.this.x); } } public void outerMethod() { x++; } public MyInner makeInner() { return new MyInner(); //在外部类方法中创建内部类实例 } public int getX(){ return x; } public static void main(String[] args) { OuterNestedClass outer = new OuterNestedClass(); //创建外部类实例 OuterNestedClass.MyInner inner = outer.new MyInner();//内部类实例 outer.outerMethod(); System.out.println("外部类中的x = " + outer.getX()); inner.innerMethod(); OuterNestedClass.MyInner inner2 = outer.makeInner();//创建内部类实例 inner2.innerMethod(); }}运行结果如下:外部类中的x = 101内部类中 String = Hello!外部类中的x = 101内部类调用外部类方法执行x++后,x = 102内部类中 String = Hello!外部类中的x = 102内部类调用外部类方法执行x++后,x = 103上面代码中,如果将public MyInner makeInner()方法声明改为public static MyInner makeInner(),编译器将提示错误:“没有任何类型OuterNestedClass的外层实例可访问。必须用类型OuterNestedClass的外层实例(例如,x.new A(),其中x是OuterNestedClass的实例)来限定分配。”这表明非静态成员类的每个实例都隐含着与外围类的一个外围实例相关联,在没有外围实例的情况下,要想创建非静态成员内部类的实例是不可能的。静态成员内部类
静态成员内部类,就是修饰为static的内部成员类。声明为static的内部类,不需要内部类对象和外部类对象之间的联系,就是说我们可以直接引用outer.inner,即不需要创建外部类实例,也不需要创建内部类。静态内部类与静态内部方法相似,只能访问外围类的static成员,不能直接访问外部类的实例变量与实例方法,只有通过对象引用才能访问。由于static内部类不具有任何对外部类实例的引用,因此static内部类中不能使用this关键字来访问外部类中的实例成员,但是可以访问外部类中的static成员,这与一般类的static方法相通。静态成员内部类和普通的内部类还有一个区别:普通内部类不能有static数据和static属性,也不能再包含静态成员内部类,但静态成员内部类可以,而静态成员内部类不能声明为private,一般声明为public,方便调用。测试代码如下:
public class Outer { private static int x = 100; //外围类静态数据成员 //创建静态内部类 public static class MyInner { private String y = "Hello!"; public void innerMethod() { System.out.println("内部类中String = " + y); System.out.println("外部类中的staic变量x = " + x); } } public static MyInner makeInner() { return new MyInner(); //在外部类方法中创建内部类实例 } public void outerMethod() { x++; } public int getX(){ return x; } public static void main(String[] args) { Outer outer = new Outer(); //与普通类的实例通过类名创建相似 Outer.MyInner si = new Outer.MyInner();//静态内部类不通过外部实例就可以创建对象 outer.outerMethod(); System.out.println("外部类中的static变量x = " + outer.getX()); si.innerMethod(); outer.outerMethod(); Outer.MyInner si2 = Outer.makeInner(); //通过外围类静态方法创建内部类实例 si2.innerMethod(); }}运行结果如下:外部类中的static变量x = 101内部类中 String = Hello!外部类中的staic变量x = 101内部类中 String = Hello!外部类中的staic变量x = 102局部内部类
定义在代码块、方法体内、作用域(使用花括号“{}”括起来的一段代码)内的类叫局部内部类。局部内部类只能在代码代码块、方法体内和作用域中使用(创建对象和使用类对象)。局部内部类也像别的类一样进行编译,但只是作用域不同而已,只在该方法或条件的作用域内才能使用,退出这些作用域后无法引用的。局部内部类访问外部类的属性和方法使用“外部类名.this.属性名”和“外部类名.this.方法名(参数)”的形式。局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的,最多只能有final修饰。局部内部类的定义方式如下:
public class Test { { class AA{} //块内局部类 } public Test(){ class AA{} //构造器内局部类 } public static void main(String[] args){ } public void test(){ class AA{} //方法内局部类 }}注意到了吧,局部内部类可以同名,编译后形成诸如:外部类名称+$+同名顺序+局部类名称:Test$1AA.class/Test$2AA.class/Test$3AA.class。以下是将局部内部类定义在代码块内的示例代码:
public class LocalNestedClass2 { private String internalTracking(boolean b) { if (b) { final class TrackingSlip { private String id; TrackingSlip(String s) { id = s; } String getSlip() { return id; } } TrackingSlip ts = new TrackingSlip("slip"); String s = ts.getSlip(); return s.toUpperCase(); } else return ""; } public String track() { return internalTracking(true); } public static void main(String[] args) { LocalNestedClass2 p = new LocalNestedClass2(); System.out.println(p.track()); } }匿名内部类
匿名类,就是没有名称的类,其名称由Java编译器给出,一般是形如:外部类名称+$+匿名类顺序,没有名称也就意味着在其他地方就不能引用,不能实例化,只用一次,当然也就不能有构造器。匿名类根据位于地方不同分为:成员匿名类和局部匿名类。匿名类不能使用任何关键字和访问控制符,匿名类和局部类访问规则一样,只不过内部类显式的定义了一个类,然后通过new的方式创建这个局部类实例,而匿名类直接new一个类实例,没有定义这个类。匿名类最常见的方式就是回调模式的使用,通过默认实现一个接口创建一个匿名类然后,然后new这个匿名类的实例。匿名内部类定义和实例化形式如下:
new父类构造方法(参数){ 修饰符 返回参数类型 方法名(参数列表)//该方法名须在父类中存在 { }}匿名内部类只能和new连用,用于创建一个实例。匿名内部类只能使用一次,创建实例之后,类定义会立即消失(想要多次使用就要用到反射的知识了)。匿名内部类必须继承一个类(抽象的、非抽象的都可以)或者实现一个接口。如果父类(或者父接口)是抽象类,则匿名内部类必须实现其所有抽象方法。匿名内部类不能是抽象类,因为匿名内部类在定义之后,会立即创建一个实例。匿名内部类不能定义构造方法,匿名内部类没有类名,无法定义构造方法,但是,匿名内部类拥有与父类相同的所有构造方法。匿名内部类中可以定义代码块,用于实例的初始化,但是不能定义静态代码块。以下是匿名内部类的测试代码:
abstract class Test{ public abstract void print(); }interface Inner { String getName(); }public class AnonymousNestedClass { public static void main(String[] args) { AnonymousNestedClass outer = new AnonymousNestedClass (); Inner inner = outer.getInner("Inner", "gz"); System.out.println(inner.getName()); //定义一个匿名内部类,并实例化对象 Test test = new Test() { @Override public void print() { System.out.println("匿名内部类实现父类所有的抽象方法"); } }; test.print(); System.out.println("匿名内部类的类名:test.getClass().getName() == " + test.getClass().getName()); System.out.println("父类的类名:Test.class.getName() == " + Test.class.getName()); System.out.println("test.getClass().equals(Test.class) == " + test.getClass().equals(Test.class)); System.out.println("test.getClass().getSuperclass().equals(Test.class) == " + test.getClass().getSuperclass().equals(Test.class)); } public Inner getInner(final String name, String city) { return new Inner() { private String nameStr = name; public String getName() { return nameStr + ", " + city; } }; } } 运行结果:Inner, gz匿名内部类实现父类所有的抽象方法!匿名内部类的类名:test.getClass().getName() == nestedClass.AnonymousNestedClass$1父类的类名:Test.class.getName() == nestedClass.Testtest.getClass().equals(Test.class) == falsetest.getClass().getSuperclass().equals(Test.class) == true
新闻热点
疑难解答