day_12:面向对象设计原则、设计模式、常用类、String类、Date类
面向对象的设计原则
单一职责原则:就是所谓的“高内聚,低耦合”,也就是说每个类应该只有一个职责,对外只提供一种功能,而引起该类变化的原因也应该只有一个。
开闭原则:对扩展开发,对修改关闭,对功能的扩展是通过增加代码来进行的,而非修改原有的类代码。
里氏替换原则:在任何父类出现的地方,都可以用它的子类来替换
依赖注入原则:要依赖抽象,而不是依赖于具体的实现
接口分离原则:不应该强迫子类实现他们不需要使用的方法,一个接口应该只提供一种对外的功能,不要把所有的方法都封装到一个接口中,还是可以从分层的角度来理解。
迪米特原则:一个对象应该对其他对象尽可能少的了解,也就是说要降低对象之间的耦合度,面向接口来编程,不理会其内部的工作原理
设计模式
是代码设计经验的总结,它与具体的语言无关,是一种思想,掌握了面向对象的思想,才可以更好的理解设计模式,而反之亦然。
单例模式
单例:单个实例,实例==对象
目的:在整个应用程序中,只会创建一份对象
两种实现方式:延迟加载(懒汉式)[ 节约资源但是线程不安全 ]、立即加载(饿汉式)[ 线程安全但是浪费资源 ]
应用场景:这个类里面是否写了全局变量,写了的话就不能使用单例模式。
/** * 单例模式 -- 饿汉式 * 优点:线程安全 * 缺点:占用空间(浪费资源) */ public class MyClass1 { private static MyClass1 my = new MyClass1(); private MyClass1(){} public static MyClass1 getInstance(){ return my; } public static void method(){} }
/** * 单例模式 -- 懒汉式 * 优点:节省资源 * 缺点:线程不安全 */ public class MyClass2 { private static MyClass2 my = null; private MyClass2(){} public static MyClass2 getInstance(){ if(my == null){ my = new MyClass2(); } return my; } public static void method(){} }
public class Test01 { public static void main(String[] args) { /** * 单例模式:单个实例 * 创建一个类-MyClass,只能有一个对象 */ //实例化(new了一个对象) // MyClass m1 = new MyClass(); // MyClass m2 = new MyClass(); // System.out.println(m1 == m2); // MyClass m1 = MyClass.getInstance(); // MyClass m2 = MyClass.getInstance(); // // System.out.println(m1 == m2); MyClass1.method(); } }
简单工厂设计模式
又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
简单工厂模式包含如下角色:
Factory:工厂角色
Product:抽象产品角色
ConcreteProduct:具体产品角色
优点:
简单工厂模式最大的优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类负责,但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,而且产品较多时,工厂方法代码将会非常复杂。
应用场景:
工厂类负责创建的对象比较少;客户端只知道传入工厂类的参数,对于如何创建对象不关心。
public abstract class Girl { public abstract void hobby(); }
public class BeautiFulGirl extends Girl { @Override public void hobby() { System.out.println("活泼开朗,敢于表达自己的想法"); } }
public class UglyGirl extends Girl{ @Override public void hobby() { System.out.println("表意不明,朝三暮四"); } }
package com.cmlx.model01_type01; public class Test01 { public static void main(String[] args) { /** * 简单工厂模式: * 需求:去Girl工厂下订单 * 分析:工厂类、产品类 * * 应用场景:创建一系列关联的类 */ GirlFactory girlFactory = GirlFactory.getFactory(); Girl girl = girlFactory.createGirl(GirlFactory.BEAUTIFULGIRL); girl.hobby(); } }
public class GirlFactory { public static final int BEAUTIFULGIRL = 1; public static final int UGLYGIRL = 2; public GirlFactory() { } //单例模式--》饿汉式 private static GirlFactory girlFactory = new GirlFactory(); public static GirlFactory getFactory() { return girlFactory; } public Girl createGirl(int type) { Girl girl = null; if(type == BEAUTIFULGIRL) { girl = new BeautiFulGirl(); }else if(type == UGLYGIRL){ girl = new UglyGirl(); } return girl; } }
常用类
基本数据类型包装类/封装类:把基本数据类型包装成了类
出现的原因:Java是一门纯面向对象的语言,基本数据类违背了面向对象语言的特征,所以Java把8种基本的数据类型都包装成了对应的类。
byte Byte short Short int Integer long Long
float Float double Double char Character boolean Boolean
应用场景:集合规定只能存放引用数据类型的数据,如果要存放基本数据类型,可以存放对应的包装类的对象
拆装箱:
//装箱:基本数据类型 -> 包装类对象 Integer integer = Integer.valueOf(10); System.out.println(integer); //拆箱:包装类对象 -> 基本数据类型 int intValue = integer.intValue(); System.out.println(intValue); //自动装箱:基本数据类型 -> 包装类对象 Integer integer = 10; System.out.println(integer); //自动拆箱:包装类对象 -> 基本数据类型 int intValue = integer; System.out.println(intValue);
String类
String是不可变类, 即一旦一个String对象被创建, 包含在这个对象中的字符序列是不可改变的, 直至该对象被销毁。String类是final类,不能有子类。
常量池:java运行时会维护一个常量池,常量池用来存放运行时产生的各种字符串,并且池中的字符串的内容不重复。
String str3 = new String("123"); String str4 = new String("123"); System.out.println(str3 == str4);//false String str5 = "12" + "3"; System.out.println(str5 == str1);//true String str6 = "12"; String str7 = "3"; String str8 = str6+str7;//new StringBuild(str6).append(str7).toString(); System.out.println(str8 == str1);//false final String str9 = "12"; final String str10 = "3"; String str11 = str9+str10; System.out.println(str11 == str1);//true /** * 两个字符串常量直接拼接 * 有一个字符串为变量时拼接,底层都会创建StringBuild对象 */
String常用方法
String str = "123abcDEF123"; str = str.concat("木头人");//拼接:在此字符串末尾拼接目标字符串,并返回新的字符串 str = str.substring(3);//截取:从目标索引开始,截取到字符串的末尾,并返回新的字符串 str = str.substring(1, 9);//截取:从目标索引(包含)所以开始,截取到结束索引(不包含),并返回新的字符串 str = str.toUpperCase();//转大写,并返回新的字符串 str = str.toLowerCase();//转小写,并返回新的字符串 str = " bc de f123 "; str = str.trim();//去掉首尾空格,并返回新的字符串 str = str.replace(" ", "");//替换 System.out.println(str); System.out.println("此字符串的长度为:" + str.length()); System.out.println("比较字符串内容是否相等:" + str.equals("bcdef123")); System.out.println("比较字符串内容(不区分大小写)是否相等:" + str.equalsIgnoreCase("BCDef123")); System.out.println("查询此字符串是否以\"bc\"开头:" + str.startsWith("bc")); System.out.println("查询此字符串是否以\"123\"结尾:" + str.endsWith("123")); int indexOf = str.indexOf("d");//查询“d”在此字符串中的下标位置 System.out.println(indexOf); char charAt = str.charAt(4);//获取指定下标上的字符 System.out.println(charAt); String valueOf = String.valueOf(100);//将其他类型转换为String类型 System.out.println(valueOf); String s = 100+""; System.out.println(s); } //String类substring底层实现 public static String method(int beginIndex,int endIndex){ String str = "abcDEF123木头人"; char[] charArray = str.toCharArray(); String s = ""; for (int i = beginIndex; i < endIndex; i++) { s += charArray[i]; } return s; }
public class Test03 { public static void main(String[] args) { /** * 验证邮箱合法性:1445584980@qq.com */ String email = "1445584980@qq.com"; int length = email.length(); int indexOf1 = email.indexOf("@"); int indexOf2 = email.indexOf("."); if(indexOf1 == 0 || indexOf1 == length-1 || indexOf2 == 0 || indexOf2 == length-1 || indexOf2-indexOf1 < 2 ){ System.out.println("邮箱格式错误"); }else{ System.out.println("邮箱格式正确"); } } }
StringBuffer类
为什么需要StringBuffer类?
一个String对象的长度是固定的,不能改变它的内容,或者是附加新的字符到String对象中。您也许会使用+来串联字符串以达到附加新字符或字符串的目的,但+会产生一个新的String对象。如果程序对这种附加字符串的需求很频繁,系统会频繁在内存中创建String对象,造成性能下降。所以并不建议使用+来进行频繁的字符串串联。应该使用java.lang.StringBuffer类。
什么是StringBuffer?
代表可变的字符序列,称为字符串缓冲区,它的工作原理是:预先申请一块内存,存放字符序列,如果字符序列满了,会重新改变缓存区的大小,以容纳更多的字符序列。StringBuffer 是可变对象,这个是String最大的不同。
创建StringBuffer对象及其方法:
public class Test04 { public static void main(String[] args) { //带有缓冲区的字符串 //默认创建16个字符的缓冲区 //StringBuffer sb = new StringBuffer(); //默认创建"木头人".length() + 16 个字符的缓冲区 StringBuffer sb = new StringBuffer("木头人"); sb = sb.append("123");//在缓冲区末尾追加字符串,并返回StringBuffer的对象 sb = sb.insert(3,"abc");//在指定下标上插入字符串,并返回StringBuffer的对象 sb = sb.reverse();//翻转字符,并返回StringBuffer的对象 sb = sb.delete(3, 6);//删除从开始索引(包含)到结束索引(不包含),并返回StringBuffer的对象 sb = sb.deleteCharAt(2);//删除指定下标上的字符,并返回StringBuffer的对象 sb.setCharAt(2, '日');//替换指定下标上的字符 sb = sb.replace(2, 4, "1干木");//替换从开始索引(包含)到结束索引(不包含)上的字符串,并返回StringBuffer的对象 System.out.println(sb); System.out.println("此缓冲区里字符的个数为:" + sb.length()); } }
StringBuilder类
StringBuilder与StringBuffer的用法完全一致,唯一的区别是StringBuffer是线程安全的,而StringBuilder不是线程安全的。所以StringBuilder的性能要比StringBuffer要好。单线程推荐使用StringBuilder,多线程使用StringBuffer。
创建StringBuilder对象及其方法:
public class Test05 { public static void main(String[] args) { //带有缓冲区的字符串 //默认创建16个字符的缓冲区 //StringBuilder sb = new StringBuilder(); //默认创建"木头人".length() + 16 个字符的缓冲区 StringBuilder sb = new StringBuilder("木头人"); sb = sb.append("123");//在缓冲区末尾追加字符串,并返回StringBuilder的对象 sb = sb.insert(3,"abc");//在指定下标上插入字符串,并返回StringBuilder的对象 sb = sb.reverse();//翻转字符,并返回StringBuilder的对象 sb = sb.delete(3, 6);//删除从开始索引(包含)到结束索引(不包含),并返回StringBuilder的对象 sb = sb.deleteCharAt(2);//删除指定下标上的字符,并返回StringBuilder的对象 sb.setCharAt(2, '日');//替换指定下标上的字符 sb = sb.replace(2, 4, "1干木");//替换从开始索引(包含)到结束索引(不包含)上的字符串,并返回StringBuilder的对象 System.out.println(sb); System.out.println("此缓冲区里字符的个数为:" + sb.length()); /** * StringBuilder vs StringBuffer * ps:在调用方法上完全没区别!!! * * StringBuilder:线程不安全 * StringBuffer:线程安全 */ } }
为什么不能用+频繁拼接字符串?
public class Test06 { public static void main(String[] args) { /** * 为什么不能用+频繁拼接字符串 */ long codeTime = getCodeTime(new I1() { @Override public void code() { //201毫秒 // String str = ""; // for (int i = 0; i < 10000; i++) { // str += i; // // str = str+1; // // str = new StringBuilder(str).append(i);底层频繁创建StringBuilder对象,使得性能降低 // } //1毫秒 StringBuilder sb = new StringBuilder(); for (int i = 0; i < 10000; i++) { sb = sb.append(i); } } }); System.out.println(codeTime); } public static long getCodeTime(I1 i1){ long startTime = System.currentTimeMillis(); i1.code(); long endTime = System.currentTimeMillis(); return endTime - startTime; } }
Date类
java.util.Date类表示特定的瞬间,精确到毫秒。
格式化时间
public class Test02 { public static void main(String[] args) throws ParseException { //格式化时期 SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd HH:mm:ss"); String str = sdf.format(new Date()); System.out.println(str); //放入固定格式的字符串,解析出Date对象 Date parse = sdf.parse("2018年10月30 15:06:07"); System.out.println(parse); } }
创建日历类对象及日历类的方法
public class Test03 { public static void main(String[] args) { //获取日历类的对象 Calendar c = Calendar.getInstance(); //获取相应的数据 int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH) + 1; int day = c.get(Calendar.DAY_OF_MONTH); int hour = c.get(Calendar.HOUR); int minute = c.get(Calendar.MINUTE); int second = c.get(Calendar.SECOND); System.out.println(year); System.out.println(month); System.out.println(day); System.out.println(hour); System.out.println(minute); System.out.println(second); } }

浙公网安备 33010602011771号