命令模式
命令模式,参考下面代码,就能领悟到,想做出怎样的处理,就怎么去覆盖接口中的抽象方法!下面代码中接口Command中定义一个对数组处理的方法,但没说怎么处理(毕竟是抽象方法嘛),然后让其他类来实现这个接口,顺便实现这个接口的方法,他们按照何种方式实现,以后调用的时候就怎么去处理数组了。
interface Command{
public abstract void process(int[] target);
}
class PrintCommand implements Command{
public void process(int[] target){
for(int tmp : target){
System.out.println(tmp);
}
}
}
class AddCommand implements Command{
public void process(int[] target){
int sum = 0;
for(int tmp : target){
sum += tmp;
}
System.out.println("sum = "+sum);
}
}
class ProcessArray{
public void process(int[] target, Command cmd){
cmd.process(target);
}
}
class Hello{
public static void main(String[] args){
ProcessArray pa = new ProcessArray();
int[] target = {1,2,3};
//命令模式关键代码---调用PrintCommand的process方法
pa.process(target, new PrintCommand());
//命令模式关键代码---调用AddCommand的process方法
pa.process(target, new AddCommand());
}
}
Lambda表达式
Lambda表达式是Java8新增的,支持将代码块作为方法参数。
Lambda表达式入门
结合上面的命令模式代码,PrintCommand和AddCommand两个实现类可以用匿名内部类实现,也可以用Lambda表达式实现。下面以PrintCommand的实现为例书写主要代码:
匿名内部类方式—去掉PrintCommand的定义代码,并作如下改写:
pa.process(target, new Command(){
public void process(int[] target){
for(int tmp : target){
System.out.println(tmp);
}
}
});
Lambda表达式方式—去掉PrintCommand的定义代码,并作如下改写:
pa.process(target, (int[] array)->{
for(int tmp : target){
System.out.println(tmp);
}
});
对比匿名内部类和Lambda表达式,可以看出Lambda表达式是对匿名内部类的简化:(所实现接口的抽象方法的形参列表)->{所实现接口的抽象方法的代码}
这里暗示了抽象方法必只有一个!就是下面将要说的函数式接口。
Lambda表达式,形参列表只有一个参数时可以省略小括号,实现的方法只有一条语句时可以省略大括号,也可以省略return,返回的是这条语句的返回值。具体代码见该书216页。
Lambda表达式与函数式接口
函数式接口是只包含一个抽象方法的接口。函数式接口可以有多个默认方法、类方法,但只能声明一个抽象方法。Lambda表达式是对匿名内部类的简化,且只能为函数式接口创建对象,只能对函数式接口进行赋值。
枚举类
Java5增加了enum关键字,和class、interface同级别,用于定义枚举类。一个Java源代码文件中最多定义一个public枚举类,并且文件名要和类名相同。
像季节只有四个,适合用枚举类。早期使用public static final定义变量来表示,具有类型不安全等问题(比如用1,2,3,4表示四季节,可参加运算。。),而手动写枚举类比较麻烦,于是乎,语言就直接提供了定义枚举类的关键字。
- 使用enum定义的枚举类默认继承了java.lang.Enum类,因此不可显示地再让enum枚举类去继承别的类
- 用enum定义的非抽象枚举类默认会使用final修饰,如果枚举类里含有抽象方法,系统默认会加上abstract,自己不能手动加abstract
- 枚举类的构造器默认使用private修饰
- 枚举类的所有实例必须在第一行显示给出
enum SeasonEnum{
//第一行列出枚举类包含的所有实例
SPRING, SUMMER, AUTUMN, WINTER;
}
class Hello{
public void judge(SeasonEnum s){
switch(s){
case SPRING:
System.out.println("春天");
break;
case SUMMER:
System.out.println("夏天");
break;
case AUTUMN:
System.out.println("秋天");
break;
case WINTER:
System.out.println("冬天");
break;
}
}
public static void main(String[] args){
//枚举类的默认方法values()
for(SeasonEnum s : SeasonEnum.values()){
System.out.println(s);
}
new Hello().judge(SeasonEnum.AUTUMN);
}
}
java.lang.Enum类包含的方法可以查看该书225页或者官方文档,用的时候直接查看使用即可。
枚举类的成员变量、方法和构造器
enum GenderEnum{
//第一行列出枚举类包含的所有实例
MALE("男"), FEMALE("女");
//MALE("男")相当于public static final GenderEnum MALE = new Gender("男");
private final String gender;
private GenderEnum(String gender){
this.gender = gender;
}
public String getGender(){
return this.gender;
}
}
实现接口的枚举类
interface GenderDescription{
public abstract void info();
}
enum GenderEnum implements GenderDescription{
//第一行列出枚举类包含的所有实例,这里就是匿名内部类啊
MALE("男"){
public void info(){
System.out.println("这个枚举值是男性");
}
}, FEMALE("女"){
public void info(){
System.out.println("这个枚举值是女性");
}
};
private final String gender;
private GenderEnum(String gender){
this.gender = gender;
}
public String getGender(){
return this.gender;
}
}
class Hello{
public static void main(String[] args){
//枚举类的默认方法values()
for(GenderEnum ge : GenderEnum.values()){
System.out.print(ge+": ");
ge.info();
}
}
}
包含抽象方法的枚举类
//含有抽象方法的枚举类,但是一定要注意不要手动在enum之前加上abstract
enum Operation{
//笔者发现,每个枚举对象后面的括号是可以省略的
PLUS(){
public double eval(double x, double y){
return x + y;
}
},
MINUS(){
public double eval(double x, double y){
return x - y;
}
},
TIMES(){
public double eval(double x, double y){
return x * y;
}
},
DIVIDE(){
public double eval(double x, double y){
return x / y;
}
};
public abstract double eval(double x, double y);
}
class Hello{
public static void main(String[] args){
System.out.println(Operation.PLUS.eval(3,2));
System.out.println(Operation.MINUS.eval(3,2));
System.out.println(Operation.TIMES.eval(3,2));
System.out.println(Operation.DIVIDE.eval(3,2));
}
}
对象与垃圾回收
Java垃圾回收机制:
- 垃圾回收机制只负责回收堆内存中的对象,不会回收任何物理资源(例如数据库连接、网络IO等资源)
- 当对象没有变量引用时,就成为垃圾,在合适的时候被回收,不能精准控制垃圾回收
- 垃圾回收机制回收任何对象之前,总会先调用finalize()方法,该方法可能使该对象重新复活(让一个引用变量重新引用该对象),从而导致垃圾回收机制取消回收。
强制垃圾回收
System.gc();
Runtime.getRuntime().gc();
这两个方法都可以进行强制垃圾回收,意思就是说建议系统尽快进行垃圾回收,但是何时回收还是系统说的算。
class Hello{
public static void main(String[] args){
for(int i = 1; i <= 6; i++){
new Hello();
//System.gc();
Runtime.getRuntime().gc();
}
}
//这是Object类的一个方法
public void finalize(){
System.out.println("正在进行垃圾回收...");
}
}
上面代码使用了强制垃圾回收,打印如下,有时回收一次,有时回收两次,说明调用强制回收方法,系统还是有的时候听一下建议马上回收垃圾的!!
如果不使用强制垃圾回收方法的话,笔者实验多次,系统未曾进行一次垃圾回收。
对象的软、弱、虚引用
见该书233~236页
各种修饰符及适用范围
见该书236页
JAR包相关
见该书237页~241页