JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

JAVA ---- 枚举/注解/反射 java 枚举原理

wys521 2024-11-09 15:02:30 精选教程 30 ℃ 0 评论

枚举

枚举本质也是一种类,只不过是这个类的对象是有限的、固定的几个,不能让用户随意创建。

如果枚举类的实例只有一个,则可以看做是单例的实现方式。

JDK5.0之前

私有化类的构造器,保证不能在类的外部创建其对象;

在类的内部创建枚举类的实例。声明为:public static final, 对外暴露这些常量对象;

对象如果有实例变量,应该声明为private final(建议,不是必须),并在构造器中初始化。

package com.demo.enumdemo;

public class SeasonTest {
    public static void main(String[] args) {
        System.out.println(Season.SPRING);
        System.out.println(Season.SPRING.getSeasonName());
        System.out.println(Season.SPRING.getSeasonDesc());
    }
}

class Season {
    // 声明当前类的对象的实例变量 使用private final修饰
    private final String seasonName;
    private final String seasonDesc; // 季节的描述


    // 1. 私有化类的构造器
    private Season(String seasionName, String seasonDesc) {
        this.seasonName = seasionName;
        this.seasonDesc = seasonDesc;
    }

    // 2. 提供实例变量的get方法

    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }

    // 3. 创建当前类的实例 使用public static final修饰
    public static final Season SPRING = new Season("春天", "春暖花开");
    public static final Season SUMMER = new Season("夏天", "夏日炎炎");
    public static final Season AUTUMN = new Season("秋天", "秋高气爽");
    public static final Season WINTER = new Season("冬天", "冰冷刺骨");

    @Override
    public String toString() {
        return "Season{" +
                "seasonName='" + seasonName + '\'' +
                ", seasonDesc='" + seasonDesc + '\'' +
                '}';
    }
}

JDK5.0之后

使用enum关键字定义的枚举类,默认其父类是java.lang.Enum类;

使用enum关键字定义的枚举类,不要显示的定义其父类,否则报错。

package com.demo.enumdemo;

public  class SeasonTest {
    public static void main(String[] args) {
        System.out.println(Season.SPRING.getClass()); // class com.demo.enumdemo.Season
        System.out.println(Season.SPRING.getClass().getSuperclass()); // class java.lang.Enum
    }
}

enum Season {
    // 1. 必须在枚举类的开头声明多个对象。对象之间使用,隔开
    SPRING("春天", "春暖花开"),
    SUMMER("夏天", "夏日炎炎"),
    AUTUMN("秋天", "秋高气爽"),
    WINTER("冬天", "冰冷刺骨");

    // 2. 声明当前类的对象的实例变量 使用private final修饰
    private final String seasonName;
    private final String seasonDesc; // 季节的描述


    // 3. 私有化类的构造器
    private Season(String seasionName, String seasonDesc) {
        this.seasonName = seasionName;
        this.seasonDesc = seasonDesc;
    }

    // 4. 提供实例变量的get方法
    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }
}

Enum类中常用的方法

  • String toString():默认返回的是常量名(对象名), 可以继续手动重写该方法
  • static 枚举类型[] values():返回枚举类型的对象数组。该方法可以方便地遍历所有的枚举值,是一个静态方法。
  • static 枚举类型 valueOf(String name):可以把一个字符串转为对应的枚举类对象。要求字符串必须是枚举对象。
  • String name():得到当前枚举常量的名称。
  • int ordinal():返回当前枚举常量的次序号,默认从0开始。
public  class SeasonTest {
    public static void main(String[] args) {
        // toString()
        System.out.println(Season.SPRING);

        // name()
        System.out.println(Season.SPRING.name());

        // values()
        for (Season value : Season.values()) {
            System.out.println("value = " + value);
        }

        // 字符串转枚举类型
        // valueOf() 返回当前枚举类中名称为objName的枚举类对象。如果枚举类中不存在objName名称的对象,报错。
        String objName = "WINTER";
        Season season = Season.valueOf(objName);
        System.out.println("season = " + season);

        // ordinal()
        System.out.println(Season.AUTUMN.ordinal());
    }
}

枚举类实现接口的操作

  • 情况1:枚举类实现接口,在枚举类中重写接口中的抽象方法。当通过不同的枚举类对象调用此方法时,执行的是同一个方法。
  • 情况2:让枚举类的每一个对象重写接口中的抽象方法。当通过不同的枚举类对象调用此方法时,执行的是不同的实现方法。
package com.demo.enumdemo;

public  class SeasonTest {
    public static void main(String[] args) {
        for (Season value : Season.values()) {
            value.show();
        }

    }
}

interface Info {
    void show();
}
enum Season implements Info {
    // 1. 必须在枚举类的开头声明多个对象。对象之间使用,隔开
    SPRING("春天", "春暖花开") {
        public void show() {
            System.out.println("SPRING");
        }
    },
    SUMMER("夏天", "夏日炎炎") {
        public void show() {
            System.out.println("SUMMER");
        }
    },
    AUTUMN("秋天", "秋高气爽") {
        public void show() {
            System.out.println("AUTUMN");
        }
    },
    WINTER("冬天", "冰冷刺骨") {
        public void show() {
            System.out.println("WINTER");
        }
    };

    // 2. 声明当前类的对象的实例变量 使用private final修饰
    private final String seasonName;
    private final String seasonDesc; // 季节的描述


    // 3. 私有化类的构造器
    private Season(String seasionName, String seasonDesc) {
        this.seasonName = seasionName;
        this.seasonDesc = seasonDesc;
    }

    // 4. 提供实例变量的get方法
    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }
}

Annotation ---- 注解

可用于修饰包、类、构造器、方法、成员变量、参数、局部变量的声明。

注解可以在类编译、运行时进行加载,体现不同的功能。

注解是一种趋势,框架 = 注解 + 反射 + 设计模式

元注解

对现有的注解进行解释说明的注解。

元数据

String name = "Tom";

String 和 name 修饰 "Tom"的两个结构,因此可以把String 和 name 看成 "Tom"的元数据。

反射

反射被视为"动态语言"的关键,在运行期间借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

通过反射,可以调用类中私有的结构。

Class

java.exe命令对指定的.class文件进行解释运行,.class字节码文件加载到内存中(存放在方法区),加载到内存中的.class文件对应的结构即为Class的一个实例。

运行时类在内存中会缓存起来,在整个执行期间,只会加载一次。

获取Class实例的方式

package com.demo;

import org.junit.Test;

public class ClassTest {

    @Test
    public void test1() throws ClassNotFoundException {
        // 第一种方式:调用运行时类的静态属性:class
        Class<Person> clazz1 = Person.class;

        // 第二种方式:调用运行时类的对象的getClass()
        Person person = new Person();
        Class<? extends Person> clazz2 = person.getClass();

        // 第三种方式:调用Class的静态方法forName(String className)** 能够更好的体现动态性
        String className = "com.demo.Person"; // 类的全限定名
        Class<?> clazz3 = Class.forName(className);

        // 第四种方式:使用类加载器的方式
        Class<?> clazz4 = ClassLoader.getSystemClassLoader().loadClass("com.demo.Person");
    }
}

所有Java类型都有Class对象

    // Properties: 处理属性文件
    @Test
    public void test3() throws Exception {
        Properties pros = new Properties();
        // 读取的文件默认路径为: 当前module下
//        FileInputStream is = new FileInputStream(new File("info.properties"));

        // 通过类的加载器读取的问及那的默认路径为:当前module下的src
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("info.properties");

        pros.load(is);

        String name = pros.getProperty("name");
        String pwd = pros.getProperty("password");

        System.out.println(name + ": " + pwd);
    }

创建对象

  • newInstance():要求高

要求提供的空参构造器的权限要足够;

空参的构造器:

1)子类对象在实例化时,子类的构造器的首行默认调用父类空参的构造器;

2)在反射中,经常用来创建运行时类的对象,要求各个运行时类提供一个空参的构造器,便于编写创建运行时类对象的代码;

@Test
public void test3() throws Exception {
    Class clazz = Person.class;

    // 创建Person的实例
    Person person = (Person) clazz.newInstance(); // 调用Person的空参构造器
}
  • JDK9通过Constructor类调用newInstance(..)

获取运行类的完整结构

Class clazz = Class.forName("com.demo.Person");

// 获取运行时父类
Class superclass = clazz.getSuperclass();

// 获取运行时带泛型的父类
Type genericSuperclass = clazz.getGenericSuperclass();

// 获取运行时类实现的接口 类可以实现多个接口
Class[] interfaces = clazz.getInterfaces();

// 获取运行时类所在的包
Package aPackage = clazz.getPackage();

// 强转带参数的泛型
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
// 泛型参数的数组
Type[] arguments = parameterizedType.getActualTypeArguments();

// 获取指定参数名称
System.out.println(((Class)arguments[0]).getName());

调用指定属性

Class clazz = Class.forName("com.demo.Person");
Person person = (Person) clazz.newInstance();

// 获取运行时类指定名的属性
Field nameField = clazz.getDeclaredField("name");

// 确保属性可以访问
nameField.setAccessible(true);

// 设置属性的值
nameField.set(person, 2);

// 获取属性的值
nameField.get(person);

调用指定方法

// 获取运行时方法
Method showNationMethod = clazz.getDeclaredMethod("showNation", String.class, int.class);

// 确保方法可访问
showNationMethod.setAccessible(true);

// 通过Method实例调用invoke(Object obj, Object ... objs),即对方法的调用
showNationMethod.invoke(person, "CHN", 10);

调用静态方法

// 获取运行时方法
Method showInfoMethod = clazz.getDeclaredMethod("showInfo");

// 确保方法可访问
showInfoMethod.setAccessible(true);

// 通过Method实例调用invoke(Object obj, Object ... objs),即对方法的调用
showInfoMethod.invoke(null);

调用构造器

Class clazz = Person.class;

// 通过Class的实例调用getDeclaredConstructor(Class ...args)
Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class);

// 确保此构造器时可以访问的
constructor.setAccessible(true);

// 通过Constructor实例调用newInstance(Object ...args),返回一个运行时类的实例
Person tom = (Person) constructor.newInstance("Tom", 12);

调用注解

Class clazz = Customer.class;

// 获取类声明上的注解
Table annotation = (Table) clazz.getDeclaredAnnotation(Table.class);

Field nameField = clazz.getDeclaredField("name");
// 获取属性声明的注解
Column nameColumn = nameField.getDeclaredAnnotation(Column.class);
System.out.println(nameColumn.columnName());
System.out.println(nameColumn.columnType());

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表