目录
一、嵌套类基础
嵌套类:一个类定义在别的类得内部。
如:
//文件名B.java
//A类在B类中定义,嵌套
public class B {
class A {
}
}
静态嵌套类:即类前有static修饰符
扫描二维码关注公众号,回复:
11067962 查看本文章
非静态嵌套类:又名内部类。可分普通内部类,局部内部类,匿名内部类。
优点:
- 不同得访问权限要求,更细粒度得访问控制
- 简洁,避免过多得类定义
缺点:
- 语言设计更加复杂,较难掌握和使用
二、静态嵌套类:
注意区分于静态类:只有静态方法和属性,并且用static修饰。
静态嵌套类:
- 层级和包围类的成员变量/方法一样
- 第三方需要外部包围类才可以访问静态嵌套类格式:外部包围类名.静态嵌套类名
- 需要static修饰
- 可以定义静态成员和非静态成员
- 不能访问包围类的非静态变量,客以访问包围类的静态成员,可以通过包围类的对象进行访问非静态成员
- 外界可以通过静态嵌套类名访问静态成员,通过对象访问其非静态成员
- 外界需要通过包围类才可以访问到静态嵌套类,并创建其对象,不需要外部包围类的实例
public class Outer1 {
String name;
// 静态嵌套类
static class Inner1 {
String name;
}
}
三、普通内部类:
普通内部类:
- 非static类,定义外某个类的成员变量的位置
- 定义后,在类里面都可以使用
- 编译后名称为:外部类名+$+内部类名
- 可以继承其他的继承或者实现其他的接口
- 可以用private/default(不写)/protected/public控制外界控制
- 非静态类,不能实现静态变量/方法,常量除外
- 和外部包围类的实例相关,一个普通内部类实例肯定是在一个外部包围类始终中,且可以访问外部包围类的所有成员
- 在第三方类中,需要先创建外部包围类实例,才能创建普通内部类实例,不允许单独的普通内部类存在
public class Outer2 {
String name;
//普通内部类/成员内部类
public class Inner2 {
String name;
}
}
举例:
public abstract class Animal {
public abstract void eat();
}
public interface Flyable {
public void fly();
}
public class Outer3 {
String name = "aaaaaa";
public class Bird extends Animal implements Flyable {
public static final int a=3; //常量OK
//public static int b = 4; //error
public void fly() {
System.out.println("I can fly " + name);
}
public void eat() {
System.out.println("I can fly");
}
}
public Bird obj = new Bird();
public void f1() {
obj.fly();
System.out.println(obj.getClass().getName());
this.name = "bbbbbb";
obj.fly();
}
public Bird getBird()
{
return this.obj;
}
}
public class Outer3Test {
public static void main(String[] args) {
Outer3 foo1 = new Outer3();
foo1.f1();
Outer3.Bird foo2 = foo1.new Bird();
foo2.fly();
System.out.println(foo2 == foo1.getBird());
//foo1对象下,有2个内部类对象和它关联
//不允许没有关联的单独的普通内部类对象,会报错
//Outer3.Bird foo3 = foo1.new Outer3.Bird();
}
}
四、局部内部类
局部内部类:
- 定义在代码块中的非静态类,如方法,for循环,if语句等
- 定义后创建对象即可使用
- 只能活在定义的这个代码块中,代码块结束后,外界将无法使用该类。
- 编译后名称为:外部类名+$+序号+内部类名
- 可以继承其他类,或者实现其他接口
- 非静态类,不能实现静态变量/方法,常量除外
- 可以访问外部包围类成员变量,访问格式:包围类名.this.变量名
- 如果定义在静态方法中,则只能访问包围类的静态成员
- 不能是一个接口,即接口不能定义在代码中。
public class Outer3 {
String name;
//局部内部类
public void f1() {
class Inner3 {
String name;
}
}
}
五、匿名内部类:
匿名内部类:
- 没有类名得内部类,必须继承一个父类/继承一个父接口;
- 在实例化之后,迅速转型为父类/父接口;
- 这种类型得对象,只能new一个对象,之后以对象名字操作;
- 可以在普通语句和成员变量赋值时使用内部类。
- 可以继承、改写,补充父类、父接口的方法;
- 没有正式的类名,编译器产生的内部名字为:类名+$+数字变号。
注意:
- 匿名内部类不可以含静态变量和方法(常量除外);
- 访问外围变量需要以格式:“类名.this.变量名”来访问;
- 若匿名内部类定义在静态方法内,只能访问外围得的静态变量;
- 不可以重用,即使两个相同匿名内部类的语句实例化出来的类和对象都不一样。
示例:
Runable()是接口,不可以new,所以new了之后加了run()方法,类定义后无名字称为匿名内部类。
一般使用在只使用一次得场合中。
public class Outer4 {
String name;
//匿名内部类
public void f1() {
new Thread(new Runnable() {
public void run()
{
System.out.println("hello");
}
}).start();
}
}
六、嵌套类对比:
静态嵌套类:在一个类中定义,可重复使用,并需要访问外部类的静态成员。
普通内部类:和局部内部类类似,在一个类中定义,可重复使用,可以访问外部类的成员,但不需要访问外部类方法的形参和内部变量。
局部内部类:在一个方法内,需要创建一个新的类型,并且重复使用
匿名内部类:如果需要定义额外的变量和方法
七、嵌套类的应用场景
匿名内部类:android开发中常用匿名内部类实现监听。
普通内部类:广泛使用在具有母子结构的类总,内部类对象和外围对象保持紧密联系。
局部内部类:继承某一个类或接口,重新定义方法,并当作返回值在外部使用。
静态嵌套类:感觉和普通类一致,和外围类没有太多的联系,可以脱离外围对象存在,也可以访问外围类的静态成员。普通内部类可以访问外部所有的成员。所以一般用普通内部类就可以了,如果不需要访问外围类的非静态成员,则使用静态嵌套类,因为可以节省普通内部类和外围类的联系开销。
参考中国大学mooc《java核心技术》