概述

  • 之前的学习主要是先类,然后通过类创建的对象;所谓的反射,通过对象反过来对类进行相关的操作
  • 类的组成部分
    • 类的名称 -> Class(类的类)
    • 属性(成员变量)-> Field(属性类)
    • 一般方法 -> Method(方法类)
    • 构造方法-> Constructor(构造方法类)
  • 基本使用

    1. //1,获取类的类对象
    2. Class clazz = Student.class;
    3. System.out.println("类的名称:"+clazz.getName());
    4. //2,获取类的属性
    5. Field[] fields = clazz.getDeclaredFields();
    6. System.out.println("属性有:");
    7. for (Field field :fields) {
    8. System.out.print(field.getName()+",");
    9. }
    10. System.out.println("-----");
    11. //3,获取类的方法
    12. System.out.println("方法有:");
    13. Method[] methods = clazz.getDeclaredMethods();
    14. for (Method method:methods) {
    15. System.out.print(method.getName()+",");
    16. }
    17. System.out.println("-----");
    18. //4,获取构造方法
    19. System.out.println("构造方法有:");
    20. Constructor[] constructors = clazz.getDeclaredConstructors();
    21. for (Constructor constructor:constructors) {
    22. System.out.print(constructor.getName()+",");
    23. }

    类对象

  • 将所有的类,都是通过Class进行定义,每个不同的类的信息都是存储再Class创建的类的对象中的

  • Class类的对象获取几种方式

    • 第一种,直接通过类.class获取

      1. Class teacherClass = Teacher.class;
      2. Class studentClass = Student.class;
    • 第二种,通过对象获取(重点)

      1. Student student = new Student();
      2. Class studentClass1 = student.getClass();
      3. System.out.println(studentClass1.getName());
    • 第三种,通过类的名字来获取

      1. Class teacherClass2 = Class.forName("com.java2022.entity.Teacher");
      2. System.out.println(teacherClass2.getName());
    • 第四种,通过类加载器获取

      1. ClassLoader classLoader = ClassLoader.getSystemClassLoader();
      2. Class teacherClass3 = classLoader.loadClass("com.java2022.entity.Teacher");
  • 常用的方法 | 方法名 | 描述 | | —- | —- | | public String getName() | 获取类的完全名称 | | public Package getPackage() | 获取包信息 | | public Class<? super T> getSuperclass() | 获取父类 | | public Class<?>[] getInterfaces() | 获取实现父接口 | | public Field[] getFields() | 获取字段信息 | | public Method[] getMethods() | 获取方法信息 | | public Constructor<?>[] getConstructors() | 获取构造方法 | | public T newInstance() | 反射创建对象 |

  • 实现一个方法,传入类的名称,可以获取类创建的对象

    • 创建一个接口

      1. public interface IPerson {
      2. void say();
      3. }
    • 创建实现接口的类

      1. public class Teacher implements IPerson {
      2. @Override
      3. public void say() {
      4. System.out.println("我是个老师");
      5. }
      6. }
    • 实现创建对象方法

      1. //实现一个方法可以根据类的名称创建对象
      2. public static IPerson createInstance(String className){
      3. try {
      4. //获取className对应类的类对象
      5. Class<IPerson> clazz = (Class<IPerson>) Class.forName(className);
      6. //通过类的类对象创建对象
      7. return clazz.newInstance();
      8. } catch (ClassNotFoundException e) {
      9. e.printStackTrace();
      10. } catch (InstantiationException e) {
      11. e.printStackTrace();
      12. } catch (IllegalAccessException e) {
      13. e.printStackTrace();
      14. }
      15. return null;
      16. }
    • 测试对象的创建

      1. public static void main(String[] args) {
      2. IPerson iPerson = createInstance("com.java2022.entity.Worker");
      3. iPerson.say();
      4. }

      属性对象

  • Field是属性的类,由其创建的对象就是属性的对象

  • 属性对象主要用于存储类的属性的相关的信息
  • 通过类的类对象(Class)获取对应的类的属性的对象

    1. clazz.getDeclaredFields();//获取所有的属性
    2. //获取指定的属性
    3. Field field = clazz.getDeclaredField("age");
  • 通过属性对象(Feild)获取属性的相关的信息

    1. String name = field.getName();//获取属性的名称
    2. Class type = field.getType();//获取属性的类型类对象
    3. System.out.println("属性的名称:"+name);
    4. System.out.println("属性的类型:"+type.getName());
  • 通过属性对象,获取类创建对象的属性的值

    1. //通过一个对象,获取对象的所有的属性和对应值
    2. public static void get(Object obj){
    3. //获取对象的类对象
    4. Class clazz = obj.getClass();
    5. //获取对象的所有的属性对象
    6. Field[] fields = clazz.getDeclaredFields();
    7. for (Field field :fields) {
    8. field.setAccessible(true);//设置强制获取
    9. try {
    10. //获取属性对象对应的值
    11. Object value = field.get(obj);
    12. System.out.println(field.getName() + ":"+value);
    13. } catch (IllegalAccessException e) {
    14. e.printStackTrace();
    15. }
    16. }
    17. }
  • 设置属性的值

    1. Worker worker = new Worker(13,"开挖掘机的");
    2. //篡改编号
    3. Class clazz = worker.getClass();
    4. Field field = clazz.getDeclaredField("id");
    5. field.setAccessible(true);
    6. field.set(worker,2);//支持各种基本类型和包装类型,只要对象类型一致即可
    7. field.setInt(worker,4);//指定类型,必须是int类型,如果是是Integer请属性set

方法对象

  • 通过方法对象可以对类创建的对象的方法进行调用
  • 获取一个类的方法对象

    1. //2获取所有的方法对象
    2. Method[] methods = clazz.getDeclaredMethods();//获取所有的方法
    3. for (Method method:methods) {
    4. System.out.println(method.getName());
    5. }
    6. //3获取一个方法
    7. try {
    8. Method setName1 = clazz.getMethod("setName");//获取无参的方法
    9. Method setName2 = clazz.getMethod("setName",String.class);
    10. Method setAge = clazz.getMethod("setAge", int.class);
    11. } catch (NoSuchMethodException e) {
    12. e.printStackTrace();
    13. }
  • 方法对象的一般方法

    1. Class[] types = setName2.getParameterTypes();//获取所有参数的类型
    2. System.out.println("方法的名称:"+setName2.getName());
    3. for (Class t:types){
    4. System.out.println("参数类型:"+t.getName());
    5. }
    6. Class returnType = setName2.getReturnType();//获取返回对象的类型
    7. System.out.println("返回参数类型:"+returnType.getName());
  • 通过反射调用对象的私有方法 ```java public static Object callPrivateMethod(Object obj,String methodName,Class[] paramsType,Object[] values){

    1. //1,通过对象获取类的类对象
    2. Class clazz = obj.getClass();
    3. //2,获取方法对象
    4. try {
    5. Method method = clazz.getDeclaredMethod(methodName,paramsType);
    6. method.setAccessible(true);
    7. //3通过方法对象,调用对象的方法
    8. Object returnValue = method.invoke(obj,values);
    9. return returnValue;
    10. } catch (NoSuchMethodException e) {
    11. e.printStackTrace();
    12. } catch (InvocationTargetException e) {
    13. e.printStackTrace();
    14. } catch (IllegalAccessException e) {
    15. e.printStackTrace();
    16. }
    17. return null;

    } //方法的调用 public static void main(String[] args) {

    1. Student s1 = new Student();
    2. s1.setName("小黑");;
    3. callPrivateMethod(s1,"setName",
    4. new Class[]{String.class},//方法参数的类型
    5. new Object[]{"小黄"});//方法的实参
  1. Object value = callPrivateMethod(s1,"getName",null,null);
  2. System.out.println("结果是:"+value);
  3. }
  1. <a name="wlcXu"></a>
  2. ## 构造方法对象
  3. - 构造方法对象主要是用于创建对象的
  4. - 构造方法对象的获取方式
  5. ```java
  6. //2,获取构造方法对象
  7. Constructor[] constructors = clazz.getDeclaredConstructors();
  8. for (Constructor c : constructors){
  9. System.out.println(c.getName());
  10. }
  11. //获取指定的构造方法
  12. Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class);
  • 通过构造方法对象创建对象

    1. //3,通过构造方法对象创建对象
    2. Object obj = constructor.newInstance("小明",15);
    3. System.out.println(obj.toString());

    注解编程

    注解概述

  • 注解是JDK1.5之后出现的新特性,本质上是对反射的补充

  • 注解的作用

    • 编写文档:可以使用代码生成文档
    • 代码分析:在代码运行的时候可以从注解中获取相关信息
    • 编译检查:为ide提供代码正确性的判断(@OverRide)

      注解的使用

  • 定义一个注解,直接通过@interface进行定义

    1. public @interface MyAnnotation {
    2. }
  • 设置方法,是没有方法体的

    1. public @interface MyAnnotation {
    2. String name();
    3. int age();
    4. }
  • 可以在类(接口,注解),属性,方法,参数使用注解(重点)

    1. @MyAnnotation(name="xx",age=15)
    2. public class TestAnnotation002 {
    3. @MyAnnotation(age = 12)
    4. String dd;
    5. @MyAnnotation(age=13)
    6. public static void add(@MyAnnotation(age=15) String[] arg){
    7. }
    8. }
  • 通过反射获取注解上方法的值

    1. public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    2. //1,获取类对象
    3. Class clazz = UserEntity.class;
    4. //2,通过类对象获取类上的注解
    5. Annotation[] annotations = clazz.getDeclaredAnnotations();
    6. for (Annotation annotation:annotations) {
    7. // System.out.println(annotation.toString());
    8. }
    9. //获取指定的注解
    10. Annotation a = clazz.getDeclaredAnnotation(MyTable.class);
    11. System.out.println(a.toString());
    12. //1,获取对象的类的类对象
    13. Class myTableClazz = a.annotationType();
    14. //2,通过类的类对象获取对应的方法
    15. Method tableNameMethod = myTableClazz.getDeclaredMethod("tableName");
    16. //3,通过方法对象和对象进行调用获取返回结果
    17. String tableName = (String) tableNameMethod.invoke(a);
    18. System.out.println("表名:"+tableName);
    19. }

    元注解的使用

  • 元注解:就是用于定义注解的注解

  • 四个元注解

    • @Target:限制注解在那些位置定义 :::info     1.CONSTRUCTOR:用于描述构造器
          2.FIELD:用于描述域
          3.LOCAL_VARIABLE:用于描述局部变量
          4.METHOD:用于描述方法
          5.PACKAGE:用于描述包
          6.PARAMETER:用于描述参数
          7.TYPE:用于描述类、接口(包括注解类型) 或enum声明 :::

    • @Retention: 定义了注解在什么情况下生效 :::info    1.SOURCE:在源文件中有效(即源文件保留)
          2.CLASS:在class文件中有效(即class保留)
          3.RUNTIME:在运行时有效(即运行时保留)[一般的选项] :::

    • @Documented: 生成文档

    • @Inherited:在使用这个注解的类的子类,注解也效果

      枚举

      枚举的概述

  • 也是可以类,接口,注解同级别的定义

  • 主要可以用于一组常量 和 单例模式的创建

    • 传统的常量写法

      • 定义常量

        1. public interface ColorContants {
        2. int GREEN =1;
        3. int RED = 2;
        4. int YELLOW = 3;
        5. }
      • 在代码中通过switch进行判断

        1. //传统写法
        2. int color = ColorContants.RED;
        3. switch (color){
        4. case ColorContants.GREEN:
        5. break;
        6. case ColorContants.RED:
        7. break;
        8. case ColorContants.YELLOW:
        9. break;
        10. }
    • enum的写法

      • 创建enum

        1. public enum ColorEnum {
        2. GREEN, //默认的值是0
        3. RED, //默认是1
        4. YELLOW
        5. }
      • 通过switch进行判断

        1. //enum的写法
        2. ColorEnum colorEnum = ColorEnum.RED;
        3. switch (colorEnum){
        4. case GREEN:
        5. break;
        6. case RED:
        7. break;
        8. case YELLOW:
        9. break;
        10. }

        枚举的基本使用

  • 枚举中可以定义枚举类型成员,成员变量,构造方法,一般方法

  • 枚举类型成员,就是使用枚举直接创建的对象,
    • 一般都写在枚举的头部
    • 多个枚举之间使用,隔开
    • 最后一个枚举类型成员需要使用;进行分割
  • 枚举的构造方法,是在枚举对象被创建的时候调用

    • 默认调用的是无参的构造方法
    • 构造方法被重载之后,默认的无参构造方法就会失效
    • 构造方法不能是public,只能在枚举内部调用 ```java public enum ColorEnum { GREEN, //创建了一个枚举对象 RED(2,”红色”),//调用有参数的构造方法 YELLOW; String name; int index; //构造 ColorEnum(){

      } ColorEnum(int index,String name){ this.name = name; this.index = index; } //一般方法 public String getName(){ return this.name; }

}

  1. - 枚举的基本使用
  2. - 枚举不能被new出来,只能通过枚举类型来获取对象
  3. ColorEnum colorEnum = ColorEnum.GREEN;
  4. - 两种方法用法
  5. - 直接通过枚举类调用方法(调用的方法都是来自于Enum父类)
  6. ```java
  7. //获取所有的枚举
  8. ColorEnum[] colorEnums = ColorEnum.values();
  9. //根据名字获取指定的枚举对象
  10. ColorEnum redEnum = ColorEnum.valueOf("RED");
  1. - 通过枚举对象调用方法
  1. //调用自定义的方法
  2. redEnum.getName();
  3. //获取枚举对象的默认索引(父类提供了,从0开始)
  4. e.ordinal()
  5. //比较两个枚举的大小,相同0,小于-1,大于1
  6. redEnum.compareTo(greenEnum);

设计模式

概述

  • 设计就是前人提供一些经验,可以复用代码结构
  • 设计模式即可复用面向对象软件的基础
  • 设计模式的分类

    • 创建型模式,将对象的创建和使用进行分离
      • 工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
    • 结构型模式,用于描述如何将类或对象按某种布局组成更大的结构
      • 适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
    • 行为型模式,用于描述类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务
      • 策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

        UML统一建模语言

  • 学习设计模式,一般都是需要使用UML进行描述

    • 类图
      • 关联关系
        • 单向关联
        • clip_image002.jpg
        • 双向关联
        • image-20220517105056300.png
        • 自联
        • clip_image002-16527558653001.jpg
      • 聚合关系
        • 一个元素是有另一种元素多个聚集而成
        • clip_image002-16527558791772.jpg
      • 组合关系
        • 一个元素是由多个其他不同的元素组合而成
        • image-20220517105356331.png
      • 继承关系
        • 一个父类有多个子类
        • image-20220517105547325.png
    • 用例图
      • 用于描述不同的角色在项目中使用的模块
      • image-20220517105745640.pngimage-20220517105735708.png
    • 时序图
      • 用于描述一个业务整个流程在不同对象之间的运行
      • image-20220517110025551.png

        单例模式

        饿汉式

  • 在static变量的时候,直接创建对象

    1. /*饿汉式*/
    2. public class MyHungrySingleton {
    3. static MyHungrySingleton instance = new MyHungrySingleton();
    4. private MyHungrySingleton(){
    5. }
    6. public static MyHungrySingleton getInstance(){
    7. return instance;
    8. }
    9. }
  • 天生不会出现线程并发的问题

  • 如果过多的使用,浪费静态区的内存

    懒汉式

  • 为了解决饿汉式浪费静态内存的问题,所以出现了懒汉式

    1. public class MyLazySingleton {
    2. static MyLazySingleton instance;
    3. private MyLazySingleton(){
    4. }
    5. public static MyLazySingleton getInstance(){
    6. if(instance==null){
    7. instance = new MyLazySingleton();
    8. }
    9. return instance;
    10. }
    11. }
  • 但是一般的懒汉式会出现线程并发的问题,使用DCL + volatie解决

    1. public class MyLazySingleton {
    2. static volatile MyLazySingleton instance;
    3. private MyLazySingleton(){
    4. }
    5. public static MyLazySingleton getInstance(){
    6. if(instance==null){
    7. synchronized(MyLazySingleton.class){
    8. if(instance ==null){
    9. instance = new MyLazySingleton();
    10. }
    11. }
    12. }
    13. return instance;
    14. }
    15. }

    枚举式

  • 直接利用枚举的私有构造方法的特征实现

    1. public enum EnumSingleton {
    2. INSTANCE;
    3. public static EnumSingleton getInstance(){
    4. return INSTANCE;
    5. }
    6. }
  • 本质上就是一种饿汉式的使用

    容器式

  • 之前所有的单例模式都是针对某一个类进行实现,当出现多个类需要使用单例模式的时候,就会很麻烦而且不灵活

  • 所谓的容器式,就是创建一个容器,由其进行对象的创建和维护,使用者直接通过类的名称获取单例的类对象即可

    1. public class MySingleContainer {
    2. //定义一个容器
    3. Map<String,Object> container = new ConcurrentHashMap<>();
    4. public Object getInstance(Class clazz){
    5. //使用类的名称作为key值
    6. String key = clazz.getName();
    7. Object obj = container.get(clazz.getName());
    8. if(obj == null){
    9. synchronized (MySingleContainer.class){
    10. if(obj ==null){
    11. //创建对象
    12. try {
    13. obj = clazz.newInstance();
    14. //将对象放入到容器中
    15. container.put(key,obj);
    16. } catch (InstantiationException e) {
    17. e.printStackTrace();
    18. } catch (IllegalAccessException e) {
    19. e.printStackTrace();
    20. }
    21. }
    22. }
    23. }
    24. return obj;
    25. }
    26. }

    Threadlocal的方式实现

    • 不能保证整个程序唯一;
    • 可以保证线程唯一;
      1. public class ThreadLocalSingleton {
      2. private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstanceThreadLocal = new ThreadLocal<ThreadLocalSingleton>() {
      3. @Override
      4. protected ThreadLocalSingleton initialValue() {
      5. return new ThreadLocalSingleton();
      6. }
      7. };
      8. //构造方法私有化
      9. private ThreadLocalSingleton() {}
      10. //获取线程
      11. public static ThreadLocalSingleton getInstance() {
      12. return threadLocalInstanceThreadLocal.get();
      13. }
      14. }