Java基础知识

142 阅读4分钟

Java 枚举

什么是枚举

概念

enumeration,JDK1.5引入的新特性,在 Java 中被 enum 关键字修饰的类型就是枚举类型。如果枚举不添加任何方法,枚举值默认为从0开始的有序数值。

枚举的作用

统一管理常量

应用场景

错误码、状态机等等

枚举的特性

除了不能继承,基本上可以将其看作一个常规类

Java 注解

什么是注解

注解的作用:

  • 不是程序本身,对程序作出解释
  • 可以被其他程序读取

注解的格式:

  • 注解是以"@注释名"在代码中存在的,还可以添加一些参数值。

使用注解的场景

  • 附加在 package,class,method,field 上面,相当于给它们添加了额外的辅助信息,可以通过反射机制实现堆这些元数据的访问

内置注解

@Override:定义在 java.lang.Object 中,此注释只适用于方法,表示一个方法声明打算重写超类中的另一个方法声明。
@Deprecated:定义在 java.lang.Deprecated 中,可以用于修饰方法,属性,类表示不鼓励使用这些元素,通常是因为它们很危险或者有更好的选择。
@SuppressWarnings:定义在 java.lang.SuppressWarnings 中,用于抑制编译时的警告信息。
@SafeVarargs:忽略任何使用参数为泛型变量的方法或者构造函数调用产生的警告
@FunctionalInterface:标识一个匿名函数或者函数式接口
@Repeatable:标识某注解可以在同一个声明上使用多次

注解的本质

就是一个 Annotation 接口的子接口,解释了为何成员变量有括号。

注解的属性类型

注解属性类型可以有以下列出的类型
1.基本数据类型
2.String
3.枚举类型
4.注解类型
5.Class类型
6.以上类型的一维数组类型

注解成员变量赋值

(name = "", name1 = "")

获取注解属性

  • 通过反射的方式获取注解的助兴

元注解

  • 元注解的作用就是负责注解其他注解,Java 定义了4个标准的 meta-annotation 类型,它们被用来提供对其他 annotation 类型做说明。
  • 这些类型和它们所支持的类在 java.lang.annotation 包中可以找到
    • Target:用于描述注解的使用范围
      • ElementType 作用域
    • Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(SOURCE写入源代码 < CLASS编入字节码文件 < RUNTIME运行时保留,通过反射得到)
      • RententionPolicy
    • Document:说明该注解被包含在 javadoc ,用户文档中
    • Inherited:被该注解修饰的注解修饰了一个父类,如果它的子类没有被其他注解修饰,则它的子类也继承父类的注解

反射机制

反射的作用

从一个对象,获取到其类的所有信息

反射的优点与缺点

  • 优点
    • 实现动态创建对象和编译
  • 缺点
    • 影响执行性能

反射的主要 API

java.lang.Class
java.lang.reflect.Method
java.lang.reflect.Field
java.lang.reflect.Constructor

Class 类

Object 类中定义了以下的方法,此方法将被所有子类继承
public final Class getClass();
该方法可以通过对象获取到类的名称。

在 JRE 中都保留一个不变的 Class 类型的对象,无论有多少个对象,这个 Class 类型的对象始终只有一个。

  • Class 对象只能由系统建立
  • 一个加载的类在 JVM 中只会有一个 Class 实例
  • 一个 Class 对象对应一个.class 文件
  • 每个类实例会保留自己由那个 Class 实例生成的信息
  • 通过 Class 可以完成的得到一个类中所有被加载的结构
  • Class 类是 Relection 的根源,想要反射就必须先获得 Class 对象

常用方法

获取 Class 类的实例

  • Class a = Cat.class; 已知具体的类,通过 class 属性获取,该方法最为安全可靠,程序性能最高
  • Class a = cat.getClass(); 已知某个类的实例,调用实例的 getClass()方法获取 Class 对象
  • Class a = Class.forName(); 已知一个类的类全名,且该类在类路径下,可以通过 Class 类的静态方法 forName()获取。
  • 基础数据类型可以直接使用 类名.Type 的方式获得 Class 对象

哪些类型可以有 Class 对象

通过反射获取运行时类的完整结构

获取 field、method、constructor、superclass、interface、annotation

  1. 首先获取 Class 对象
  2. 通过 class 对象调用对应的属性,以及通过方法名获取方法并调用方法
    • 演示代码
    Cat cat = new Cat();
    Class<? extends Cat> aClass2 = cat.getClass();
    Class<Cat> aClass1 = Cat.class;

    Class aClass = Class.forName("g.Cat");
    Field[] fields1 = aClass.getFields(); //获取公共属性,以及父类公共属性
    for(Field f: fields1) {
        System.out.println(f);
    }

    Field[] fields2 = aClass.getDeclaredFields(); //获取本来中所有的属性
    for(Field f: fields2) {
        System.out.println(f);
    }
    aClass.getMethod("setName",String.class).invoke(cat, "花花");
    System.out.println(cat.getName());

其他获取方式与属性类似 ......

setAccessible

  • Method 和 Field、Constructor 对象都有 setAccessible()方法。
  • 作用是启动和禁用安全检查开关
  • true 是关闭安全检查

反射操作泛型

  • Java 采用泛型擦除的机制来引入泛型,Java 中的泛型仅仅是给编译器使用,确保数据的安全性和免去强制类型转换的问题,一旦编译完成,所有与泛型有关的类型全部擦除。
  • 为了通过反射操作这些类型,Java 新增了 ParameterizedType、GenericArrayType、TypeVariable 和 WildcardType 几种类型来代表不能被归一到 Class 类中的类型,但是又和原始类型齐名的类型
  • ParameterizedType:标识一种参数化类型如 Map<String,Integer>(参数化类型)
  • GenericArrayType:标识一种元素类型是参数化类型或者类型变量的数组类型(泛型数组类型)
  • TypeVariable:是各种类型变量的公共父接口
  • WildcardType:代表一种通配符类型表达式

操作步骤

  1. 获取参数列表
  2. 判断参数列表是否为参数化类型
  3. 将泛型类型强制转化为参数化类型并获取真实类型 演示
public void test1(Map<String, Integer> m, List<Cat> l) {
    System.out.println("test1");
}
public List<Cat> test2() {
    System.out.println("test2");
    return null;
}

public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException {
    Class<Test2> aClass = Test2.class;
    Method test1 = aClass.getMethod("test1", Map.class, List.class);
    Type[] genericParameterTypes = test1.getGenericParameterTypes();
    for (Type genericParameterType : genericParameterTypes) {
        System.out.println(genericParameterType);
        if (genericParameterType instanceof ParameterizedType) {
            Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }

        }
    }
    Method test2 = aClass.getMethod("test2");
    Type genericReturnType = test2.getGenericReturnType();
    System.out.println(genericReturnType);
    if(genericReturnType instanceof ParameterizedType) {
        Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
        for (Type actualTypeArgument : actualTypeArguments) {
            System.out.println(actualTypeArgument);
        }

    }
}

反射操作注解

演示

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GField {
    String value();
    String id();
    String length();
}
public class Cat {
    @GField(id = "1",value = "小小", length = "2")
    private String name;
    @GField(id = "2",value = "12", length = "4")
    public String age;
    @GField(id = "3",value = "小明", length = "6")
    public String Master;
}
public static void main(String[] args) throws NoSuchFieldException {
    Class<Cat> catClass = Cat.class;
    for (Field declaredField : catClass.getDeclaredFields()) {
        System.out.println(declaredField.getAnnotation(GField.class).value());
        System.out.println(declaredField.getAnnotation(GField.class).id());
        System.out.println(declaredField.getAnnotation(GField.class).length());
    }


}