无声specialweek

从零开始学Java-Day18

设计模式

设计模式是Java发展过程中总结出来的一些值得借鉴的优秀编程经验

设计模式一共有23种,主要分为三大类

单例设计模式

核心思想:确保实例只有一个

好处:可以节省内存空间,方便控制资源

实现思路

  1. 构造方法私有化--阻止外部直接调用本类的构造方法创建对象
  2. 创建本类对象且私有化--为了防止外部多次获取本类对象
  3. 对外提供一个公共全局访问点--按照预先设置的方式来获取对象

饿汉式:加载时事先创建好类的对象

懒汉式:不会再初始化就加载所有资源,在用的时候才加载

单例设计模式方案二:懒汉式

不会再初始化类的时候就创建本类对象,而是用的时候(调用get())才创建

代码实现思路:

  • ​ 将创建对象拆分成两步:
    • 先定义引用类型变量,默认值null
    • 在get()里判断(之前是否创建过),如果没创建过,创建,创建过返回创建的对象.
package cn.tedu.design;
//本类用于测试单例模式实现方式一:饿汉式
public class Singleton1 {
    public static void main(String[] args) {
        MySingle single = MySingle.getSingle();
        MySingle single2 = MySingle.getSingle();
        System.out.println(single);
        System.out.println(single2);
        System.out.println(single == single2);
    }
}
/*
 *思考:在构造方法与对象被私有化后,需要调用公共的全局访问点来获取本类对象,但是,
 * 我们如何调用这个公共方法
 * 之前调用方法都是通过类对象进行调用,但单例因为构造方法私有化无法创建对象。
 * 解决方案:可以将公共方法设置为静态方法,因此可以直接通过类来调用。
 * 因为公共方法是静态的所以类里创建的对象也要静态修饰
 */
class MySingle{
    //构造方法私有化:防止外界随意实例化本类对象
    private MySingle() {}
    private static MySingle single = new MySingle();

    public static MySingle getSingle(){
        return single;
    }
}

package cn.tedu.design;
//单例测试模式方案二:懒汉式--面试重点
public class Singleton2 {
    public static void main(String[] args) {
        MySingle2 single1 = MySingle2.getMySingle2();
        MySingle2 single2 = MySingle2.getMySingle2();
        System.out.println(single2);
        System.out.println(single1);
        System.out.println(single1 == single2);//true
    }
}

class MySingle2{
    private MySingle2(){}
    static private MySingle2 mySingle2;
    /*
     *在多线程下会有数据隐患
     * 解决方案一:同步代码块锁
     * 解决方案二:把该方法用 synchronized 修饰
     */
    public synchronized static MySingle2 getMySingle2() {
        if (mySingle2 == null) {
            mySingle2 = new MySingle2();
        }
        return mySingle2;
    }
}

注解与自定义注解

注解很厉害,它可以增强我们的Java代码,同时利用反射技术可以扩充实现很多功能。它们被广泛应用于三大框架底层。
传统我们通过xml文本文件声明方式(如下图,但是XML比较繁琐且不易检查),而现在最主流的开发都是基于注解方式,代码量少,框架可以根据注解去自动生成很多代码,从而减少代码量,程序更易读。例如最火爆的SpringBoot就完全基于注解技术实现。

分三类

  • JDK注解

    • @override
  • 元注解:用来定义其他注解的注解

    • @Target注解用的范围:类上、方法上、属性上等
    • @Retention注解的生命周期:源文件中、字节码文件中、运行中
      • SOURCE:在源文件中有效(即源文件保留)
      • CLASS:在class文件中有效(即class保留)
      • RUNTIME:在运行时有效(即运行时保留)
    • @Inherited 允许子注解继承
    • @Documented 生成javadoc时会包含注解,不常用
    • @Repeatable 注解为可重复类型注解,可以在同一个地方多次使用,不常用
  • 自定义注解

    1. 自定义注解需要元注解来指定,语法:@interface 注解名{}
    2. 使用@Target注解定义自定义注解的作用位置,可以指定多个,格式:
    3. 使用@Retention注解定义自定义注解的生命周期,只能指定一个
    4. 使用注解时,@符号 + 注解名直接使用
    5. 自定义注解可以添加属性
      1. 普通属性int age(); 赋值格式: @Test(age = 18)
      2. 特殊属性int value(); 赋值格式:@Test(18)
    • 一旦添加了属性必须赋值
    • 特殊属性不限制类型,限制的是属性的名字
    • 特殊属性和普通属性赋予默认的格式一样 int age() default 15;
package cn.tedu.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//本类用于测试自定义注解,熟悉注解的相关规则
public class TestAnnotation {
    public static void main(String[] args) {
        new MeiGeMi().skill();
    }

}

/*
 *0.首先注意:自定义注解的语法和Java不同,不要套用Java格式
 *1.注解定义要使用@interface 注解名的方式来定义
 *  1.1通过@Target注解来定义当前自定义注解使用的位置| 注意导包 | ElementType.静态常量 | 输入的是一个数组,可以用 , 隔开元素
 *  1.2通过使用@Retention注解来定义当前自定义注解使用的生命周期| 注意导包 |RetentionPolicy.静态常量
 * 决定注解的存活时间,只能存在一个
 *
 */
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
@interface Test{
    /*自定义注解可以添加功能--给自定义注解添加属性
    * 注意:int age();不是方法的定义,而是自定义注解中定义age属性的语法
    * 定义属性后,才使用自定义注解时要在注解后的括号里定义同类型的值,如果在定义属性时
    * 赋予默认值了可以直接使用
    * 注解中的新功能:定义特殊属性value*/
    int height() default 0;
    String value() default "一马当先,万马无光";
}
class MeiGeMi{
    @Test
    String name;
    public void skill(){
        System.out.println("Explosion!!!!!!!!!!!!!!");
    }
}

反射

获取字节码对象

  • Class.forName("类的全路径")
  • 类名.class
  • 对象.getClass();

反射是一种经典常用的技术,通常用来获取或才做其他人的资源

反射的前提是获取字节码对象 + 反射技术获取目标类的所有构造方法

具体方法详见API手册

单元测试方法

package cn.tedu.reflection;
//本类用于测试反射而准备的物料类
public class Student {
    String name;
    private int age;
    private static String skill;

    public Student() {
    }

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

    public void learn(){
        System.out.println("学习!");
    }
    private void play(String gameName){
        System.out.println("冲冲冲!!!" + gameName);
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
package cn.tedu.reflection;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;

//本类用来测试反射
public class TestReflect1 {
    /*单元测试方法:是Java测试的最小单位,使用灵活
    * 语法要求:@Test
    *          void + 没有参数 + public
    * 使用时需要导包*/
    @Test
    public void getClazz() throws ClassNotFoundException {
        Class<?> stu1 = Class.forName("cn.tedu.reflection.Student");
        Class<Student> stu2 = Student.class;
        Class<? extends Student> stu3 = new Student().getClass();
        System.out.println(stu1);//class cn.tedu.reflection.Student
        System.out.println(stu1.getName());//cn.tedu.reflection.Student
        System.out.println(stu2.getPackage().getName());//cn.tedu.reflection
        System.out.println(stu3.getSimpleName());//Student
    }
    @Test
    public void getConstruct() throws NoSuchMethodException {
        Class<Student> stu = Student.class;
        Constructor<?>[] cs = stu.getConstructors();
        Method[] method = stu.getMethods();
        for (Method method1 : method) {
            Class[] cp = method1.getParameterTypes();
            System.out.println(Arrays.toString(cp));
        }

        for (Constructor<?> c : cs) {
            //System.out.println(c.getName());
            Class[] cp = c.getParameterTypes();
            System.out.println(Arrays.toString(cp));
        }
    }

}

posted on 2021-06-24 19:08  无声specialweek  阅读(40)  评论(0编辑  收藏  举报

导航