class A{
A(){
System.out.println("A class")
}
A getInstance() {
System.out.println("return a new A")
return new A()
}
}
public static void main(String[] args)
{
System.out.println("closing class ")
InnerClass innerClass=new InnerClass()
InnerClass.A a=innerClass.new A()
a=a.getInstance()
//如果上面没有创建外部类对象,那么就不能这样
//A a =new A()这是因为在没有创建外部类对象的时候,不能创建内部类对象(这个情况除了嵌套类之外),构建内部类的对象时,需要指向一个外部类对象的引用。
}
}
Java中的几种内部类:成员内部类:作为外部类的一个成员存在,与外部类的属性、方法并列。当某个类除了他的外部类,不会被其他类使用时应该选择使用成员内部类。
局部内部类:局部内部类定义在外部类的某个代码块或方法块中。如果只会在某个方法或块中创建这个类的对象,就可以使用局部内部类。
匿名内部类:匿名内部类一般定义在需要传递接口或回调的的地方,一个匿名内部类一定是在new的后面,用其隐含实现一个接口或继承一个类。假如只需要创建这个类的一个对象不需要知道其实际类型(不需要使用到类名),那么就可以使用匿名内部类。
静态内部类:和成员内部类一样,作为外部类的一个成员存在,与外部类的属性、方法并列,只不过在声明类的时候加入了static关键字。有时候,使用内部类只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外围类对象。这时可以使用静态内部类,以便取消产生对外部类的引用。
对普通类(没有内部类的类)来说,内部类和外部类都与他无关;对有内部类的类来说,它们就是其内部类的外部类,外部类是个相对的说法,其实就是有内部类的类。所以,要回答这个问题,只需要讲解内部类是什么:
Java中的内部类共分为四种:
静态内部类static inner class (also called nested class)
成员内部类member inner class
局部内部类local inner class
匿名内部类anonymous inner class
静态内部类Static Inner Class
最简单的内部类形式。
类定义时加上static关键字。
不能和外部类有相同的名字。
被编译成一个完全独立的.class文件,名称为OuterClass$InnerClass.class的形式。
只可以访问外部类的静态成员和静态方法,包括了私有的静态成员和方法。
生成静态内部类对象的方式为:
OuterClass.InnerClass inner = new OuterClass.InnerClass()
示例代码:
package com.learnjava.innerclass
class StaticInner
{
private static int a = 4
// 静态内部类
public static class Inner
{
public void test()
{
// 静态内部类可以访问外部类的静态成员
// 并且它只能访问静态的
System.out.println(a)
}
}
}
public class StaticInnerClassTest
{
public static void main(String[] args)
{
StaticInner.Inner inner = new StaticInner.Inner()
inner.test()
}
}
成员内部类Member Inner Class
成员内部类也是定义在另一个类中,但是定义时不用static修饰。
成员内部类和静态内部类可以类比为非静态的成员变量和静态的成员变量。
成员内部类就像一个实例变量。
它可以访问它的外部类的所有成员变量和方法,不管是静态的还是非静态的都可以。
在外部类里面创建成员内部类的实例:
this.new Innerclass()
在外部类之外创建内部类的实例:
(new Outerclass()).new Innerclass()
在内部类里访问外部类的成员:
Outerclass.this.member
示例代码:
package com.learnjava.innerclass
class MemberInner
{
private int d = 1
private int a = 2
// 定义一个成员内部类
public class Inner2
{
private int a = 8
public void doSomething()
{
// 直接访问外部类对象
System.out.println(d)
System.out.println(a)// 直接访问a,则访问的是内部类里的a
// 如何访问到外部类里的a呢?
System.out.println(MemberInner.this.a)
}
}
}
public class MemberInnerClassTest
{
public static void main(String[] args)
{
// 创建成员内部类的对象
// 需要先创建外部类的实例
MemberInner.Inner2 inner = new MemberInner().new Inner2()
inner.doSomething()
}
}
局部内部类Local Inner Class
局部内部类定义在方法中,比方法的范围还小。是内部类中最少用到的一种类型。
像局部变量一样,不能被public, protected, private和static修饰。
只能访问方法中定义的final类型的局部变量。
局部内部类在方法中定义,所以只能在方法中使用,即只能在方法当中生成局部内部类的实例并且调用其方法。
示例代码:
package com.learnjava.innerclass
class LocalInner
{
int a = 1
public void doSomething()
{
int b = 2
final int c = 3
// 定义一个局部内部类
class Inner3
{
public void test()
{
System.out.println("Hello World")
System.out.println(a)
// 不可以访问非final的局部变量
// error: Cannot refer to a non-final variable b inside an inner
// class defined in a different method
// System.out.println(b)
// 可以访问final变量
System.out.println(c)
}
}
// 创建局部内部类的实例并调用方法
new Inner3().test()
}
}
public class LocalInnerClassTest
{
public static void main(String[] args)
{
// 创建外部类对象
LocalInner inner = new LocalInner()
// 调用外部类的方法
inner.doSomething()
}
}
匿名内部类Anonymous Inner Class
匿名内部类就是没有名字的局部内部类,不使用关键字class, extends, implements, 没有构造方法。
匿名内部类隐式地继承了一个父类或者实现了一个接口。
匿名内部类使用得比较多,通常是作为一个方法参数。
生成的.class文件中,匿名类会生成OuterClass$1.class文件,数字根据是第几个匿名类而类推。
示例代码:
package com.learnjava.innerclass
import java.util.Date
public class AnonymouseInnerClass
{
@SuppressWarnings("deprecation")
public String getDate(Date date)
{
return date.toLocaleString()
}
public static void main(String[] args)
{
AnonymouseInnerClass test = new AnonymouseInnerClass()
// 打印日期:
String str = test.getDate(new Date())
System.out.println(str)
System.out.println("----------------")
// 使用匿名内部类
String str2 = test.getDate(new Date()
{
})// 使用了花括号,但是不填入内容,执行结果和上面的完全一致
// 生成了一个继承了Date类的子类的对象
System.out.println(str2)
System.out.println("----------------")
// 使用匿名内部类,并且重写父类中的方法
String str3 = test.getDate(new Date()
{
// 重写父类中的方法
@Override
@Deprecated
public String toLocaleString()
{
return "Hello: " + super.toLocaleString()
}
})
System.out.println(str3)
}
}