啥子是匿名内部类
用大白话讲,就是一群没得名字的嵌套类。
那为啥要用匿名内部类
还是用大白话讲:当我们需要使用的方法只调用一次的时候,我们想偷个懒,懒得去创建一个新的类去重写该方法,这个时候选择使用匿名的方式去重写这个方法,这样我们可以不需要创建新的类,减少了代码的冗杂度,使得代码更优雅~
那接下来就得唠唠咋个写了:
//格式:
new 接口/类名(参数1, 参数2...){//直接new我们需要调用的方法的类或者是接口,然后如果需要传参就写参数列表,不需要就无参
@Override//只是一个标记,没得啥具体意义,只是写了更直观晓得这个是重写了的
需要重写的方法1(){//这里就是重写的方法 and 方法体
}
@Override
需要重写的方法2(){//可以写多个,都是可以的,还是那句话,看需求,你需要重写几个就重写几个,前提是你确实是需要用的
}
......
};
那么问题来了,我啷个晓得遇到啥子请况的时候用喃?
匿名内部类适用于以下场景:
1.当只需要使用一次的类时:
匿名内部类可以在创建对象的同时定义一个子类,而不必单独定义一个名字,这样可以避免定义无用的类,使代码更加简洁。
interface Greeting {
void sayHello();
}
public class Main {
public static void main(String[] args) {
// 使用匿名内部类实现接口
Greeting greeting = new Greeting() {
public void sayHello() {
System.out.println("Hello!");
}
};
greeting.sayHello();
}
}
在上面的示例代码中,我们使用匿名内部类实现了 Greeting
接口,而不需要单独定义一个实现类。这样可以避免定义无用的类,使代码更加简洁。在 main
方法中,我们实例化了一个 Greeting
对象并调用其 sayHello
方法来输出 “Hello!”。
另外,还有一些其他的场景,比如需要实现一个 Runnable
接口来创建一个线程,也可以使用匿名内部类来避免定义一个无用的类。以下是一个示例代码:
public class Main {
public static void main(String[] args) {
// 使用匿名内部类实现Runnable接口
Runnable runnable = new Runnable() {
public void run() {
System.out.println("Hello, I am a thread!");
}
};
// 创建线程并启动
Thread thread = new Thread(runnable);
thread.start();
}
}
在上面的示例代码中,我们使用匿名内部类实现了 Runnable
接口,而不需要单独定义一个实现类。这样可以避免定义无用的类,使代码更加简洁。然后我们创建了一个线程,并启动它来输出 “Hello, I am a thread!”。
2.当需要重写接口或抽象类的方法时:
匿名内部类可以方便地实现接口或抽象类,而无需单独定义一个类。
abstract class Animal {
abstract void move();
}
public class Main {
public static void main(String[] args) {
// 使用匿名内部类实现抽象类
Animal animal = new Animal() {
void move() {
System.out.println("Animal is moving.");
}
};
animal.move();
}
}
在上面的示例代码中,我们使用匿名内部类实现了 Animal
抽象类,而不需要单独定义一个实现类。在 main
方法中,我们实例化了一个 Animal
对象并调用其 move
方法来输出 “Animal is moving.”。
另外,还有一些其他的场景,比如需要实现一个 Comparator
接口来对集合进行排序,也可以使用匿名内部类来方便地实现接口。以下是一个示例代码:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {
// 创建一个包含字符串的集合
List<String> list = new ArrayList<String>();
list.add("apple");
list.add("orange");
list.add("banana");
list.add("pear");
// 使用匿名内部类实现Comparator接口
Collections.sort(list, new Comparator<String>() {
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
// 输出排序后的集合
System.out.println(list);
}
}
在上面的示例代码中,我们使用匿名内部类实现了 Comparator
接口,而不需要单独定义一个实现类。然后我们创建了一个包含字符串的集合,并使用 Collections.sort
方法对其进行排序,而排序规则是通过匿名内部类实现的。最后输出排序后的集合。
3.当需要传递一个类的实例时:
使用匿名内部类可以更加方便地创建一个实现了特定接口或抽象类的对象,并将其作为参数传递给其他方法。
interface Greeting {
void sayHello();
}
public class Main {
public static void greet(Greeting greeting) {
greeting.sayHello();
}
public static void main(String[] args) {
// 使用匿名内部类作为参数传递
greet(new Greeting() {
public void sayHello() {
System.out.println("Hello, world!");
}
});
}
}
在上面的示例代码中,我们定义了一个接口 Greeting
,它有一个 sayHello
方法。然后我们定义了一个静态方法 greet
,它接受一个 Greeting
对象作为参数,并调用其中的 sayHello
方法。最后在 main
方法中,我们使用匿名内部类来创建一个 Greeting
对象,并将它作为参数传递给了 greet
方法。在这个匿名内部类中,我们实现了 Greeting
接口的 sayHello
方法来输出 “Hello, world!”。
需要注意的是,匿名内部类可以用于实现接口或继承类,但不能同时实现接口和继承类。因此,在使用匿名内部类作为参数传递时,要根据需要选择合适的接口或继承类。
当需要在方法中使用局部变量时,可以使用匿名内部类来访问这些变量,而无需将这些变量声明为类的成员变量。
interface Calculator {
int calculate(int x, int y);
}
public class Main {
public static void main(String[] args) {
int a = 10;
int b = 5;
// 使用匿名内部类访问局部变量a和b
Calculator add = new Calculator() {
public int calculate(int x, int y) {
return x + y + a + b;
}
};
Calculator subtract = new Calculator() {
public int calculate(int x, int y) {
return x - y - a - b;
}
};
// 输出计算结果
System.out.println("Addition result: " + add.calculate(2, 3));//20
System.out.println("Subtraction result: " + subtract.calculate(2, 3));//-16
}
}
在上面的示例代码中,我们定义了两个匿名内部类 add
和 subtract
,它们都实现了 Calculator
接口,而且都访问了方法中的局部变量 a
和 b
。然后我们调用这两个对象的 calculate
方法来计算加法和减法的结果,并输出结果。
4.当需要访问外部类的成员变量或方法时:
匿名内部类可以访问其外部类的成员变量和方法,这样可以使代码更加灵活。
public class OuterClass {
private int x = 10;
public void outerMethod() {
System.out.println("Outer method is called");
}
public void createInnerClass() {
// 使用匿名内部类访问外部类成员变量和方法
new Thread(new Runnable() {
public void run() {
System.out.println("Inner class is running, x is " + x);
outerMethod();
}
}).start();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.createInnerClass();
}
}
在上面的示例代码中,我们定义了一个外部类 OuterClass
,它有一个私有成员变量 x
和一个公共方法 outerMethod
。然后我们在 createInnerClass
方法中使用匿名内部类来创建一个新的线程,并在其中实现了 Runnable
接口的 run
方法。在这个匿名内部类中,我们可以访问外部类的成员变量 x
和方法 outerMethod
。最后我们在 main
方法中创建了一个 OuterClass
对象并调用了它的 createInnerClass
方法来启动这个线程。
需要注意的是,在匿名内部类中访问外部类的成员变量和方法时,这些成员变量和方法必须是 final 或 effectively final 的。如果这些成员变量和方法不是 final 或 effectively final 的,编译器会报错。
关于final和有效final我不过多赘述,想了解的话移步这里!!!这位大佬讲的究极清晰
另外,如果接口中只有一个抽象方法,那么这个接口就是函数式接口,可以使用 Lambda 表达式来代替匿名内部类实现。以下是一个使用 Lambda 表达式实现函数式接口的示例代码:
interface Calculator {
int calculate(int x, int y);
}
public class Main {
public static void main(String[] args) {
// 使用 Lambda 表达式实现函数式接口
Calculator add = (x, y) -> x + y;
Calculator subtract = (x, y) -> x - y;
// 输出计算结果
System.out.println("Addition result: " + add.calculate(2, 3));
System.out.println("Subtraction result: " + subtract.calculate(2, 3));
}
}
在上面的示例代码中,我们使用 Lambda 表达式实现了 Calculator
函数式接口,而不需要使用匿名内部类来实现。然后我们创建了两个 Calculator
对象 add
和 subtract
,并分别使用 Lambda 表达式来实现加法和减法的计算规则。最后输出计算结果。
需要注意的是,Lambda 表达式只能用于函数式接口,它们不能用于普通接口或抽象类。