day28【设计模式】

1.单例设计模式

1.作用

​ 单例设计模式的意思是,一个类只允许创建一个实例,也就是一个对象,对象在堆内存中只能开辟一个空间。

2.实现步骤

  1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
  2. 在该类内部产生一个唯一的实例化对象,并且将其封装为private static final类型的成员变量。
  3. 定义一个静态方法返回这个唯一对象。

3. 单例设计模式的类型

根据实例化对象的时机单例设计模式又分为以下两种:

  1. 饿汉单例设计模式

    饿汉单例设计模式就是使用类的时候已经将对象创建完毕,不管以后会不会使用到该实例化对象,先创建了再说。很着急的样子,故被称为“饿汉模式”。

  2. 懒汉单例设计模式

    懒汉单例设计模式就是调用getInstance()方法时实例才被创建,先不急着实例化出对象,等要用的时候才实例化出对象。不着急,故称为“懒汉模式”。

4.代码实现

  • 饿汉式

    • 比较饥饿,着急创建出来唯一的一个对象

      /*
      	单例设计模式
          比较饥饿,着急创建出来唯一的一个对象
      */
      public class Single
      {
      	//1、私有化构造函数
      	private Single(){}
      	//2、创建一个本类的对象
      	private static final Single s=new Single();
      	//3、定义一个方法返回本类的对象
      	public static Single getInstance()
      	{
      		return s;
      	}
      	//测试方法
      	public void test()
      	{
      		System.out.println("测试方法");
      	}
      }
      class SingleDemo 
      {
      	public static void main(String[] args) 
      	{
      		/*
      			要想获取到Single类的对象,调用getInstance方法
      			既然不能通过对象来调用,那么只能通过类名来调用
      			如果要想通过类名来调用方法,那么被调用的方法必须用static来修饰
      		*/
      		Single s1=Single.getInstance();
      		s1.test();
      		//Single s2=Single.getInstance();
      	}
      }
      
  • 懒汉式

    • 比较懒惰,什么时候用对象,就什么时候创建

      public class Single {
          //比较懒惰,什么时候用对象,就什么时候创建
      
          //构造方法私有化
          private Single(){
      
          }
      
          //创建一个唯一的对象
          private static Single s = null;
      
          //获取对象的方法
          public static synchronized Single getSingle(){
              //如果值是null,说明没有创建过这个对象
              if(s == null){//t1 t2
                  s = new Single();
              }
      
              return s;
          }
      }
      

注意:懒汉单例设计模式在多线程环境下可能会实例化出多个对象,不能保证单例的状态,所以加上关键字:synchronized,保证其同步安全。

5. 小结

单例模式可以保证系统中一个类只有一个对象实例。

实现单例模式的步骤:

  1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
  2. 在该类内部产生一个唯一的实例化对象,并且将其封装为private static final类型的成员变量。
  3. 定义一个静态方法返回这个唯一对象。

2.多例设计模式

多例模式,是一种常用的软件设计模式。通过多例模式可以保证系统中,应用该模式的类有固定数量的实例。多例类要自我创建并管理自己的实例,还要向外界提供获取本类实例的方法。

  • 作用

    ​ 一个类可以创建多个对象,有多个实例。

  • 实现步骤

    1.创建一个类, 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。

    ​ 2.在类中定义该类被创建的总数量

    ​ 3.在类中定义存放类实例的list集合

    ​ 4.在类中提供静态代码块,在静态代码块中创建类的实例

    ​ 5.提供获取类实例的静态方法

  • 代码演示

    • 比如一个类只允许创建3个对象。

      public class Person {
          //这个类一共创建3个对象
      
          //构造方法私有化
          private Person(){}
      
          //定义集合用于保存多个对象
          private static ArrayList<Person> list = new ArrayList<>();
      
          //静态代码块,只会执行一次,且是在这个类最开始最先执行
          static{
              //创建3个对象放在集合里
              for (int i = 0; i < 3; i++) {
                  list.add(new Person());
              }
          }
      
          //定义供外界访问的获取对象的方法
          public static Person getPerson(){
              //随机一个对象返回给调用者
              //创建随机对象
              Random r = new Random();
              //获取索引
              int i = r.nextInt(3);
              //根据索引从集合中获取对象
              Person person = list.get(i);
              //返回给调用者
              return person;
          }
      }
      
      
      public class Demo {
          public static void main(String[] args) {
      
              //获取10次,但是获取到的其实就是3个对象
              for (int i = 0; i < 10; i++) {
                  Person person = Person.getPerson();
                  System.out.println(person);
              }
          }
      }
      

3.动态代理

1.动态代理介绍和引入

  • 代理模式概念

    为什么要有“代理”?生活中就有很多例子,例如委托业务等等,代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事,这才是“代理”存在的原因。例如,我现在需要出国,但是我不愿意自己去办签证、预定机票和酒店(觉得麻烦 ,那么就可以找旅行社去帮我办,这时候旅行社就是代理,而我自己就是被代理了。

    在我们的代码中,假如有以下业务情景:

    ​ 用户登录到我们的系统后,我们的系统会为其产生一个ArrayList集合对象,内部存储了一些用户信息,而后,这个对象需要被传给后面的很多其它对象,但要求其它对象不能对这个ArrayList对象执行添加、删除、修改操作,只能get()获取元素。那么为了防止后面的对象对集合对象进行添加、修改、删除操作,我们应该怎样办呢?

    ​ 要想实现这种要求,方案有很多种。"代理模式"就是其中的一种,而且是非常合适的一种。

  • 动态代理概念

    动态代理简单来说是:拦截对真实对象(被代理对象)方法的直接访问,增强真实对象方法的功能

    动态代理详细来说是:代理类在程序运行时创建的代理对象被称为动态代理,也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。也就是说你想获取哪个对象的代理,动态代理就会动态的为你生成这个对象的代理对象。动态代理可以对被代理对象的方法进行增强可以在不修改方法源码的情况下,增强被代理对象方法的功能在方法执行前后做任何你想做的事情。动态代理技术都是在框架中使用居多,例如:Struts1、Struts2、Spring和Hibernate等后期学的一些主流框架技术中都使用了动态代理技术。

  • jdk的动态代理使用前提

    要使用动态代理,代理对象和被代理的对象所属类必须实现共同接口。

  • 演示Java已经实现的代理模式的思想,ArrayList使用工具类的演示:

    • Collections工具类有一个unmodifiableList()方法,可以传入被代理对象,返回一个代理对象,这个返回的代理对象不能调用增删改方法。
    static <T> List<T> unmodifiableList(List<? extends T> list)
        	参数:list是传入的被代理对象集合
        	返回值:返回的是代理对象集合,不能对集合进行增删改,如果增删改将导致抛出 		
    		UnsupportedOperationException:不支持操作异常
        说明:
    		unmodifiableList作用:传递List接口,方法内部对List接口进行代理,返回一个被代理后的List接口
    		对List进行代理之后,调用List接口的方法会被拦截:
    		如果使用的size,get方法,没有对集合进行修改,则允许执行
    		如果使用的add,remove,set方法,对集合进行了修改,则抛出运行时异常
    

    代码演示:

    public class Demo02 {
        public static void main(String[] args) {
    
            //创建集合
            ArrayList<String> list = new ArrayList<>();
    
            list.add("柳岩");
            list.add("老王");
            list.add("石原里美");
    
    
            //让这个集合不能对内容进行修改,不能调用:1) 添add 2) 删remove 3) 改set的方法
            List<String> list2 = Collections.unmodifiableList(list);
    
            //list2此时是一个代理对象,他这个对象不允许调用增删改方法
            //unmodifiableList这个方法返回的list2是一个代理对象,该方法内部使用的就是代理模式的思想,我们可以使用动态代理来模拟该方法内部原理
    
    //        list2.add("李四");//报异常
    //        list2.remove("柳岩");//报异常
            String s = list2.get(1);
            System.out.println(s);
        }
    }
    

说明:unmodifiableList这个方法返回的list2是一个代理对象,该方法内部使用的就是代理模式的思想,我们可以使用动态代理来模拟该方法内部原理

2.动态代理完成不允许对集合增删改

  • 测试类代码

    public class Demo03 {
        public static void main(String[] args) {
            //创建集合
            ArrayList<String> list = new ArrayList<>();
    
            list.add("柳岩");
            list.add("老王");
            list.add("石原里美");
    
    
            //让这个集合不能对内容进行修改,不能调用:1) 添add 2) 删remove 3) 改set的方法
            //List list2 = Collections.unmodifiableList(list);
            //使用我们自己定义的类和方法以及动态代理技术模拟:让这个集合不能对内容进行修改,不能调用:1) 添add 2) 删remove 3) 改set的方法
            List<String> list2 = MyColl.getList(list);
    
            //list2此时是一个代理对象,他这个对象不允许调用增删改方法
            //unmodifiableList这个方法返回的list2是一个代理对象,该方法内部使用的就是代理模式的思想,我们可以使用动态代理来模拟该方法内部原理
    
    //        list2.add("李四");//报异常
    //        list2.remove("柳岩");//报异常
            //list2.set(2,"老王");
            String s = list2.get(1);
            System.out.println(s);
            int size = list.size();
            System.out.println(size);
        }
    }
    
  • MyColl类:动态代理实现对代理对象的增强

    那么如何实现动态代理呢?

    获取某个被代理类的代理类对象这时必须使用Java中的Proxy这个类完成。

day28【设计模式】_第1张图片

注:在Java中当某个类需要被代理的时候,要求这个类中的被代理的方法必须抽取到一个接口中,然后这个类需要实现那个接口,只有在这个接口中的方法,代理类才能代理它。

在Proxy类中提供了一个方法,可以实现:

在这里插入图片描述
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 返回一个指定接口的代理类实例或者对象。

  • loader:类加载器。一个类的字节码文件不可能直接就出现在方法区中,必须通过一个类的类加载器 将 类的字节码文件加载到方法区中,所以需要一个类加载器。

​ 那么我们如何确定这个类加载器呢?

​ 说明:这个类加载器可以随便给,但是一般情况下我们给被代理的对象的类加载器即可。

​ 举例: 创建被代理对象list的对象: ClassLoader loader = list.getClass().getClassLoader(); 有了这个加 载器了,这样就可以在方法区中给我们加载出来一个代理类的Class对象了。

  • Class[] interfaces:被代理对象的所有接口的数组,说明把接口的字节码文件放在这里即可,因为接口的字节码文件中就存在函数。

​ 注:Class[] getInterfaces() 通过字节码文件对象,获取其所有接口的数组。

​ 代码如:Class[] interfaces = list.getClass().getInterfaces();

​ 3) InvocationHandler h:调用处理器 ,是一个接口。

day28【设计模式】_第2张图片

所以我们需要自己定义一个类来实现这个接口,或者我们也可以使用匿名内部类来实现。

代码如:

InvocationHandler h = new InvocationHandler()
{
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
 		{
 		}
 };

说明:

A:invoke函数属于调用处理器InvocationHandler 接口中的函数,所以实现类必须复写这个函数;
在这里插入图片描述

​ 参数:

​ 1)proxy:就是代理对象本身。这里不用管;

​ 2)method:当前代理对象正在调用的方法;

​ 3)args :当前正在调用的方法的实际参数;

代码实现:

@SuppressWarnings("all")
public class MyColl {
    /*
       getList方法:
           参数代表的是被代理对象
           返回值代表是代理对象(中介)
    */
    public static List<String> getList(List<String> list) {

        /*
         * 动态代理演示
         * 动态代理:就是在程序运行的过程中,动态的生成一个类,这个类要代理目标业务对象,并且可以动态生成这个代理类的对象。
         * 如何实现:
         * Proxy类中提供了一个方法,可以实现:
         * static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
         *        返回一个指定接口的代理类实例
         *        参数:
         *          loader:类加载器,一个类的字节码文件不可能直接就出现在方法区中,必须通过类加载器加载,所以需要一个类加载器。
         *              一般给被代理的对象的类加载器
         *              注意:这里要保证被代理对象和代理对象所属类的类加载器要一样。而这里都是list,索引类加载器都是根类加载器
         *          Class[] interfaces:被代理对象的所有接口的数组,说明把接口的字节码文件放在这里即可,因为接口的字节码文件中就存在函数。
         *                            通过获取到接口获取接口中的方法,这样后面才可以对方法进行增强
                                Class[] getInterfaces() 通过字节码文件对象,获取其所有接口的数组
         *          InvocationHandler h:调用处理器 ,是一个接口,所以我们需要自己定义一个类来实现这个接口。
         *        返回值:返回的是生成的代理对象
         */
        //获取类加载器
        ClassLoader classLoader = list.getClass().getClassLoader();
        //获取被代理对象的接口
        Class<?>[] interfaces = list.getClass().getInterfaces();
        //调用处理器 修改代理对象拦截被代理对象的方法
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            /*
                invoke()方法:
                在使用代理对象调用任何方法时,都会执行到invoke方法中,在invoke方法中给出处理方式,无论是add,remove,get都是这样
                参数:
                Object proxy     代理对象(在这里没用)
                Method method    当前代理对象正在被调用的方法的Method对象
                Object[] args    执行方法时传入的实际参数
                返回值:
                Object 实际执行完方法后得到的返回值.举例:String s = list2.get(1); 那么s接收的就是这个null
             */
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                /*
                    list2.add("李四") :
                        方法名:add
                        参数:李四
                        
                    list2.set(2,"老王");
                        方法名:set
                        参数:[2, 老王] 
                 */
                //输出被调用方法名
                System.out.println(method.getName());
                //输出被调用方法的参数
                System.out.println(Arrays.toString(args));

                //这个返回值会返回给调用方法的调用者
                return null;
            }
        };
        //动态代理
        List<String> list2 = (List<String>) Proxy.newProxyInstance(classLoader, interfaces,invocationHandler );
        //返回代理对象
        return list2;
    }
}
  • 流程图

day28【设计模式】_第3张图片

  • 最终代码实现:不允许集合增删改

    package com.itheima.sh.demo_04;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.Arrays;
    import java.util.List;
    
    @SuppressWarnings("all")
    public class MyColl {
        /*
           getList方法:
               参数代表的是被代理对象
               返回值代表是代理对象(中介)
        */
        public static List<String> getList(List<String> list) {
    
            /*
             * 动态代理演示
             * 动态代理:就是在程序运行的过程中,动态的生成一个类,这个类要代理目标业务对象,并且可以动态生成这个代理类的对象。
             * 如何实现:
             * Proxy类中提供了一个方法,可以实现:
             * static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
             *        返回一个指定接口的代理类实例
             *        参数:
             *          loader:类加载器,一个类的字节码文件不可能直接就出现在方法区中,必须通过类加载器加载,所以需要一个类加载器。
             *              一般给被代理的对象的类加载器
             *              注意:这里要保证被代理对象和代理对象所属类的类加载器要一样。而这里都是list,索引类加载器都是根类加载器
             *          Class[] interfaces:被代理对象的所有接口的数组,说明把接口的字节码文件放在这里即可,因为接口的字节码文件中就存在函数。
             *                            通过获取到接口获取接口中的方法,这样后面才可以对方法进行增强
                                    Class[] getInterfaces() 通过字节码文件对象,获取其所有接口的数组
             *          InvocationHandler h:调用处理器 ,是一个接口,所以我们需要自己定义一个类来实现这个接口。
             *        返回值:返回的是生成的代理对象
             */
            //获取类加载器
            ClassLoader classLoader = list.getClass().getClassLoader();
            //获取被代理对象的接口
            Class<?>[] interfaces = list.getClass().getInterfaces();
            //调用处理器 修改代理对象拦截被代理对象的方法
            InvocationHandler invocationHandler = new InvocationHandler() {
                @Override
                /*
                    invoke()方法:
                    在使用代理对象调用任何方法时,都会执行到invoke方法中,在invoke方法中给出处理方式,无论是add,remove,get都是这样
                    参数:
                    Object proxy     代理对象(在这里没用)
                    Method method    当前代理对象正在被调用的方法的Method对象
                    Object[] args    执行方法时传入的实际参数
                    返回值:
                    Object 实际执行完方法后得到的返回值.举例:String s = list2.get(1); 那么s接收的就是这个null
                 */
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    /*
                        list2.add("李四") :
                            方法名:add
                            参数:李四
    
                        list2.set(2,"老王");
                            方法名:set
                            参数:[2, 老王]
                     */
                    //输出被调用方法名
    //                System.out.println(method.getName());
                    //输出被调用方法的参数
    //                System.out.println(Arrays.toString(args));
                    ////////////////////////////////////////////////////////////////////////////////////////
                    //目的是不让调用增删改的方法
    
                    //判断方法名如果是增删改就产生异常
                    if(method.getName().equals("add") || method.getName().equals("remove") || method.getName().equals("set")){
                        //产生异常
                        throw new RuntimeException("不能调用" + method.getName() + "方法");
                    }
                    //判断方法名如果是其他方法就正常执行
                    //method是一个方法
                    //执行方法
                    /*
                        invoke(Object o,Object... obj)
                            o   代表的是执行的哪个对象
                            obj 代表的方法的实际参数
                     */
                    //list表示被代理对象,args表示被执行方法的实参   result 表示执行的方法返回的结果
                    //例如:调用的方法:String s = list2.get(1); ---》args表示1  将获取的结果result给s
                    Object result = method.invoke(list, args);
                    //这个返回值会返回给调用方法的调用者
                    return result;
                }
            };
            //动态代理
            List<String> list2 = (List<String>) Proxy.newProxyInstance(classLoader, interfaces,invocationHandler );
            //返回代理对象
            return list2;
        }
    }
    

注意:

上述代码生成的代理类对象必须使用List接口接收,不能使用ArrayList类接收,因为ArrayList和代理类没有关系,只是实现了共同父接口List.

//list2表示代理类对象
List<String> list2 = (List<String>) Proxy.newProxyInstance(classLoader, interfaces,invocationHandler );//正确
 //list2表示代理类对象
 ArrayList<String> list2 = (ArrayList<String>) Proxy.newProxyInstance(classLoader, interfaces,invocationHandler );//错误

day28【设计模式】_第4张图片

3.动态代理完成:集合只允许添加四个字的字符串

  • 测试类

    public class Demo04 {
        public static void main(String[] args) {
            //创建集合
            ArrayList<String> list = new ArrayList<>();
    
            //添加方法
            list.add("石原里美");
            list.add("新垣结衣");
    
            //用动态代理的方式返回一个代理对象,要求代理对象只能添加长度为4的字符串
            List<String> list2 = MyColl2.getList(list);
    
            //添加
            list2.add("桥本环奈");
            //list2.add("柳岩");
            System.out.println(list2);
        }
    }
    
  • 动态代理生成的代理类对象

    package com.itheima.sh.demo_04;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.ArrayList;
    import java.util.List;
    @SuppressWarnings("all")
    public class MyColl2 {
        public static List<String> getList(ArrayList<String> list){
            //动态代理
            //返回值地方只能接口不能写具体类型
            List<String> list2 = (List<String>) Proxy.newProxyInstance(list.getClass().getClassLoader(), list.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //对其他方法没有限制
                    //对添加方法 只允许添加长度为4的字符串
                    if(method.getName().equals("add")){
                        //判断参数的长度是否为4
                        String s = (String) args[0];
                        if(s.length() != 4){
                            //产生异常
                            throw new RuntimeException("添加的字符串长度必须是4");
                        }
                    }
    
                    //如果是其他情况就要正常执行
                    Object result = method.invoke(list, args);
    
                    return result;
                }
    
            });
            return list2;
        }
    }
    

4. 总结

  • 动态代理非常的灵活,可以为任意的接口实现类对象做代理

  • 动态代理可以为被代理对象的所有接口的所有方法做代理,动态代理可以在不改变方法源码的情况下,实现对方法功能的增强,

  • 动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。

  • 动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。

  • 动态代理同时也提高了开发效率。

  • 缺点:只能针对接口的实现类做代理对象,普通类是不能做代理对象的。

4.工厂设计模式

  • 介绍

    工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。之前我们创建类对象时, 都是使用new 对象的形式创建, 除new 对象方式以外, 工厂模式也可以创建对象.

  • 没有使用工厂设计模式创建对象即以前创建对象方式的问题

    • 假设定义三个车类 BaoMa BenChi Wulin ,然后在测试类创建三个类的对象

    • 代码演示:

      public class BaoMa {
      }
      public class BenChi {
      }
      public class AoDi {
      }
      public class Test01 {
          public static void main(String[] args) {
              //创建三个类的对象
              BaoMa baoMa = new BaoMa();
              BenChi benChi = new BenChi();
              AoDi aoDi = new AoDi();
          }
      }
      

      问题说明:

      ​ 1.假设当前项目下具有很多个测试类,都要使用这三个类,然后我想统计每个类的对象有多少个,那么 这样统计就会很麻烦

      ​ 2.测试类和这三个类还耦合在一起了,我们应该降低耦合

  • 使用工厂设计模式创建对象

    • 实现步骤
      • 编写一个Car接口
      • 编写一个BaoMa类实现Car接口
      • 编写一个Benchi类实现Car接口
      • 编写一个AoDi类实现Car接口
      • 提供一个CarFactory(汽车工厂),定义静态方法用于生产汽车对象
      • 定义CarFactoryTest测试汽车工厂
  • 代码演示

    package com.itheima.sh.demo_04;
    /*
        汽车工厂类
     */
    public class CarFactory {
        //工厂专门用来创建汽车对象
        //name表示调用该方法时指定的车类型
        public static Car getCar(String name){
            if(name.equals("BaoMa")){
                return new BaoMa();
            }else if(name.equals("BenChi")){
                return new BenChi();
            }else if(name.equals("AoDi")){
                return new AoDi();
            }
    
            return null;
        }
    }
    //汽车
    public interface Car {
    }
    public class BaoMa implements Car{
         //宝马
    }
    public class BenChi implements Car{
        //奔驰
    }
    public class AoDi implements Car{
        //奥迪
    }
    //测试类
    public class Test01 {
        public static void main(String[] args) {
            //创建三个类的对象
    //        BaoMa baoMa = new BaoMa();
    //        BenChi benChi = new BenChi();
    //        AoDi aoDi = new AoDi();
    
            //---------------------------------
            //使用工厂创建对象
            Car baoMa = CarFactory.getCar("BaoMa");
            System.out.println(baoMa);
    
            Car benChi = CarFactory.getCar("BenChi");
            System.out.println(benChi);
    
            Car AoDi = CarFactory.getCar("AoDi");
            System.out.println(AoDi);
        }
    }
    

小结:

  • 工厂模式的存在可以改变创建类的方式

  • 方便管理对象

  • 降低类与类之间的耦合,调用工厂类中的方法直接指定字符串即可,创建对象的事情都交给工厂类

5.Lombok【自学扩展】

1.lombok介绍

​ Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。出现的神奇就是在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法。这样就省去了手动重建这些代码的麻烦,使代码看起来更简洁些。

2.lombok使用

​ 1. 添加lombok的jar包:

​ 将lombok.jar(本例使用版本:1.18.10),添加到模块目录下,并添加到ClassPath

day28【设计模式】_第5张图片

2. 为IDEA添加lombok插件(连接网络使用)
  • 第一步

day28【设计模式】_第6张图片

  • 第二步:

day28【设计模式】_第7张图片

  • 第三步:

day28【设计模式】_第8张图片

注意:一定勾选上Enable annotation processing 按钮才可以使用lombok,否则不能使用。

  • 第四步:安装完毕后,重启IDEA。

3.新建一个类:Student

public class Student {
    private String name;
    private int age;
}

4.lombok常用注解

  • @Getter和@Setter

    • 作用:生成成员变量的get和set方法。
    • 写在成员变量上,指对当前成员变量有效。
    • 写在类上,对所有成员变量有效。
    • 注意:静态成员变量无效。
  • @ToString:

    • 作用:生成toString()方法。
    • 该注解只能写在类上。
  • @NoArgsConstructor和@AllArgsConstructor

    • @NoArgsConstructor:无参数构造方法。
    • @AllArgsConstructor:满参数构造方法。
    • 注解只能写在类上。
  • @EqualsAndHashCode

    • 作用:生成hashCode()和equals()方法。
    • 注解只能写在类上。
  • @Data

    • 作用: 生成setter/getter、equals、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。

    • 注解只能写在类上。

  • 编写代码

    package com.itheima.sh.demo_04;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data // setter/getter、equals、hashCode、toString方法
    @NoArgsConstructor//无参构造
    @AllArgsConstructor//满参构造
    public class Student {
        private String name;
        private int age;
    }
    public class Test01 {                                                          
        public static void main(String[] args) {                                   
            Student s = new Student();                                             
            Student s1 = new Student("张三",20);                                     
                                                                                   
            System.out.println("s = " + s);      // s = Student(name=null, age=0)  
            System.out.println("s1 = " + s1);   //  s1 = Student(name=张三, age=20)  
            System.out.println(s1.getName());    // 张三                             
        }                                                                          
    }                                                                              
    

你可能感兴趣的:(java,设计模式,java)