Java基础——内部类
1、定义在另一个类中的类:内部类。
内部类可以通过OuterClass.this来获取外部类的引用,同时外部类可以通过outerObject.new InnerClass(construction parameters)来获得内部类对象。同时,内部类用于外部类所有元素的访问权限,在内部类构造时,编译器会隐式的将外部类的引入传入。
public class DotThis{
void f(){System.out.println("DotThis.f()");}
public class Inner{
public DotThis outer(){
return DotThis.this;
}
}
// A plain "this" wouldbe Inner's "this"
public Inner inner(){return new Inner();}
public static void main(String[] args){
DotThis dt = new DotThis();
DotThis.Inner dti = dt.inner();
dti.outer().f();
}
}/*Output
DotThis.f()
*///:~
2、在方法和作用域中的内部类:局部内部类。
局部内部类不仅能够访问包含它们的外部类,还能够访问局部变量。不过被引用的局部变量事实上必须是final的,它们一旦赋值就不能被改变。其原因与下文介绍的lambda表达式的原因类似。
3、匿名内部类:只需要使用一次一个类的对象,就可以不必命名了。
invite(new ArrayList<String>() {{add("Harry"); add("Tony")}});
new Object(){}.getClass().getEnclosingClass()
// gets class of static method, 不过直接使用new Object().getClass().getEnclosingClass() 也能通过吧
而对于只包含一个方法的匿名内部类,通常可以使用lambda表达式更精简的实现。
4、静态内部类(嵌套类):如果只是想把一个类隐藏在另一个类的内部,但又不需要引用外部类的对象,可以将内部类声明为static的。同时,声明在接口中的内部类,自动成为static和public的内部类。
5、lambda表达式
当需要一个只包含一个方法的类的对象(只需要一个方法,但由于Java面向对象,因此必须针对这个方法构建一个类,再将类对象传入:函数式接口)时,可以使用lambda表达式进行实现。使用lambda表达式的重点是延迟执行(多次,适当的条件、时间和位置)。lambda表达式可以引用使用外围作用域中的变量,不过因为不确定lambda表达式将何时、几次被执行,因此引用值必须为不变量。同时,由于共享作用域,因此lambda表达式同样不能有与外围作用域同名的局部变量。
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
interface Test{
void accept(int value);
}
public class LambdaTest {
static void repeat(int n, Test action){
for(int i=0; i<n; i++)
action.accept(i);
}
public static void main(String[] args) {
String[] planets = new String[] {
"Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"
};
System.out.println(Arrays.toString(planets));
System.out.println("Sorted in dictionary order: ");
Arrays.sort(planets);
System.out.println(Arrays.toString(planets));
System.out.println("Sorted by length: ");
Arrays.sort(planets, (first, second) -> first.length() - second.length());
System.out.println(Arrays.toString(planets));
repeat(10, i->System.out.println("Countdown: " + (9 - i)));
// if the function can be implement directly by current method simply
repeat(10, System.out::println);
Timer t = new Timer(1000, event -> System.out.println("The time is " + new Date()));
t.start();
JOptionPane.showMessageDialog(null, "Quit Program?");
System.exit(0);
}
}/* Output
[Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune]
Sorted in dictionary order:
[Earth, Jupiter, Mars, Mercury, Neptune, Saturn, Uranus, Venus]
Sorted by length:
[Mars, Earth, Venus, Saturn, Uranus, Jupiter, Mercury, Neptune]
Countdown: 9
Countdown: 8
Countdown: 7
Countdown: 6
Countdown: 5
Countdown: 4
Countdown: 3
Countdown: 2
Countdown: 1
Countdown: 0
0
1
2
3
4
5
6
7
8
9
The time is Tue May 29 15:54:37 GMT+08:00 2018
The time is Tue May 29 15:54:38 GMT+08:00 2018
The time is Tue May 29 15:54:39 GMT+08:00 2018
*///:~
标准形式:
(String first, String second) -> {
if(first.length() < second.length()) return -1;
else if(first.length() > second.length()) return 1;
else return 0;
}
可推断返回值,同时单行可省略花括号:
(String first, String second) -> first.length() - second.length()
可以推断类型可省略类型:
(first, second) -> first.length() - second.length()
只有一个参数可省略小括号:
first -> first.length()
无参数必须保留小括号:
() -> System.out.println("Hello World!")
现有方法能够直接实现功能:
Math::pow // 等价于 (x, y) -> Math.pow(x, y)