您的位置:首页 > 编程语言 > Java开发

Java内部类

2016-03-07 15:14 375 查看
一、内部类

把一个类放在另一个类的内部定义,这个定义在内部的类就是内部类。

1.成员内部类

成员内部类是与成员变量、方法和初始化块相似的类成员。可以用public、private、protected或者缺省修饰。

成员内部类分为两种:没有使用static修饰的成员内部类是非静态内部类。使用static修饰的成员内部类是非静态内部类。

非静态内部类

非静态内部类不能有静态成员如:静态变量,静态方法,静态初始化块。

非静态内部类可以访问外部类所有的成员变量和方法,因为在非静态内部类的对象里保存了一个它寄存的外部类对象的引用(所以在非静态内部类直接访问外部类的所有成员变量和方法编译是不会报错的)。

外部类不能直接访问内部类的成员变量和方法,只能通过实例化内部类来访问。(private修饰的成员也可以)如下:

public class Test
{
public class Inner{
private int  i = 3;
}
public void test()
{
System.out.println(new inner().i);
}
public static void main (String[] args)
{
Test t= new Test();
t.test();
}
}3

在外部类以外调用非静态内部类:

在创建非静态内部类的实例时必须先创建外部类实例,如:Test Inner = new test().new Inner();

如果要创建一个非静态内部类的子类的实例,必须先存在一个外部类的实例,因为在创建子类实例的时候会调用非静态内部类的构造函数,而要调用非静态内部类的构造函数则必须先创建一个外部类的实例。

静态内部类

静态内部类不能访问外部类的实例变量和方法,只能访问静态变量和方法。

静态内部类可定义有静态成员如:静态变量,静态方法,静态初始化块。

外部类不能直接访问静态内部类的成员变量和方法:访问静态内部类的静态变量和方法,通过静态内部类类名来调用。访问静态内部类的实例变量和方法,通过实例化静态内部类来调用。(private修饰的成员也可以)

public class Test
{
static class Inner{
private int  i = 3;
private static int n = 4;
}
public void test()
{
System.out.println(new inner().i);
System.out.println(inner.n);
}
public static void main (String[] args)
{
Test t= new Test();
t.test();
}
}3 4

在外部类以外调用静态内部类:

静态内部类在创建实例时不需要创建外部类的实例,如Test Inner = new Test.Inner();

如果要创建一个静态内部类的子类的实例,可以直接实例化子类。

class Son extends Test.Inner{ }


2.局部内部类

局部内部类在方法或者一个作用域中定义,只能在该方法或者作用域中使用。
局部内部类不能用任何的修饰符修饰。

可以访问外部类的局部变量,则必须使用final修饰符来修饰外部类的局部变量。

以下与非静态内部类相同:

局部内部类不能有静态成员如:静态变量,静态方法,静态初始化块。

局部内部类可以访问外部类所有的成员变量和方法,因为在局部内部类的对象里保存了一个它寄存的外部类对象的引用。(所以在局部内部类内部类直接访问外部类的所有成员变量和方法编译是不会报错的)

外部类不能直接访问局部内部类的成员变量和方法,只能通过实例化内部类来访问。(private修饰的成员也可以)

如下图:

public class Test
{
public void test(){
class InnerClass{
private int i = 1;
}
InnerClass in = new InnerClass();
System.out.println(in.i);
}
public static void main (String[] args)
{
Test t = new Test();
t.test();
}
}1


3.匿名内部类

匿名内部类是一个只使用一次的,没有名字的,会在继承父类或者实现接口的同时创建一个对象的类。

子类继承父类:

abstract class Father{
public abstract void read();
}
class Son extends Father{
public void read(){
System.out.println("read");
}
}
public class Test {
public static void main (String[] args)
{
Father father = new Son();
father.read();
}
}
如果只需要使用子类实例化一次,可以使用匿名内部类,new 父类构造方法{ 匿名内部类类体(覆盖父类方法) }

abstract class Father{
public abstract void read();
}

public class Test
{
public static void main (String[] args)
{
Father father = new Father(){
public void read(){
System.out.println("read");
}
};
father.read();
}
}


子类实现接口:

interface Father{
public abstract void read();
}
class Son implements Father{
public void read(){
System.out.println("read");
}
}
public class test
{
public static void main (String[] args)
{
Father father = new Son();
father.read();
}
}
如果只需要使用子类实例化一次,可以使用匿名内部类,new 接口名(){匿名内部类类体(覆盖接口抽象方法) }
interface Father{
public abstract void read();
}

public class test
{
public static void main (String[] args)
{
Father father = new Father(){
public void read(){
System.out.println("read");
}
};
father.read();
}
}

匿名内部类的限制

匿名内部类必须继承一个父类(可抽象可不抽象),或者实现一个接口。
匿名内部类会创建实例,所以它不能是抽象类,也就是说匿名内部类必须实现抽象父类或者接口的全部抽象方法。

匿名内部类没有类名,所以没有构造方法,但是可以通过初始化块来进行初始化。

通过多态的方式来调用匿名内部类的方法。

以下与局部内部类相同:

匿名内部类需要访问外部类的局部变量,则必须使用final修饰符来修饰外部类的局部变量。

匿名内部类不能有静态成员如:静态变量,静态方法,静态初始化块。

匿名内部类可以访问外部类所有的成员变量和方法,因为在匿名内部类的对象里保存了一个它寄存的外部类对象的引用。(所以在匿名内部类直接访问外部类的所有成员变量和方法编译是不会报错的)

匿名内部类的使用原理分析

从编译后的Class文件可以看出,创建匿名内部类实例的时候,实际上会有一个隐式的子类去继承父类或者实现接口,然后调用这个隐式子类的构造方法(继承父类的话会先调用父类构造方法),这跟普通子类继承父类或者实现接口是一样的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: