将一个类定义放在另一个类的定义内部,这就是内部类。
1、创建内部类对象方法,假设有一个外部类Outer,其中有一个内部类Inner。
(1)在外部类中,提供创建并返回内部类对象的方法,方法名可以和内部类名字相同(首字母小写),
如:
public void inner() {
return new Inner();
}
(2)先创建外部类对象,然后使用外部对象.new的方式创建内部类。
如:
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner()
2、内部类 和 其构造方法都支持所有的访问修饰符,并受到访问控制。(和普通的成员变量 和 普通方法一样)
(1)内部类默认的是包访问。如果在和定义不同的包中使用Outer.Inner声明变量,就会提示无法访问Inner。
(2)内部类的缺省构造方法默认的是包访问。如果在和定义不同的包中使用outer.new Inner(),则会提示构造函数无法访问。
(第一种创建方式是不是更简单呢)
3、链接到外部类
(1)内部类可以访问外部类所有成员,因为内部类默认存在一个指向外部类的引用。
(2)如果需要在内部类内部返回此引用,可以使用外部类.this 返回。
(3)外部类可以创建内部类对象,通过此对象直接访问内部类所有成员(包括private)。
4、私有内部类 + 向上转型 = 完全隐藏实现。(获取到对象后,想要向下转型为内部类都是不能的)
(1)提供一个public接口。
(2)创建一个private内部类实现此接口。
(3)外部类提供一个返回内部类对象的方法,返回值向上转型为public接口。
5、方法和作用域内的内部类
没有访问修饰符,直接受作用域控制,和局部变量类似。即:超出作用域,则无法访问。
6、匿名内部类
(1)没有单独的class关键字定义,只能在创建对象的地方,同时定义匿名内部类。
对象的创建(成员变量 或者 方法的局部变量)绑定类的定义,一次性的。
(2)创建并定义匿名类对象方法
a. 依靠继承一个父类(可以是抽象的),覆写父类方法。使用父类的构造方法(可以带参数)创建对象。
b. 依靠实现一个接口,实现接口方法。使用缺省的构造方法创建对象。
(3)因为创建匿名内部类的对象,返回时向上转型为父类或者接口,因此在匿名内部类定义中,即使加入public的新方法也无法使用。
(4)匿名内部类,没有名字,没有办法自己定义构造方法,可以使用实例代码块代替,只是不能重载。
(5)匿名内部类内部使用一个外部定义的对象引用,则编译器要求加上final,不能修改。(JDK8 不用手动添加,编译器会默认加上)
(6)工厂方法模式可以加入匿名内部类,减少工厂实现类的编写。
a、新建产品类接口。
b、新建工厂类接口,包括获取产品的方法 getXXX。
c、创建产品类实现,其中:
产品类的构造方法变为私有。(只能工厂创建)
产品类新增公共静态属性factory,并使用匿名内部类定义。(代替工厂实现类)
7、嵌套类 又称 静态内部类
使用static修饰,嵌套类中没有指向外部对象的引用。因此
(1)创建嵌套类时(第2种创建内部类的方法),不需要先创建外部类对象。如:Outer.Inner inner = new Outer.Inner();
(2)嵌套类不能访问非静态的外部对象或方法。
(3)普通内部类不能有静态属性和方法,包含嵌套内部类。但嵌套类可以。
(4)接口中放入内部类,默认会加上public static,也就是嵌套类。
a、如果要创建公共代码,使得他们可以被某个接口的所有不同实现所共有,那么用接口嵌套类更加方便。
b、接口的实现可以像普通类一样,创建嵌套类对象,如Inner inner = new Inner()
8、为什么需要内部类
(1)每一个内部类都可以独立继承或实现一个类或接口。和外围类的继承,实现没有关系。因此可以实现多继承。
(2)内部类是面向对象的闭包,方便回调。
a. 闭包是一个可调用的对象,他记录了一些信息,这些信息来自于创建它的作用域。闭包不仅包含方法 还有数据(上下文)。因此内部类是面向对象的闭包。
b. 回调,即回头再调用的意思,"通过回调,对象能够携带一些信息,这些信息允许他在稍后的某个时刻调用初始的对象。"
简单说,可以先用组合 将对象A存于另一个对象B中(如:成员变量),等待适合条件再调用A的方法或属性。
按照上面定义,普通的类也可以作为回调对象,而使用内部类的好处在于,内部类虽然可以访问外部类的所有资源,但是可以只公布少量回调要用的方法。
(3)隐藏实现细节。
(4)可以任意访问外部类成员。
9、内部类的继承
当一个类继承内部类时,就拥有了内部类的特性,需要有一个指向外部类的引用。
(1)此导出类构造器增加外部类引用作为形参。
(2)导出类构造器内通过外部类引用.super()建立连接。(类似调用基类的构造函数super())
(3)如果基类是带参数构造器,则调用外部类引用.super(实参) 建立连接。
10、内部类不能被覆盖
11、使用局部内部类(方法中的内部类等)而不是用匿名内部类的原因,需要不止一个该内部类的对象。(匿名内部类创建和定义绑定,是一次性的)
12、内部类标识$,可以有多层内部类 Outer$Inner1$Inner2$Inner3
来源:https://www.cnblogs.com/shineon/p/11453113.html