内部类(内置类、嵌套类)
定义:指将一个类的定义放在另一个类的定义内部。
分类:静态内部类、成员内部类、局部内部类、匿名内部类。
特点
1)一个内部类对象可以访问创建它的外部类对象的内容,包括私有数据!
2)内部类不为同一包的其他类所见,具有很好的封装性;
3)内部类有效实现了“多重继承”,优化 java 单继承的缺陷。
4)匿名内部类可以很方便的定义回调。
5)外部类不能直接使用内部类属性,不能直接调用内部类的方法。外部类要访问内部类的成员,必须要建立内部类的对象,通过内部类对象类调用内部类资源。
6)内部是编译时的概念,一旦编译成功,内部类和外部类就会成为两个完全不同的类。
在java 里任何一个类,无论是以怎样的形式定义,在编译之后生成字节码文件之后,其必然是一个单独存在的类。
java加载任何一个类的时候都是会首先从加载其class文件开始,若一个类不存在对应的class文件,那么它必然无法被加载也无法被使用。
因此,内部类的成员变量/方法名可以和外部类的相同
7)内部类可以被继承,也可被覆盖。
静态内部类
不常用。(浪费内存)
定义:指在类内部的静态类。
特点:
static 修饰类只能修饰内部类。
静态内部类可以访问外部类所有的静态变量,不可访问外部类的非静态变量,但可以通过new 外部类().成员的方式访问。
举例 :
public class Outer {
//定义外部类的成员变量
int i = 1;
//定义 静态内部类
public static class Inner {
//定义内部类的成员变量
int i = 2;
//静态内部类的方法
public void visit() {
//通过new 外部类().成员的方式访问外部类的非静态变量
System.out.println("visit outer variable:" + new Outer().i);
System.out.println("visit inner variable:" + i);
}
}
public static void main(String[] args) {
//创建静态内部类的对象时,不需要外部类的对象,可以直接创建
//创建外部类对象
//Outer o = new Outer();
//不可以写成Inner i = o.new Inner(); 因为是静态内部类,不是成员内部类
Inner i = new Inner();
//通过内部类对象调用内部类方法
i.visit();
}
}
结果:
成员内部类(普通内部类)
定义:指在类内部,成员位置上的非静态类。
特点:
可以使用任意访问修饰符,如:public、private、protected等。
成员内部类可以访问外部类所有的变量和方法,包括静态和非静态,私有和公有,即不受访问修饰符影响。
普通内部类对象依赖外部类对象而存在,即在创建一个普通内部类对象时首先需要创建其外部类对象
举例:
public class Outer {
private static int radius = 1;
private int count =2;
//成员内部类
class Inner {
public void visit() {
System.out.println("visit outer static variable:" + radius);
System.out.println("visit outer variable:" + count);
}
}
public static void main(String[] args) {
//在创建内部类Inner对象时,要首先创建外部类Outer对象,不可以直接new一个内部类对象
//外部类要想访问内部类的成员,必须创建对象访问。
Outer o = new Outer();
//下面这一步也可以写成:Outer.Inner i = o.new Inner();
//内部类 对象名 = 外部类对象.new 内部类( );
Outer.Inner i = o.new Inner();
i.visit();
}
}
结果:
局部内部类(方法内部类)
定义:局部内部类定义在外部类的方法中,只在该方法内可以用;
特点:
定义在实例方法中的局部类可以访问外部类的所有变量和方法
定义在静态方法中的局部类只能访问外部类的静态变量和方法。
不能使用访问控制符和static修饰符,因为局部类不能在外部类的方法以外的地方使用。
举例:
//外部类
public class Outer {
private int outer_a = 1; //外部类的私有成员变量
private static int STATIC_b = 2; //外部类的静态 私有成员变量
//外部类中的普通方法
public void testFunctionClass(){
int outer_c =3; //外部类中的变量
//局部内部类(方法内部类)
class Inner {
int inner_d = 4; //局部内部类中的变量
private void visit(){
System.out.println("outer_a:" + outer_a);
System.out.println("STATIC_b:" + STATIC_b);
System.out.println("outer_c:" + outer_c);
System.out.println("inner_d:" + inner_d);
}
}
//创建方法内部类中的对象
Inner i = new Inner();
//调用方法内部类中的方法
i.visit();
}
//外部类中的静态方法
public static void testStaticFunctionClass(){
int outer_d =5; //局部内部类中的变量
class Inner {
private void visit(){
//System.out.println("outer_a:" + outer_a); 编译错误,定义在静态方法中的局部类不可以访问外部类的实例变量
System.out.println("STATIC_b:" + STATIC_b);
System.out.println("outer_d:" + outer_d);
}
}
//创建方法内部类中的对象
Inner i = new Inner();
//调用方法内部类中的方法
i.visit();
}
public static void main(String[] args) {
//创建外部类的对象
Outer o = new Outer();
//调用外部类的方法
//o.visit();错误,编译不通过
o.testFunctionClass();
o.testStaticFunctionClass();
}
}
结果:
匿名内部类
常用。
定义:没有名字的内部类。
特点:
1)没有访问修饰符
2)没有构造方法
3)定义匿名内部类的前提是,内部类必须是继承一个类或者实现接口,格式为new 父类 / 接口(){ //匿名内部类实现部分 )}
。
也就是说,匿名内部类最终提供给我们的是一个匿名子类的对象
举例:
public class Outer {
public Outer() {
//this.getClass().getSimpleName()方法以String的形式返回此类的简单名称。如果此类是匿名的,则此方法返回空字符串。
System.out.println("创建 " + this.getClass().getSimpleName() + " 对象");
}
// 自定义接口
interface Interface01 {
void visit(Object obj);
}
//创建一个实现类,书写visit()方法的具体实现过程
// public class Interface01Impl implements Interface01{
// @Override
// public void visit() {
// System.out.println("I'm a impl class...");
// }
// }
private void anonymousClassTest() {
//如果实现类Interface01Impl全程只使用一次,为了这一次的使用去创建一个类过于麻烦
// 在这个过程中会新建一个匿名内部类对象,
// 这个匿名内部类实现了 Interface01 接口并重写 visit 方法
Interface01 interface01 = new Interface01() {
// 可以在内部类中定义属性,但是只能在当前内部类中使用,
// 无法在外部类中使用,因为外部类无法获取当前匿名内部类的类名,
// 也就无法创建匿名内部类的对象
int i = 1;
@Override
public void visit(Object obj) {
System.out.println("对象 " + obj + " 被访问");
}
};
// new Object() 过程会新建一个匿名内部类,继承于 Object 类,
// 并重写了 toString() 方法
interface01.visit(new Object() {
@Override
public String toString() {
return "obj1";
}
});
}
public static void main(String[] args) {
Outer o = new Outer();
o.anonymousClassTest();
}
}
结果: