Java学习笔记19---枚举类,设计模式

(一)、枚举类:
关键字:enum
语法:public enum 枚举类名{ 对象}
适用场景:当对象的个数固定,且有限。
例子:public enum Sex{
MAlE,
FEMALE;
public void test(){};//枚举中定义方法,MALE,FEMALE对象都有这个方法
private string cnName;
Sex(String cnName){this.cnName=cnName};//构造方法,不能定义成public,对象有限。
}
测试类中:获取枚举类的序号:Sex.MALE.ordinal()。
把枚举对象转为字符串:Sex.MALE.name();
把字符串转为枚举对象Sex.valueof();
虚拟机中的枚举对象只会有一份,可以用==来比较,定义几个对象就有几个。
获取枚举中的所有对象:Sex.values();返回值Sex[]数组。
枚举类中也可以有方法,构造方法,属性,但是构造方法不能是公共的,枚举类型也不能继承。
代码实现:

public enum Sex {
    //枚举类,对象固定且有限
    MALE("男"),
    FEMALE("女");
    //构造方法不能加public
    //因为对象数是固定的有限个
    private  String chName;
    Sex(String chName){
        this.chName=chName;
    }
    public String getChName() {
        return chName;
    }
    //枚举类中可以定义方法,
    public void test(){
        System.out.println("我是枚举类中的test方法");
    }
}

public class SexTestEnum {
    public static void main(String[] args) {
        int i1= Sex.MALE.ordinal();//返回此枚举常量的序号
        int i2=Sex.FEMALE.ordinal();
        System.out.println(i1);
        System.out.println(i2);
        Sex.MALE.test();//调用方法
        Sex.FEMALE.test();
        System.out.println(Sex.MALE.name());//把枚举对象转为字符串
        System.out.println(Sex.FEMALE.toString());//把枚举对象转为字符串
        System.out.println(Sex.MALE.getChName());
        Sex sex = Sex.valueOf(Sex.MALE.name());//把字符串转为枚举对象
        System.out.println(sex);
        Sex[] sexs= Sex.values();//获取枚举类型中的所有对象
        for(Sex sex1:sexs){
            System.out.println(sex1);
        }
    }
}

(二)、设计模式((Design pattern)重要)
定义:就是编程中的一些套路;目的让我们的代码实现特定的目的,结构上更加优秀。
GOF(group of Four)—总结出了23种设计模式;
1.单例模式(singleton)
(1).定义:虚拟机中这个类只有一个实例(一个对象);
(2).饿汉式单例模式:(一开始就创建好了)
第一步:让构造方法私有,别人没办法创建此类对象;
第二步:自己创建这个实例对象;//定义成私有的,静态的
第三步:定义静态方法,获取唯一实例;
代码如下:

//设计模式之饿汉单例模式
public class Singleton1 {
    //第一步:让构造方法私有
    private void Singleton1(){}
    //第二步:自己创建这个类的实例对象
    private static  final Singleton1 st1=new Singleton1();
    //第三步:定义静态方法,获取唯一实例
    public static Singleton1 getInstance(){
        return st1;
    }

}

测试类:
public class Singleton1Test {
    public static void main(String[] args) {
       Singleton1 st1= Singleton1.getInstance();
       Singleton1 st2=Singleton1.getInstance();
        System.out.println(st1==st2);//true证明只有一个对象
    }
}

(2).懒汉式单例模式:(用到实例对象时才创建,不像饿汉式那样随着类的加载就创建)
第一步:构造方法私有;
第二步:只声明有实例对象,不创建;
第三步:在获取实例方法中创建对象;注意要进行判断对象是不是刚开始的null,
第一次才创建对象,后面就不创建了,注意在方法上也要加上锁synchronized,保证在多线程下单例的安全。
注:静态方法上的synchronized锁住类对象,普通方法锁住this对象;

//设计模式之懒汉单例模式
public class Singleton2 {
    //第一步私有化构造函数
    private Singleton2(){}
    //第二步只声明实例对象,不实现
      private  static Singleton2 ST;
    //第三步定义获取实例方法,并实现实例对象创建
    //在多线程时 为了保证安全,需加锁Syncthronize
    public synchronized static Singleton2 getInstance(){
        //进行判断,只有第一次时才创建对象
        if(ST==null){
            ST=new Singleton2();
        }
        return ST;
    }
}

(3).用枚举类实现单例 (属于饿汉式单例);
//枚举类型创建单例模式
public enum Singleton3 {
ST;
}
(4).懒汉式单例改进:
在(2)中的懒汉式模式中,在多线程中,每次调用方法都要加锁,锁很浪费资源,所以现在有了一个改进方法,采用静态内部类, 在多线程中第一次枷锁,第二次及以后不加锁;
第一步:私有化构造;
第二步:用静态内部类创建唯一实例;(类只加载一次,所以只创建了一次对象)
第三步:获取唯一实例;
代码如下:

//懒汉式单例模式的改进,采用静态内部类
public class Singleton4 {
    //第一步私有化构造
    private Singleton4(){}
    //第二步用静态内部类创建唯一实例
    static class Inner{
        static Singleton4 ST=new Singleton4();
    }
    //第三步获取实例
    public static Singleton4 getInstance(){
        return Inner.ST;
    }

}

2.享元模式 flyweight
(1).提倡重用已有的对象,而不是创建新的对象;
Integer的享元范围:-128到127;
后面学习连接池时也会用到享元模式:对数据库连接对象进行重用。

public class Flyweight {
    public static void main(String[] args) {
        //Integer类的源码就是享元模式,享元范围是-128到127
        System.out.println(Integer.valueOf(1)==Integer.valueOf(1));//true
        System.out.println(Integer.valueOf(127)==Integer.valueOf(127));//true
        System.out.println(Integer.valueOf(200)==Integer.valueOf(200));//false
    }
}

3.原型模式prototype
(1).根据已有对象来创建新的对象,克隆;
(2).要求:需要实现一个接口:Cloneable,并且需要重写其父类Object中的c lone()方法。
代码如下:

public class Prototype implements Cloneable{
    @Override
    protected  Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    private String name;
    private  int age;
    private  Date birthday;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}
测试类:
public class PrototypeTest1 {
    public static void main(String[] args) throws CloneNotSupportedException {
        copy();//浅拷贝

    }

    private static void copy() throws CloneNotSupportedException {
        Prototype pt = new Prototype();
        pt.setName("小明");
        pt.setAge(18);
        pt.setBirthday(new Date());
        System.out.println(pt.getName());
        System.out.println(pt.getAge());
        System.out.println(pt.getBirthday());
        System.out.println("==================");
        //克隆的另一个对象
        Prototype pt2= ( Prototype )pt.clone();
        System.out.println(pt==pt2);//false
        pt2.setName("小红");
        System.out.println("新克隆用户的名字:"+pt2.getName());
        System.out.println("小明的名字:"+pt.getName());
        pt2.getBirthday().setDate(15);
        //新克隆用户的生日改变了,随之也把小明的生日改变了
        //克隆对于引用数据类型仅仅复制的是地址,内容没有复制,
        // 同一个地址中,内容改变了,其他引用此地址的对象的内容随之改变。
        System.out.println("新克隆用户的生日:"+pt2.getBirthday());
        System.out.println("小明的生日:"+pt.getBirthday());
    }
}

(3).使用场景:当对象属性非常多时,希望新的对象的大部分属性是从原对象复制过来的。
(4)常遇到的问题:浅拷贝与深拷贝
刚才的Cloneable是浅拷贝,也就是说对象的属性仅仅是复制了地址,没有把内容
复制一份。当更改克隆出来的引用数据类型对象时,也会把原来对象的值也给改变(基本类型用浅拷贝可以完全拷贝,引用数据类型要用深拷贝)。
深拷贝是指所有的内容都得是全新的,深拷贝可以用反序列化来完成。
代码如下:

//深拷贝,采用反序列化流,需要实现Serializable接口
public class Prototype2 implements Cloneable,Serializable {
    @Override
    protected  Object clone()  {
       // return super.clone();不再直接使用父类的克隆方法了
        //定义了一个字节数组流
       ByteArrayOutputStream bos=new ByteArrayOutputStream();

        try {
            //定义一个序列化流
            ObjectOutputStream os=new ObjectOutputStream(bos);
            os.writeObject(this);//把当前对象写入字节数组流

            //取出字节数组
            byte[] bytes=bos.toByteArray();

            //反序列化为对象
            ByteArrayInputStream bis=new ByteArrayInputStream(bytes);
            ObjectInputStream ois=new ObjectInputStream(bis);
            return  ois.readObject();

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
    private String name;
    private  int age;
    private Date birthday;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}

测试类同浅拷贝一样,只是输出结果中新克隆用户的生日改变了,小明的生日将不再改变了。
4.建造器模式:(Builder)
问题:person
String sex ; string name; Integer weight;
目的:让创建对象的过程更为灵活;适用于一步一步创建更为复杂的某些属性。
代码如下:

public class Person {
    private  String name;
    private String sex;
    private Integer weight;
    private Integer height;
    public Person(String name,String sex,Integer weight,Integer height){
        this.name=name;
        this.sex=sex;
        this.weight=weight;
        this.height=height;
    }
    //建造器
    public static class PersonBuilder{
        private  String name;
        private String sex;
        private Integer weight;
        private Integer height;
        //返回值是构造器本身
        public PersonBuilder name(String name){
            this.name=name;
            return this;
        }
        public PersonBuilder sex(String sex){
            this.sex=sex;
            return this;
        }
        public PersonBuilder weight(Integer weight){
            this.weight=weight;
            return this;
        }
        public PersonBuilder height(Integer height){
            this.height=height;
            return this;
        }
        //定义一个方法,搜集信息,返回类型为Person类
        public Person build(){
            return new Person(name,sex,weight,height);
        }
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", weight=" + weight +
                ", height=" + height +
                '}';
    }   
}
测试类:
public class PersonTest {
    public static void main(String[] args) {
        //可以打点连调是因为返回的类型就是PersonBuilder类,
        //这就是建造器中的方法为什么要返回PersonBulider类型的原因。
        Person p1=new Person.PersonBuilder()
                .name("小明")
                .sex("男")
                .weight(60).build();
        System.out.println(p1);
        Person p2=new Person.PersonBuilder()
                .name("小红")
                .height(160)
                .build();
        System.out.println(p2);
    }
}

5.迭代器模式(iterator)
(1).定义:以一种一致的方式对集合内的元素进行遍历,而不在乎集合的数据结构。
(2)for(Object o:list)的底层就是迭代器模式。
6.策略模式(strategy)
(1)Java集合或者数组的排序算法;
基本数据类型:双基点的快速排序;
对象类型:TimSort(早期的JDK使用归并排序);
规模小:插入排序;
(2)排序的算法是固定的,排序的规则能否固定-------不能。
把排序的规则抽出来, 形成比较器接口(Comparator),不同比较器的实现称之为策略。
(3)Open close 开闭原则;
算法不能更改-----体现的是close原则;
比较器可以改------体现的是open原则;
代码如下:


public class StrategyStudent {
    public static void main(String[] args) {
        Student s1=new Student("Zhangsan",12);
        Student s2=new Student("Lisi",19);
        Student s3=new Student("Bob",10);
        Student s4=new Student("Wangming",21);
        Student s5=new Student("Tommy",16);
        Student s6=new Student("Tommy",19);
        List<Student> list=new ArrayList<>();
        list.add(s1);
        list.add(s2);
        list.add(s3);
        list.add(s4);
        list.add(s5);
        list.add(s6);

        //按年龄从小到大顺序输出
        Collections.sort(list, ( o1,  o2) -> {return o1.getAge()-o2.getAge(); });
        System.out.println(list);
        //按年龄从大到小顺序输出
        Collections.sort(list, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return -o1.getAge()-o2.getAge();
            }
        });
        System.out.println(list);
        //按姓名字母的字典顺序输出
        Collections.sort(list, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return  o1.getName().compareTo(o2.getName());
            }
        });
        System.out.println(list);
        //先按名字再按年龄排
        Collections.sort(list,(o1,o2)->{
            int b=o1.getName().compareTo(o2.getName());
            if(b==0){
                return o1.getAge()-o2.getAge();
            }else{
                return b;
            }
        });
        System.out.println(list);
    }
}
Student类如下:
public class Student {
    private String name;
    private  int age;

   public Student(String name,int age){
       this.name=name;
       this.age=age;
   }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值