一、定义
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。
二、作用
使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。
1.内部类可以很好的实现隐藏,一般的非内部类,是不允许有 private 与protected权限的,但内部类可以;
2.内部类拥有外围类的所有元素的访问权限;
3.可是实现多重继承;
4.可以避免修改接口而实现同一个类中两种同名方法的调用。
三、内部类的使用
当我们在创建一个内部类的时候,它无形中就与外围类有了一种联系,依赖于这种联系,它可以无限制地访问外围类的元素。
public class OuterClass {
private String name ;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/**
* 类名称:InnerClass
* 描述: 内部类
* 创建人:王秋林
*/
public class InnerClass{
public InnerClass(){
setName("wangql");
setAge(25);
}
public void show(){
System.out.println("name:" + getName() +" and age:" + getAge());
}
}
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
innerClass.show();
}
}
输出结果:name:wangql and age:25
在这个应用程序中,我们可以看到内部了InnerClass可以对外围类OuterClass的属性进行无缝的访问,尽管它是private修饰的。这是因为当我们在创建某个外围类的内部类对象时,此时内部类对象必定会捕获一个指向那个外围类对象的引用,只要我们在访问外围类的成员时,就会用这个引用来选择外围类的成员。
其实在这个应用程序中我们还看到了如何来引用内部类:引用内部类我们需要指明这个对象的类型:OuterClasName.InnerClassName。同时如果我们需要创建某个内部类对象,必须要利用外部类的对象通过.new来创建内部类: OuterClass.InnerClass innerClass = outerClass.new InnerClass();。
同时如果我们需要生成对外部类对象的引用,可以使用OuterClassName.this,这样就能够产生一个正确引用外部类的引用了。
public class OuterClass {
public void display(){
System.out.println("OuterClass...");
}
public class InnerClass{
public OuterClass getOuterClass(){
return OuterClass.this;
}
}
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
innerClass.getOuterClass().display();
}
}
输出结果:OuterClass...
注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。所以内部类的成员变量/方法名可以和外部类的相同。
1:成员内部类
成员内部类也是最普通的内部类,成员内部类就是作为外部类的成员,可以直接使用外部类的所有成员和方法,即使是private的。同时外部类要访问内部类的所有成员变量/方法,则需要通过内部类的对象来获取。
要注意的是,成员内部类不能含有static的变量和方法。因为成员内部类需要先创建了外部类,才能创建它自己的。
package com.mianshi.test;
/**
* 类名称:OuterClass1
* 描述: 成员内部类测试
* 创建人:王秋林
* 创建时间:2017-2-12
*/
public class OuterClass1 {
private String str;
public void outerDisplay(){
System.out.println("内部类的方法...");
}
public class InnerClass{
public void innerDisplay(){
//使用内部类的属性
str = "内部类的属性...";
System.out.println(str);
//使用内部类的方法
outerDisplay();
}
}
/*推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 */
public InnerClass getInnerClass(){
return new InnerClass();
}
public static void main(String[] args) {
OuterClass1 outer = new OuterClass1();
OuterClass1.InnerClass inner = outer.getInnerClass();
inner.innerDisplay();
}
}
输出结果:
内部类的属性...
内部类的方法...
推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 。
在成员内部类要引用外部类对象时,使用outer.this来表示外部类对象;
而需要创建内部类对象,可以使用outer.inner obj = outerobj.new inner();
2:局部内部类
局部内部类,是指内部类定义在方法和作用域内。它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
《Thinking in Java》给了这么两个例子:
(1)定义在方法中
public class Parcel4 {
public Destination destination(String s) {
class PDestination implements Destination {
private String label;
private PDestination(String whereTo) {
label = whereTo;
}
public String readLabel() {
return label;
}
}
return new PDestination(s);
}
public static void main(String[] args) {
Parcel4 p = new Parcel4();
Destination d = p.destination("Tasmania");
System.out.println(d.readLabel());
}
}
(2)定义在作用域里
public class Parcel5 {
private void internalTracking(boolean b) {
if (b) {
class TrackingSlip {
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip() {
return id;
}
}
TrackingSlip ts = new TrackingSlip("slip");
String s = ts.getSlip();
System.out.println(s);
}
}
public void track() {
internalTracking(true);
}
public static void main(String[] args) {
Parcel5 p = new Parcel5();
p.track();
}
}
局部内部类也像别的类一样进行编译,但只是作用域不同而已,只在该方法或条件的作用域内才能使用,退出这些作用域后无法引用的。
3:匿名内部类
匿名内部类也就是没有名字的内部类。
public class OuterClass {
public InnerClass getInnerClass(final int num,String str2){
return new InnerClass(){
int number = num + 3;
public int getNumber(){
return number;
}
}; /* 注意:分号不能省 */
}
public static void main(String[] args) {
OuterClass out = new OuterClass();
InnerClass inner = out.getInnerClass(2, "chenssy");
System.out.println(inner.getNumber());
}
}
interface InnerClass {
int getNumber();
}
输出结果:5
(1)匿名内部类是没有访问修饰符的。
(2)new 匿名内部类,这个类首先是要存在的。如果我们将那个InnerClass接口注释掉,就会出现编译出错。
(3) 注意getInnerClass()方法的形参,第一个形参是用final修饰的,而第二个却没有。同时我们也发现第二个形参在匿名内部类中没有使用过,所以当所在方法的形参需要被匿名内部类使用,那么这个形参就必须为final。
(4) 匿名内部类是没有构造方法的。因为它连名字都没有何来构造方法。
4:静态内部类
使用static修饰的内部类我们称之为静态内部类,也称之为嵌套内部类。静态内部类的创建不需要依赖于外围类的。静态内部类的创建是不能使用任何外围类的非static成员变量和方法。静态内部类和普通的内部类还有一个区别:普通内部类不能有static数据和static属性,也不能包含静态类,但静态类可以。而静态类不能声明为private,一般声明为public,方便调用。
package com.mianshi.test.innerClass;
/**
*
* 类名称:OuterClass2
* 描述: 静态内部类
* 创建人:王秋林
* 创建时间:2017-2-12
*/
public class OuterClass2 {
public static String name = "staticInnerClass1";
/**
*静态内部类
*/
static class InnerClass1{
/* 在静态内部类中可以存在静态成员 */
public static String _name1 = "staticClass";
public void display(){
/*
* 静态内部类只能访问外围类的静态成员变量和方法
* 不能访问外围类的非静态成员变量和方法
*/
System.out.println("OutClass name :" + name);
}
}
/**
* 非静态内部类
*/
class InnerClass2{
/* 非静态内部类中不能存在静态成员 */
public String _name2 = "staticInnerClass2";
/* 非静态内部类中可以调用外围类的任何成员,不管是静态的还是非静态的 */
public void display(){
System.out.println("OuterClass name:" + name);
}
}
/**
* 方法名:外围类方法
* 开发者:wangql
* 开发时间:2017-2-12
*/
public void display(){
/* 外围类访问静态内部类:内部类. */
System.out.println(InnerClass1._name1);
/* 静态内部类 可以直接创建实例不需要依赖于外围类 */
new InnerClass1().display();
/* 非静态内部的创建需要依赖于外围类 */
OuterClass2.InnerClass2 inner2 = new OuterClass2().new InnerClass2();
/* 方位非静态内部类的成员需要使用非静态内部类的实例 */
System.out.println(inner2._name2);
inner2.display();
}
public static void main(String[] args) {
OuterClass2 outer = new OuterClass2();
outer.display();
}
}
输出结果:
staticClass
OutClass name :staticInnerClass1
staticInnerClass2
OuterClass name:staticInnerClass1
参考文章: