长大后想做什么?做回小孩!

0%

局部内部类&匿名内部类

局部内部类又称方法内部类,顾名思义就是定义在方法体内的类。

局部内部类只又在方法中可见,即只能在该方法中使用。

局部内部类:

局部内部类不能用static、public、protect、private修饰。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Outter {

//外部类方法
public void Outter_show(){
int a = 11;//外部类成员变量
int b = 22;//外部类成员变量

//方法内部类
class Inner{
int b = 33;//内部类成员变量
//内部类方法
public void Inner_show(){
System.out.println(a);
System.out.println(b);
}
}
//创建内部类对象,调用内部类方法
new Inner().Inner_show();
}

public static void main(String[] args) {
Outter outter = new Outter();
outter.Outter_show();
}//运行结果:11
} // 33

实际应用中,可能需要在内部类外部调用成员内部类,但是由于外部类不能访问内部类,所以只能使用返回内部类的父类或者接口的形式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Outter {
//外部类方法,因为外部类不能访问内部类
//所以通过父类或者接口的方式返回
public Runnable getInner(){
//方法内部类
class Inner implements Runnable{
@Override
public void run() {
System.out.println("I'm Inner....");
}
}
return new Inner();
}

public static void main(String[] args) {
//创建外部类对象,调用外部类方法返回内部类
Runnable runnable = new Outter().getInner();
runnable.run();
}//运行结果:I'm Inner....
}

匿名内部类:

swing应用程序编程时添加监听器、初始化新线程时。。。经常会用到匿名内部类。

无论是继承父类还是实现接口,实际上拿到的是父类或者接口的引用,这个引用指向由匿名内部类定义的类的实例。这个被继承的父类或者接口必须是实际存在的。

栗子:

1
2
3
4
5
6
7
8
9
10
11
//用GUI编程时常见的添加事件监听器的代码为例
//匿名实例
// 添加鼠标监听事件
button.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被点击");
}

});

匿名内部类在使用时的编写方式不同又可以分为匿名实例匿名类实例,上述代码就是匿名实例,下面介绍匿名类实例的方式。

1
2
3
4
5
6
7
8
9
10
11
//匿名类实例
//同样使用添加鼠标监听事件
ActionListener listener = new ActionListener(){

@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被点击");
}

}
button.addActionListener(listener);

两者的区别和应用场景显而易见,不再赘述。


匿名内部类的目的和应用场景:

1.解决抽象类和接口不能实例化对象,有时候没必要特意去编写一个类去实现接口中的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//以接口用匿名内部类为例
//抽象类用匿名内部类方法一样
interface Animal{
public abstract void run();
}

class test(){
public static void main(String[] args){
Animal animal = new Animal(){
@Override
public void run(){
System.out.println("跑了。。。。");
}
}
animal.run();
}//运行结果:跑了。。。。

2.当接口或者抽象类作为参数时,用匿名内部类来实例化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
interface Fruit{
public void plant();
public String getName();
}

class Farmer{
public void plant(Fruit fruit){
fruit.plant();
}
}

class test{
public static void main(String[] args){
Farmer farmer = new Farmer();
farmer.plant(new Fruit(){

@Override
public void plant(){
System.out.println("种植"+this.getName());
}

@Override
public String getName(){
return "苹果";
}
});
}//运行结果:种植苹果

以上方法也经常采用定义一个苹果类实现Fruit接口,然后农民类中不变,传参时传入苹果类对象(多态)。


注意:

  1. 使用匿名内部类时,匿名内部类既可以继承父类,也可以实现接口 ,同时只能继承一个类或者实现一个接口。

  2. 匿名内部类中不能存在任何的静态成员变量和静态方法

  3. 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。

  4. 匿名类的声明是在编译时进行的,实例化在运行时进行。这意味着 for循环中的一个new语句会创建相同匿名类的几个实例,而不是创建几个不同匿名类的一个实例。

  5. 匿名内部类中的方法都是通过父类引用访问的,所以,如果定义了一个在父类中没有的方法,那么这个方法是不能被这个父类引用调用到的。但是可以仅仅作为匿名内部类中方法之间的代码共享(类似于面向过程)。

  6. 匿名内部类中是不能定义构造函数的,但可通过实例初始化代码块来达到构造器的效果,但是也不能重载实例初始化方法(即仅有一个这样的“构造器”)。

    初始化代码块(构造代码块)例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    public class Outter {
    public Inner getInner(final int age,final String name){
    return new Inner() {
    int age_ ;
    String name_;
    //构造代码块完成初始化工作
    {
    if(0 < age && age < 200){
    age_ = age;
    name_ = name;
    }
    }
    @Override
    public String getName() {
    return name_;
    }
    @Override
    public int getAge() {
    return age_;
    }
    };
    }

    public static void main(String[] args) {
    Outter out = new Outter();
    Inner inner_1 = out.getInner(201, "chenssy");
    System.out.println(inner_1.getName());
    Inner inner_2 = out.getInner(23, "chenssy");
    System.out.println(inner_2.getName());
    }//运行结果:null
    }// chenssy