Java内部类
- 内部类:在类中定义的类,外面的类叫外部类,里面的类叫内部类
- 作用:为了更加精确的描述现实中的一类事物,例汽车内部的发动机类
- 根据有无static修饰可以分为静态内部类和非静态内部类:
- 非静态内部类对象的创建:内部类 内部类对象名 = 外部类对象名.new 内部类();
- 静态内部类:静态内部类只能直接访问外部类的静态成员变量和方法,但是可以通过创建外部类的对象间接使用外部类的非静态的成员变量和方法。静态内部类对象的创建格式:内部类 内部类对象名 = new 内部类();
- 例:
public class Outter { class InnerA{ //非静态内部类 } static class InnerB{ //静态内部类 } public static void main(String[] args) { Outter out = new Outter(); //非静态内部类对象的创建需要借助外部类对象 InnerA ina = out.new InnerA(); //下面静态内部类对象的创建实际上是:InnerB inb = new Outter.InnerB(); InnerB inb = new InnerB(); } }
- 非静态内部类又分为普通内部类和匿名内部类
- 普通内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员),但是外部类如果要访问内部类中的属性和方法必须先创建一个内部类对象,通过内部类对象来调用,其定义格式如下:
class Outter { class Inner{ } }
- 匿名内部类由于没有类名而不能单独存在,定义匿名内部类的同时须直接实例化该类,匿名内部类能够在实现父类或者接口中的方法情况下同时产生一个相应的对象,其对象的创建格式为:new 接口/父类构造器(){ @Override… }; 例:
public class Outter { public static void main(String[] args) { IAnimal animal = new IAnimal() { public void sleep() { System.out.println("睡觉。。。"); } @Override public void eat(String name, String food) { System.out.println(name + "在吃" + food); } }; animal.eat("张飞", "豆芽"); } }
- 上例创建了一个实现了IAnimal接口的类,但是该类没有名字,该类需要重写IAnimal接口的所有抽象方法,并且可以自定义添加其他方法或属性
- 匿名内部类没有构造方法,当然也不能自定义构造方法
- 匿名内部类一定不能是抽象类;
- 可以在匿名内部类中添加新的属性和方法,但是这些属性和方法不能被上转型对象所调用,只能被非上转型对象方式创建的匿名内部类对象所调用,例如在上例中animal不能调用匿名内部类的sleep方法,匿名内部类中自定义的属性和方法只能通过以下方法调用:
public class Outter { public static void main(String[] args) { new IAnimal() { public void sleep() { System.out.println("睡觉。。。"); } @Override public void eat(String name, String food) { System.out.println(name + "在吃" + food); } }.sleep(); //只能在创建内部类时调用 } }
- 从上例可以看出同一个匿名内部类对象只能调用一个新增的属性或方法,无法再调用实现的抽象方法、重写的方法或继承的方法,也无法调用继承的属性,因此创建匿名内部类通常不自定义添加属性和方法
- 内部类与外部类的权限:内部类可以直接定义在类中,也可以定义在方法或代码块中
- 其中直接定义在外部类中的内部类可以有public、protected、默认的和private四种访问权限修饰(普通外部类、接口和抽象类只能使用public和default修饰),也可以使用static修饰( static不能修饰普通外部类、接口和抽象类)
- 但是定义在方法或代码块中的内部类不能有访问修饰符修饰,也不能有static修饰
- 普通内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员),但是外部类如果要访问内部类中的属性和方法必须先创建一个内部类对象,通过内部类对象来调用,其定义格式如下: