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(){}
}
MyClass1.java
/**
 * 单例模式 -- 懒汉式
 * 优点:节省资源
 * 缺点:线程不安全
 */
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(){}
}
MyClass2.java
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();
        
    }

}
Test01.java

 简单工厂设计模式

  又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

简单工厂模式包含如下角色:    

    Factory:工厂角色
    Product:抽象产品角色
    ConcreteProduct:具体产品角色

优点:

  简单工厂模式最大的优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类负责,但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,而且产品较多时,工厂方法代码将会非常复杂。   

应用场景:

  工厂类负责创建的对象比较少;客户端只知道传入工厂类的参数,对于如何创建对象不关心。

public abstract class Girl {
    public abstract void hobby();
}
Girl.java
public class BeautiFulGirl extends Girl {

    @Override
    public void hobby() {
        System.out.println("活泼开朗,敢于表达自己的想法");
    }
}
BeautiFulGirl.java
public class UglyGirl extends Girl{

    @Override
    public void hobby() {
        System.out.println("表意不明,朝三暮四");
    }
}
UglyGirl.java
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();
    }

}
Test01.java
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;
    }
}
GirlFactory.java

常用类

基本数据类型包装类/封装类:把基本数据类型包装成了类

  出现的原因: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;
    }
String常用方法
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());
        
        
    }

}
创建StringBuffer对象及其方法

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:线程安全
         */
    }

}
创建StringBuilder对象及其方法

为什么不能用+频繁拼接字符串?

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);
        
        
    }

}
创建日历类及其对应的方法

 

posted @ 2018-10-29 19:39  cmlx  阅读(131)  评论(0)    收藏  举报