黑马程序员---工具类和设计模式
来源:互联网 发布:矩阵论 清华 编辑:程序博客网 时间:2024/04/29 10:29
-------
一、工具类
需求:定义一个工具类,实现int型数组的打印、获取最值、选择排序、冒泡排序、折 半查找(二分查找)等功能。
思路:
工具类:工具类中不需要有类的特有数据(属性),仅仅用到了类中的方法,那么将方法都static化,直接通过类名调用,而且不需要建立对象,所以也把构造函数私有化,进制其他程序创建该类对象,使得代码更严谨。我们只需调用相应方法就可以达到目的。把需要对外的方法都public,扩大其权限,同时把不需要对外的成员都private,不对外公开。
步骤:
1.定义类ArrayTool工具类,且将构造函数私有化;
2.分别定义各功能函数,需要对外的方法全部public,不需要对外的成员都private。
public class ArrayTool{private ArrayTool(){}///构造函数私有化//获取最小值角标public static int getMin(int[] arr){/*int min = arr[0];//初始化min使其等于数组arr的第一个值。for (int i=1; i<arr.length; i++){if (min>arr[i])min = arr[i];}return min;*/int min = 0;for (int i=1; i<arr.length; i++){if (arr[min]>arr[i])//将min作为数组的角标使用。min = i;}return min;}//获取最大值的角标public static int getMax(int[] arr){int max = 0;for (int i=1; i<arr.length; i++){if (arr[max]<arr[i])//将max作为数组的角标使用。max = i;}return max;}//选择排序(升序):首先确定最小值public static void selectSort(int[] arr){for (int i=0; i<arr.length-1; i++){for (int j=i+1; j<arr.length; j++){if (arr[i]>arr[j])swap(arr,i,j);}}}//冒泡排序(降序):首先确定最小值public static void bubbleSort(int[] arr){for (int i=0; i<arr.length-1; i++){for (int j=0; j<arr.length-1-i; j++)//-i:让每一次比较的元素减少,-1:避免角标越界。{if (arr[j]<arr[j+1])swap(arr,j,j+1);}}}//打印数组public static void printArray(int[] arr){System.out.print("[");for (int i=0; i<arr.length; i++){if (i<arr.length-1)System.out.print(arr[i]+",");elseSystem.out.println(arr[i]+"]");}}//元素位置置换private static void swap(int[] arr,int a,int b){arr[a] = arr[a] + arr[b];arr[b] = arr[a] - arr[b];arr[a] = arr[a] - arr[b];}//折半查找(二分查找):必须保证该数组是有序,升序降序均可,并返回将一个数插入该数组中的位置。public static int halfSearch(int[] arr,int key){int start = 0, end = arr.length-1, mid;int max = getMax(arr);int min = getMin(arr);//若key值大于最大值或小于最小值,返回插入元素的位置if (key>arr[max])return max;else if(key<arr[min])return min;//while循环对在数组区间内的元素进行判断while (start<=end){mid = (start+end)>>1;if (key>arr[mid]){//判断数组是升序还是降序if (arr[0]<=arr[arr.length-1])start = mid + 1;elseend = mid - 1;}else if (key<arr[mid]){if (arr[0]>=arr[arr.length-1])start = mid + 1;elseend = mid - 1;}elsereturn mid;}return start;//返回将一个元素插入该数组中的位置。}}
总结:工具类的定义,方便了程序员对资源的合理利用,我们只需要知道该工具类(或工具包)有哪些功能,选择适合自己需要的功能就行,而不需要知道该功能具体是怎么实现的,因为方法都是静态的,不需要创建对象,方便又快捷。在正式的开发中就会经常用到工具类来提高程序员的工作进度。
二、设计模式
java中一共有23种设计模式。
1、单例设计模式
作用:使对象唯一,用于数据共享。必定提供一个静态的对外方法来获取该单利的实例。
饿汉式:先初始化对象。类一进内存,就已经建立好了对象(单例设计常用:因为安全简单)。
懒汉式:对象是方法被调用时,才开始初始化,也叫做延时加载。类进内存,对象还没有存在,只有调用了与之对应的方法时才创建对象(面试考点:加载存在缺陷,可能会导致对象重复建立,与单例设计对象唯一相悖,开发基本不用,改进型代码体相对饿汉式麻烦)。
需求:写出单例设计模式的两种体现:分别为饿汉式和懒汉式。
思路:
单例设计模式是解决某一类问题最行之有效的方法,它解决的是某一个类中只存在一个对象,所以只需做到下面的三点即可完成设计,而其他的对于事物的描述,一切照旧。
1.将构造函数私有化,保证其不被创建对象;
2.在类中创建一个本类对象,保证其他程序可以访问到该类对象;
3.提供一个方法可以获取到该对象,方便其他程序对自定义对象的访问。
步骤:懒汉式
1.创建一个空对象;
2.创建私有化的构造函数;
3.定义一个方法体来获取该对象,且在方法体中进行判断对象是否为空,不为空则不创建对象,直接返回对象在堆内存中的地址。
4.饿汉式外加方法体:通过覆盖父类Object.equals来实现本类对象特有的比较内容。
//饿汉式:class SingleE{private int num;//私有化的成员变量,描述照旧//饿汉式代码体现块private static SingleE s = new SingleE();private SingleE(){}public static SingleE getInstance(){return s;}//方法体,描述照旧public void setNum(int num){this.num = num;}public int getNum(){return num;}//java中任何类都是Object的直接或间接子类,所以可以直接复写(重写、覆盖)Object父类中的equals方法,//来定义属于自己的比较内容。其中参数类型是Object表示可以传入任何类类型值。public boolean equals(Object obj){//判断传入值类型是否是SingleE类类型,若不是返回false。不同类型对象不能参与比较。作用:增强程序健壮性。if (!(obj instanceof SingleE))return false;SingleE e = (SingleE)obj;//多态:向下转型(类型符合)return this.num == e.num;}}class Person{int num;Person(int num){this.num = num;}}class SingleDemo{public static void main(String[] args) {SingleL l = SingleL.getInstance();SingleE s1 = SingleE.getInstance();//创建对像s1SingleE s2 = SingleE.getInstance();//创建对象s2,和s1指向的堆内存地址相同,即指向对象唯一,单例设计成功。Person p = new Person(8);//创建Person类型变量p指向new Person()在堆内存中的首地址。//System.out.println(p);//输出的是Person类类型变量所指向的地址:Person@14a55f2s1.setNum(8);//给s1所指对象赋值,结果为:num=8. //System.out.println("num="+s1.getNum());s2.setNum(11);//给s2所指对象即s1所指对象传赋值,结果为:num=11,覆盖了原来的num=8.所以下面两条的输出语句都是8//System.out.println("num="+s1.getNum());//System.out.println("num="+s2.getNum());System.out.println("compare end:"+s1.equals(p));}}//懒汉式:代码体现块class SingleL{private static SingleL s = null;//创建空对象private SingleL(){}//私有化构造函数public static SingleL getInstance()//定义方法体获取对象{if(s == null)//这个if语句执行可能会出现进程挂载的情况{//s = new Single(); //为了防止多个进程挂载后出现对象重复建立的情况,采用synchronized同步代码块保证一次只有一个程序//进入判断体。若该if语句中有一个程序挂载,那么就锁住该同步代码块语句防止其他调用程序进入该代码块。synchronized(SingleL.class)//同步代码块{if(s==null)s = new SingleL();}}return s;}}
2、模版设计模式
模版方法设计模式:在定义功能时,功能的一部分是确定的,但是有一部分是不确定的,而确定的部分在使用不确定的部分,
那么这时候就将不确定的部分暴露出去,有该类的子类去完成。
需求:获取一段程序运行的时间。
思路:获取程序开始和结束时间并相减即该程序的运行时间。获取时间的方法:System.currentTimeMillis()。
abstract class GetTime//抽象类{/*final:最终1、可以修饰类、函数和变量;2、被final修饰的类不可以被继承(意为最终类);3、被final修饰的方法不可以被子类复写;4、被final修饰的变量(成员变量和局部变量)是一个常量只能赋值一次,且常量名所有字母均必须大写,如:PI、MY_BIRTHDAY;5、内部类定义在类中的局部位置上,只能访问该局部被final修饰的局部变量(后期涉及)。*///固定方法调用未知方法(模版设计模式)public final void getTime(){long start = System.currentTimeMillis();//获取程序开始执行的时间runcode();//未知方法long end = System.currentTimeMillis();//获取程序执行完后的时间System.out.println("毫秒:"+(end-start));//打印程序运行的时间}//抽象型函数,没有方法体(不可以实例化),抽象的出现就是为了让子类复写。因为抽象类函数定义的是一个总体的方法,//但是不确定具体的执行内容,会有多种方式来实现,所以不具备方法体和参数列表。//abstract不能和final、static、private关键字共存,共存后都不能被子类复写,抽象就没有意义了。public abstract void runcode();}//子类继承父类,那么子类就具有父类中所有的非私有化成员。class SubTime extends GetTime{public void runcode(){for (int i=0; i<2222; i++){System.out.print("*");}}}class Template{public static void main(String[] args){//GetTime gt = new SubTime();//多态:向上转型:父类型引用指向子类对象。SubTime gt = new SubTime();gt.getTime();}}
3、装饰设计模式
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。那么自定义的该类成为装饰类。装饰类通常会通过构造方法接收被装饰的对象。
BufferedReader 类中特有方法 readLine 底层调用的仍然是 read 方法的,是一个字符一个字符的读取,并将暂时读取的字符存入到一个临时容器中,当读取到某一行的终止(换行 ('\n')、回车 ('\r') 或回车后直接跟着换行)时,再返回容器中的数据。也属于装饰设计模式。
装饰和继承:若多个类需要另一类的缓冲功能,以前是通过继承将每一个子类都具备缓冲功能。那么继承体系会复杂,并不利于扩展。现在优化思想,单独描述一下缓冲内容。将需要被缓冲的对象,传递进来,也就是谁需要被缓冲,谁就作为参数传递给缓冲区。这样继承体系就变得很简单。优化了体系结构。
特点:装饰模式比继承要灵活,避免了继承体系臃肿,而且降低了类于类之间的关系。
注:装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。所以装饰类和被装饰类通常是都属于一个体系中的。
示例:
class MyLineNumberReader{ private BufferedReader bufr; private int lineNumber; //定义行变量,可以通过设置行显示的起始位置。 MyLineNumberReader(BufferedReader bufr) { this.bufr = bufr; } //装饰设计模式 public String myReadLine() throws IOException { lineNumber++; return bufr.ReadLine(); //指向BufferedReader ,调用其方法 /* // 自定义读取一行的功能 StringBuilder sb = new StringBuilder(); int ch = 0; while ((ch=r.read())!=-1){ if (ch=='\r') //满足条件,跳出当前循环,进入下一次循环 continue; if (ch=='\n') //独到换行符,就返回字符串容器的中的内容 return sb.toString(); sb.append((char)ch); //向容器中添加读取到的字符 } if (sb.length()!=0) return sb.toString(); return null; */ } public void setLineNumber(int lineNumber){ this.lineNumber = lineNumber; } public int getLineNumber(){ return lineNumber; } @Test public static void main(String[] args) throws IOException{ FileReader fr = new FileReader("Demo.java"); MyLineNumberReader mylnr = new MyLineNumberReader(fr); String line = null; mylnr.setLineNumber(50); while ((line=mylnr.myReadLine())!=null) System.out.println(mylnr.getLineNumber()+":"+line); } }
解析:自定义读取行功能中,if(sb.length()!=0) 存在的理由:如果一行文本的结尾没有回车符,那么while 循环体中的 if(ch=='\n') 将读不到,所以 StringBuilder 中存入的数据没有被取出,就要在循环体外再判断一次。
总结:设计模式是根据实际经验总结出来的,是一种纯思想的思考问题的方法,深入学习必须了解设计模式,有利于自己在各开发语言学习中的发展(不论java、c++、c#都通吃),虽然它是纯思想的,但是得根据具体的项目来实施,如果没有实际的开发经验,只通理论同样不切实际。
- 黑马程序员---工具类和设计模式
- 黑马程序员——Java基础——数组工具类、设计模式和继承(一)
- 黑马程序员-设计模式,继承和抽象类
- 黑马程序员------装饰设计模式和单例设计模式
- 黑马程序员:设计模式
- 黑马程序员-设计模式
- 黑马程序员-----------设计模式
- 黑马程序员-设计模式
- 黑马程序员--设计模式
- 黑马程序员 设计模式
- 黑马程序员-----设计模式
- 黑马程序员_单例设计模式和装饰类设计模式
- 黑马程序员_源自梦想 静态、工具类、单例设计模式
- 黑马程序员----面向对象2(主函数、工具类、文档注释、单例设计模式)
- 黑马程序员---装饰类设计模式
- 黑马程序员----java设计模式之装饰设计模式和享元设计模式
- 黑马程序员-Collections和Arrays工具类
- 黑马程序员-策略设计模式
- Java基础复习:Map接口
- 黑马程序员---正则表达式
- LeetCode —— Sort Colors
- POJ-3026-Borg Maze
- CSS常用浮出层的写法
- 黑马程序员---工具类和设计模式
- 队列管理算法及策略总结
- nesC学习备忘录
- poj1934-打印LCS全部路径+搜索
- 六级之听力攻略1
- 流行趋势:27个引领时尚的网页设计作品【上篇】
- poj 2492 A Bug's Life
- escape加号被过滤解决方法
- springMVC详解