《疯狂Java讲义(第4版)》-----第6章【面向对象(下)】(命令模式、Lambda、枚举类、垃圾回收、jar)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ccnuacmhdu/article/details/82924551

命令模式

命令模式,参考下面代码,就能领悟到,想做出怎样的处理,就怎么去覆盖接口中的抽象方法!下面代码中接口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页

猜你喜欢

转载自blog.csdn.net/ccnuacmhdu/article/details/82924551
今日推荐