javanew⼀个内部类_java内部类
java内部类的⼏种类型:成员内部类,静态内部类,⽅法内部类,匿名内部类。
成员内部类:成员内部类是类内部的⾮静态类。成员内部类不能定义静态⽅法和变量(final修饰的除外)。这是因为成员内部类是⾮静态的,类初始化的时候先初始化静态成员,如果允许成员内部类定义静态变量,那么成员内部类的静态变量初始化顺序是有歧义的。例⼦如下:
运⾏结果为:访问外部类中的a:99,访问内部类中的b:2
成员内部类的使⽤⽅法:
1、 Inner 类定义在 Outer 类的内部,相当于 Outer 类的⼀个成员变量的位置,Inner 类可以使⽤任意访问控制符,如 public 、protected 、 private 等
2、 Inner 类中定义的 test() ⽅法可以直接访问 Outer 类中的数据,⽽不受访问控制符的影响,如直接访问 Outer 类中的私有属性a
3、 定义了成员内部类后,必须使⽤外部类对象来创建内部类对象,⽽不能直接去 new ⼀个内部类对象,即:内部类 对象名 = 外部类对象.new 内部类( );
4、 编译上⾯的程序后,会发现产⽣了两个 .class ⽂件
其中,第⼆个是外部类的 .class ⽂件,第⼀个是内部类的 .class ⽂件,即成员内部类的 .class ⽂件总是这样:外部类名$内部类名.class
另外,友情提⽰哦:
1、 外部类是不能直接使⽤内部类的成员和⽅法滴。如:
那么外部类如何使⽤内部类的成员和⽅法呢??
答:可先创建内部类的对象,然后通过内部类的对象来访问其成员变量和⽅法。
Java 编译器在创建内部类对象时,隐式的把其外部类对象的引⽤也传了进去并⼀直保存着。这样就使得内部类对象始终可以访问其外部类对象,同时这也是为什么在外部 类作⽤范围之外向要创建内部类对象必须先创建其外部类对象的原因。
2、 如果外部类和内部类具有相同的成员变量或⽅法,内部类默认访问⾃⼰的成员变量或⽅法,如果要访问外部类的成员变量,可以使⽤this 关键字。如:
运⾏结果:
静态内部类:静态内部类是 static 修饰的内部类,这种内部类的特点是:
1、 静态内部类不能直接访问外部类的⾮静态成员,但可以通过new 外部类().成员 的⽅式访问。
2、 如果外部类的静态成员与内部类的成员名称相同,可通过“类名.静态成员”访问外部类的静态成员;如果外部类的静态成员与内部类的成员名称不相同,则可通过“成员名”直接调⽤外部类的静态成员。
3、 创建静态内部类的对象时,不需要外部类的对象,可以直接创建 内部类 对象名= new 内部类();
运⾏结果 :
⽅法内部类:⽅法内部类就是内部类定义在外部类的⽅法中,⽅法内部类只在该⽅法的内部可见,即只在该⽅法内可以使⽤。
⼀定要注意哦:由于⽅法内部类不能在外部类的⽅法以外的地⽅使⽤,因此⽅法内部类不能使⽤访问控制符和 static 修饰符。
匿名内部类:匿名类是不能有名称的类,所以没办法引⽤他们。必须在创建时,作为new语句的⼀部分来声明他们。
但使⽤匿名内部类还有个前提条件:必须继承⼀个⽗类或实现⼀个接⼝。
这就要采⽤另⼀种形式 的new语句,如下所⽰:
new
java接口可以创建对象吗这种形式的new语句声明⼀个 新的匿名类,他对⼀个给定的类进⾏扩展,或实现⼀个给定的接⼝。他还创建那个类的⼀个新实例,并把他作为语句的结果⽽返回。要扩展的类和要实现的接⼝是
new语句的操作数,后跟匿名类的主体。
注意匿名类的声明是在编译时进⾏的,实例化在运⾏时进⾏。这意味着
for循环中的⼀个new语句会创建相同匿名类的⼏个实例,⽽不是创建⼏个不同匿名类的⼀个实例。
从技术上说,匿名类可被视为⾮静态的内 部类,所以他们具备和⽅法内部声明的⾮静态内部类相同的权限和限制。
假如要执⾏的任务需要⼀个对象,但却不值得创建全新的对象(原因可能 是所需的类过于简单,或是由于他只在⼀个⽅法内部使⽤),匿名类就显得很有⽤。匿名类尤其适合在Swing应⽤程式中快速创建事件处理程式。以下是⼀个匿名内部类的实例:
1、匿名内部类的基本实现:
运⾏结果:
可以看到,我们直接将抽象类Person中的⽅法在⼤括号中实现了,这样便可以省略⼀个类的书写,并且,匿名内部类还能⽤于接⼝上。
2、在接⼝上使⽤匿名内部类:
运⾏结果:
由上⾯的例⼦可以看出,只要⼀个类是抽象的或是⼀个接⼝,那么其⼦类中的⽅法都可以使⽤匿名内部类来实现。
在使⽤匿名内部类的过程中,我们需要注意如下⼏点:
1、使⽤匿名内部类时,我们必须是继承⼀个类或者实现⼀个接⼝,但是两者不可兼得,同时也只能继承⼀个类或者实现⼀个接⼝。
2、匿名内部类中是不能定义构造函数的。
3、匿名内部类中不能存在任何的静态成员变量和静态⽅法。
4、匿名内部类为局部内部类(即⽅法内部类),所以局部内部类的所有限制同样对匿名内部类⽣效。
5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接⼝的所有抽象⽅法。
匿名内部类重点难点:
1. 如果是在⼀个⽅法的匿名内部类,可以利⽤这个⽅法传进你想要的参数,不过记住,这些参数必须被声明为final 。
使⽤的形参为何要为final??
我们给匿名内部类传递参数的时候,若该形参在内部类中需要被使⽤,那么该形参必须要为final。也就是说:当所在的⽅法的形参需要被内部类⾥⾯使⽤时,该形参必须为final。
⾸先我们知道在内部类编译成功后,它会产⽣⼀个class⽂件,该class⽂件与外部类并不是同⼀class⽂件,仅仅只保留对外部类的引⽤。当外部类传⼊的参数需要被内部类调⽤时,从java程序的⾓度来看是直接被调⽤:
public class OuterClass {
public void display(final String name,String age){
class InnerClass{
void display(){
System.out.println(name);
}
}
}
}
从上⾯代码中看好像name参数应该是被内部类直接调⽤?其实不然,在java编译之后实际的操作如下:
public class OuterClass$InnerClass {
public InnerClass(String name,String age){
this.InnerClass$name = name;
this.InnerClass$age = age;
}
public void display(){
System.out.println(this.InnerClass$name + "----" + this.InnerClass$age );
}
}
所以从上⾯代码来看,内部类并不是直接调⽤⽅法传递的参数,⽽是利⽤⾃⾝的构造器对传⼊的参数进⾏备份,⾃⼰内部⽅法调⽤的实际上时⾃⼰的属性⽽不是外部⽅法传递进来的参数。
直到这⾥还没有解释为什么是final。在内部类中的属性和外部⽅法的参数两者从外表上看是同⼀个东西,但实际上却不是,所以他们两者是可以任意变化的,也就是说在内部类中我对属性的改变并不会影响到外部的形参,⽽然这从程序员的⾓度来看这是不可⾏的,毕竟站在程序的⾓度来看这两个根本就是同⼀个,如果内部类该变了,⽽外部⽅法的形参却没有改变这是难以理解和不可接受的,所以为了保持参数的⼀致性,就规定使⽤final来避免形参的不改变。
简单理解就是,拷贝引⽤,为了避免引⽤值发⽣改变,例如被外部类的⽅法修改等,⽽导致内部类得到的值不⼀致,于是⽤final来让该引⽤不可改变。
故如果定义了⼀个匿名内部类,并且希望它使⽤⼀个其外部定义的参数,那么编译器会要求该参数引⽤是final的。
2. 匿名内部类中使⽤初始化代码块