概要
在平时的编程中,用的最多的内部类就是点击事件和Handler的使用。这个点,已经没心思遍题记这种废话了。直接切入主题上重点笔记吧:
1.当生成一个内部类对象的时候(静态类除外),此对象与制造它的外围对象之间就有了一种联系,所以它能够访问外围类的成员,而且不需要任何特殊条件。此外,内部类还拥有其外围成员的所有元素的访问权限,外围类也是可以直接访问内部类的private和protected修饰的变量和方法。
2.如何创建一个内部类?具体代码如下:
class OuterClass{//外围类
class InnerClass{//内部类
}
OuterClass out = new OuterClass();
OuterClass.InnerClass = out.new InnerClass();//我们需要先初始化外围对象,然后再out.new InnerClass();初始化新的对象。
}
通过上面的代码我们可以知道在创建内部类的时候(静态类除外),我们必须持有一个外围类对象,这是因为我们的内部类能够访问外围类的方法与变量。
3.如果一个内部类是静态的(这时候这个内部类叫嵌套类),它是不需要外围类引用的,因为这个静态内部类类是跟外围类关联的 ,而不是跟外围类的对象关联的。我们在创建静态内部类的时候,就不需要外围类的对象了。
4.我们可以覆盖父类的内部类。
5.在方法和作用域中也可以创建内部类。他们的理由是:
- 你实现了某个类型的接口,于是可以创建并返回对其的引用。
- 你要解决一个复杂的问题,先创建一个辅助你的解决办法,但是又不希望这个类是可以公用的。
6.下面将介绍几种内部类:
- 在方法中定义的类:
在方法中创建的类,他编译也会产生一个class文件,格式是A 1MethodClass.class。也就是类名+′ ’号+方法编号+内部类的方式。值得注意的是在Point 1处我们有一个if判断语句,表面上看,我们的MethodClass可能用不到,所以它不会编译,但实际上,方法中和作用域的内部类在一开始就编译了。
class A{
public void display(){
if(true){// point 1
class MethodClass{//我们在方法中创建了一个类
}
}
}
}
- 匿名内部类:
所谓的匿名内部类,其实也就是在方法或者作用域内创建一个没有名字的类,因为匿名内部类不能有构造函数,所以匿名内部类的重点部分是数据的初始化,我们将分为几个版本来介绍。具体代码如下:
<b>第一个版本,接口的匿名内部类</b>
interface Contents{
int value();
}
public class Paracel{
public Contents contents(){
return new Contents(){//我们直接new一个接口就行了
private int i = 11;//值得注意的是,我们可以直接在内种定义并且初始变量
public void int value(){return i;}
}
}
}
<b>第二个版本,没有默认构造器的类的匿名内部类</b>
public class Wrapping{
private int i;
public Wrapping(int x){//我们的这个类只有一个带参数的构造函数
i = x;
}
public int value(){return i;}
}
public class Paracel{
public Wrapping wrapping(int x,final y){
return new Wrapping(x){
{print("Inside instance initializer");//我们可以用这种方式充当匿名内部类
}
private String yValue = y;//我们也可以初始化值,但是值得注意的是,从匿名内部类引入外部的值,必须是final的,如果是构造器函数的,就不需要了。这是因为这个方法的生命周期比匿名内部类要短,方法返回后,堆栈的值就清空的,所以传入的这个值实际上是重新复制了一遍到匿名内部类中,为了不要让其值被修改而产生误会,所以使用了fianl这种方式。但对于构造器的传值,他并不会在匿名内部类内部被直接使用。
public int value(){
return super.value;
}
}
}
}
- 匿名内部类只能实现一个接口或者一个类。
- 嵌套类就是static修饰的内部类,他不会持有外部类的引用,所以我们不能访问外围内的非静态变量或者方法,嵌套类的private方法和字段是可以被外围类访问的。普通内部类和外围类有一个区别就是:普通的内部类不能持有static数据和方法,但是嵌套类是可以持有static方法和变量的。为什么普通内部类不能持有静态变量或者方法:
静态变量是要占用内存的,在编译时只要是定义为静态变量了,系统就会自动分配内存给他,而内部类是在宿主类编译完编译的,也就是说,必须有宿主类存在后才能有内部类,这也就和编译时就为静态变量分配内存产生了冲突,因为系统执行:运行宿主类->静态变量内存分配->内部类,而此时内部类的静态变量先于内部类生成,这显然是不可能的,所以不能定义静态变量!
7.接口中的内部类:如果你想要创建某些公用代码,是的他们可以被某个接口的所有不同实现所共同,那么使用内部的嵌套类会显得很方便。值得注意的是,我们放在接口中的任何类都强制成为public static类型的。接口中定义类的示例代码如下:
interface A{
class Test{//注意这里强制成为public static类型的
public void display(){
}
}
}
8.内部类的存在,让我们有效的实现了多重继承。
9.闭包是一个可调用的对象,它记录了一些信息,这些信息来源于创建它的作用域。我们的内部类就是典型的闭包:内部类持有当前作用域外围对象的方法访问和变量访问权限。下面是示例代码:
public class Main {
public static void main(String[] args) {
OuterClass1 outerClass1 = new OuterClass1();
OuterClass1.InnerClass innerClass = outerClass1.new InnerClass();
innerClass.show();//我们通过内部类,能调用它外围类的接口。记得我们闭包的定义:一个对象记录了一些信息,这些信息来源于创建它的作用于,这个作用于就是外围类的方法和变量了。
}
}
class OuterClass1 {
void display() {
}
class InnerClass {
void show() {//这就是闭包的使用了,这个内部类能调用外围类的变量和方法
display();
}
}
}
10.继承一个内部类,必须在构造器中指明外围类对象,但如果一个类中的内部类继承了父类的内部类,那么它的方法调用和构造函数的写法跟正常继承是一样的,在构造函数并不用传入外围类对象,这是因为这个内部类的外围类已经持有了继承内部类父类的对象了(继承关系,子类会持有父类的一个对象)。具体代码示例如下:
//这种情况下描述的是内部类继承非外围类父类的内部类。
class WithInner{
class Inner{}
}
public class InheritInner extends WithInner.Inner{
IheritInner(WithInner wi){//这里我们的构造器必须有外围类对象这个参数
wi.super();//调用super方法
}
}
//这种情况下描述的是内部类继承外围类父类的内部类
class OuterClass1 {
void display() {
}
class InnerClass {
void show() {
display();
}
}
}
class OuterClass2 extends OuterClass1{
class InnerClass1 extends OuterClass1.InnerClass{
}
}
11.一个类如果重写一个跟父类内部类一模一样的类,它并不会覆盖这个类,他们两个类有各自的命名空间。
12.局部内部类是不能使用访问说明符的,我们使用局部内部类而不使用匿名内部类的唯一理由就是:需要不止一个该类的内部类。
13.内部类生成class文件的命名规范:
- Counter.class 外围类
- LocalInnerClass$1.class匿名内部类
- LocalInnerClass$1LocalCounter.class 局部内部类
14.为什么需要内部类?实际上我们的接口也可以实现内部类的功能。内部类和接口一样,都是为了解决多重继承的问题,但是内部类能够处理的更加好一些。在某些情况下,我们必须是要用内部类才能完成多重继承的:
interface A{}
interface B{}
//examples 1
Class CA implements A,B{//我们可以通过直接继承实现内部类
}
//examples 2
Class InnerA implements A{
B getB(){//在这里,我们通过内部类实现多重继承
return new B(){};
}
}
//然而,如果出现这种情况,没有内部类我们是无能为力的:
abstract AA {}//这里有两个类,我们怎么多重继承?
class BB{}
Class InnerB extends AA{
AA getAA(){
return new AA(){};
}
}
我们如何选择是使用接口还是内部类?一般情况下,能直接用继承多个接口解决的多重继承,我们就直接用接口。因为接口用起来简单