内部类顾名思义就是指在类里面的类,内部类分为以下四种:
①成员内部类
②局部内部类
③匿名内部类
④静态内部类
问题来了,为什么要使用内部类呢?
每个内部类都能够独立地继承一个(接口的)实现,无论外围类是否已经继承(接口的)实现,对其都不影响。内部类能够十分好的解决多重继承的问题。创建内部类的对象的时候,并不依赖于外围类对象的创建,内部类就是一个独立的实体。内部类除了其的外围类,其它类都不能够访问它。
内部类可以很轻松地访问外围类的属性等,就算外围类属性等用的private修饰,这是因为在创建一个外围类的内部类的对象时,此时内部类对象会捕获指向外围类对象的引用,只要我们在访问外围类的属性等时,就会用这个引用来选择外围类的属性等。
内部类是个编译时的概念,只要编译成功,它就与其的外围类属于两个不同的类(还有一定的联系)。会生成两个.class文件。外围类.class和外围类$内部类.class。
一、成员内部类:
成员内部类是最普通的内部类,也就是在一个类里面定义一个类。成员内部类使用外围类的成员方法、成员变量等无条件限制,无论是用private修饰的还是static修饰的。
如果成员内部类的方法名或者成员变量同名,那么,会发生隐藏现象,要使用如下方法来访问:外围类.this.成员方法---外围类.this.成员变量。
内部类访问外围类的成员方法、变量无限制,但是外围类访问内部类的成员方法、变量却不能随心所欲了,但是值得注意的是:外围类访问成员内部类的方法,必须先创建一个成员内部类的对象,再通过这个对象来访问,成员内部类是依托外部类而存在的,如果要创建成员内部类的对象,前提是必须存在一个外围类的对象。
package com.qianfeng.innerClass;
import com.qianfeng.innerClass.MemberInnerClass.InnerClass;
/**
* 成员内部类
* @author littledyf
*
*/
public class MemberInnerClass {
private String a;
//外围类的方法
public void outMethod(){
System.out.println("我是外部类的方法...");
}
//与内部类同名的外围类的方法
public void method(){
System.out.println("我是外部类的同名方法...");
}
//通过getxxxx来访问成员内部类
public InnerClass getInnerClass(){
return new InnerClass();
}
//成员内部类
public class InnerClass{
public void innerMethod(){
//使用外围类的属性,无条件使用,不管是private还是static
a = "我是内部类使用外围类的属性";
System.out.println(a);
//使用外围类的的方法
outMethod();
//使用外围类的同名方法要使用如下形式,因为同名,会发生隐藏现象
MemberInnerClass.this.method();
}
//与外围类同名的成员内部类的方法
public void method(){
System.out.println("我是内部类的同名方法...");
}
}
}
package com.qianfeng.innerClass;
import org.junit.Test;
/*
* 测试成员内部类
*/
public class MemberInnerClassTest {
@Test
public void t(){
/**
* 外围类访问成员内部类的方法,必须先创建一个成员内部类的对象,再通过这个对象来访问
* 成员内部类是依托外部类而存在的,如果要创建成员内部类的对象,前提是必须存在一个外围类的对象
*/
//外围类访问成员内部类的第一种访问方式
System.out.println("第一种方式访问...");
MemberInnerClass mic1 = new MemberInnerClass();
MemberInnerClass.InnerClass ic = mic1.new InnerClass();
ic.innerMethod();
ic.method();
System.out.println("-----------分割线-----------");
//外围类访问成员内部类的第二种访问方式
System.out.println("第二种方式访问...");
MemberInnerClass mic2 = new MemberInnerClass();
MemberInnerClass.InnerClass ic1 = mic2.getInnerClass();
ic1.innerMethod();
ic1.method();
}
}
二、局部内部类
局部内部类是定义在方法中的或者一个作用域里的内部类,局部内部类的访问仅限于方法内或者该作用域内。
局部内部类不能被public、private、static等修饰符修饰。
局部内部类访问作用域的局部变量,该局部变量需要用final修饰。
外部类不能访问局部内部类,只能在方法体中访问局部内部类,且访问必须在内部类定义之后,即创建局部内部类的对象只能在局部内部类的作用域里,且要在内部类定义之后。
局部内部类访问外部类中同名的方法或者变量时,如下:OutClass.this.method()----OutClass.this.变量。
package com.qianfeng.innerClass;
/**
* 局部内部类
* @author littledyf
*
*/
public class PartInnerClass {
//与局部内部类同名的变量s1
private String s1 = "我是外部类与局部内部类同名的变量s1";
//外部类变量s2
private String s2 = "我是外部类用private修饰的变量s2";
//与局部内部类同名的method1
public void method1(){
System.out.println("我是外部类的method1");
}
//与局部内部类同名的method2
public void method2(){
System.out.println("我是外部类的method2");
}
//有局部内部类的method3
public void method3(){
//方法中用final修饰的变量
final String s3 = "我是局部类外部方法中用final修饰的变量s3";
class InnerClass{
private String s1 = "我是局部内部类中与外部类同名的变量s1";
public void method1(){
//局部内部类可以直接访问外部类的变量,即使是private和static
System.out.println(s2);
//局部内部类访问外部方法的变量需要有final修饰
System.out.println(s3);
//局部内部类和外部类有同名的变量和方法时
System.out.println(s1);//实际就是this.s1
System.out.println(PartInnerClass.this.s1);
method2();
PartInnerClass.this.method2();
}
public void method2(){
System.out.println("我是局部内部类的method2");
}
}
InnerClass ic = new InnerClass();
ic.method1();
}
}
package com.qianfeng.innerClass;
import org.junit.Test;
/**
* 测试局部内部类
* @author littledyf
*
*/
public class PartInnerClassTest {
@Test
public void t(){
PartInnerClass pic = new PartInnerClass();
pic.method3();
}
}
三、匿名内部类
匿名内部类不能有访问修饰符和static修饰符的。匿名内部类也就是没有名字的内部类。因为没有名字,所以匿名内部类只能使用一次,通常用来简化代码编写。
匿名内部类是唯一一种没有构造器的类,因为没有构造器,所以其的使用范围非常有限,大部分匿名内部类用于接口回调。匿名内部类在编译的时候,系统自动起名为OutClass$1.class。一般来说,匿名内部类用于继承其它类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或者重写。
匿名内部类不能定义任何静态成员、方法和类。因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。)一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
package com.qianfeng.innerClass;
/**
* 匿名内部类的使用
* @author littledyf
*
*/
public class AnonymityInnerClass {
public void Method(){
AnonymityInnerClassOther aico = new AnonymityInnerClassOther(){
public void print(){
System.out.println("我是匿名内部类");
}
};
aico.print();
}
}
package com.qianfeng.innerClass;
/**
* 匿名内部类将通过重写其方法来获得实现
* @author littledyf
*
*/
public class AnonymityInnerClassOther {
public void print(){
System.out.println("我是已经存在的类,让匿名内部类来重写实现");
}
}
package com.qianfeng.innerClass;
import org.junit.Test;
/**
* 测试匿名内部类
* @author littledyf
*
*/
public class AnonymityInnerClassTest {
@Test
public void t(){
AnonymityInnerClass aic = new AnonymityInnerClass();
aic.Method();
}
}
匿名内部类对于接口和抽象方法的实现也是跟上面差不多。实现抽象方法重写时,不需要在里面用abstract修饰。
四、静态内部类。
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。
静态内部类的创建不依赖外部类。使用static来修饰一个内部类,则这个内部类就属于外部类本身,而不属于外部类的某个对象,不需要依赖外部类。静态内部类不能访问外部类的非静态成员和非静态方法。因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。