注解和反射

一、内置注解

@Override:重写
@Deprecated:表示注解的方法或类不推荐使用
@SuppressWarnings:正压警告

二、使用元注解自定义注解

// 表示我们的注解可以用在哪些地方
@Target({ElementType.METHOD, ElementType.TYPE})
// 表示我们的注解在什么时候还有效
@Retention(RetentionPolicy.RUNTIME)
// 表示是否将我们的注解生成在JavaDoc中
@Documented
// 表示子类可以继承父类的注解
@Inherited
public @interface myAnnotation {
    // 不加默认值的话,使用注解时必须传参!
    int id();
    // 如果只有一个参数,一般推荐使用value做参数名,且使用的时候直接传值就行,不用 value="..."
    // 如果是其他名称就必须使用  属性名="属性值"  传值
    String value() default "";
    String[] typeof() default {"类型一","类型二"};
}

三、反射

3.1 获取Class对象的方法

package demo;

public class Test2 extends Object {
    public static void main(String[] args) throws ClassNotFoundException {
        /**
         * 直接获得Class对象
         */
        // 方式一:若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
        Class c1 = User.class;
        // 方式二:若已知某个类的实例,调用该实例的getClass()方法获取Class对象,
        User user = new User();
        Class c2 = user.getClass();
        // 方式三:通过Class类的静态方法forName()获取
        Class c3 = Class.forName("demo.User");
        // 方式四:通过ClassLoader类加载器获得Class对象
        ClassLoader loader = ClassLoader.getSystemClassLoader();// 获得类加载器对象
        Class c4 = loader.loadClass("demo.User");
        System.out.println(c1.hashCode() + "," + c2.hashCode() + "," + c3.hashCode() + "," + c4.hashCode()); // 356573597,356573597,356573597,356573597
        /**
         * 间接获得类对象
         */
        // 获得父类Class对象
        Class c5 = c1.getSuperclass();
        System.out.println(c5); // class demo.Person

        /**
         * 特殊情况获得类对象
         */
        // 基本内置数据类型的包装类都有一个Type属性,可以直接用类名.Type
        Class<Integer> type = Integer.TYPE;
        System.out.println(type); // int
    }
}

class Person {
    public String type;
}

class User extends Person{
    private String name;
    private int age;
    private String habit;
    // 此处省略构造器、get、set、toString方法
}

3.2 获取Class对象的属性和方法

public class Test3 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        // 获得User的Class对象
        Class<?> c1 = Class.forName("demo.User");
        /**
         * 【获得类的名字】
         * getName()是获得 包名+类名
         * getSimpleName()只会获得类名
          */
        System.out.println(c1.getName());// demo.User
        System.out.println(c1.getSimpleName());// User
        System.out.println("========================================");
        /**
         * 【获得类的属性】
         * getField() 指定属性名(只能获得public的属性,而且还能得到父类的属性)
         * getDeclaredField() 能获得自己所有的属性
         * getFields() 获得属性值的数组,但是使用范围同getFile一样,只能获得public属性,而且也能得到父类的public属性
         * getDeclaredFields() 获得自己所有的属性值(包含private修饰的属性),返回一个数组
         */
		System.out.println(c1.getField("name"));// 会报错,因为只能获得public修饰的属性
        System.out.println(c1.getDeclaredField("name"));// private java.lang.String demo.User.name
        Field[] f1 = c1.getFields();
        Field[] f2 = c1.getDeclaredFields();
        System.out.println("========================================");
        /**
         * 【获得类的方法】
         * getMethods() 获得本类及其父类所有的仅限public修饰的方法
         * getDeclaredMethods() 获得类自己所有的方法,甚至包括private,不能得到父类的方法
         */
        Method[] m1 = c1.getMethods();
        Method[] m2 = c1.getDeclaredMethods();
        /**
         * 【还有构造器之类的方法此处不做展示】
         */
    }
}

3.3 使用反射示例

方法(Method)、属性(Field)、构造器(Constructor)对象都有setAccessible()方法,其作用是设置安全检查开关,默认为false,当参数值为true时,有两个好处:①提高访问权限,使得原来无法访问的私有成员也可以访问;②提高反射的效率;

获得User实例化对象

Class c1 = Class.forName("demo.User");
// 调用无参构造器得到User对象
User u1 = (User) c1.newInstance();
// 调用有参构造器得到User对象
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, String.class);
User u2 = (User) constructor.newInstance("Carle", 20, "code");

获得User对象的内部方法

Class c1 = Class.forName("demo.User");
User u = (User) c1.newInstance();
// 通过反射获取方法
Method method = c1.getDeclaredMethod("setName", String.class);
// 激活方法,传入User对象和方法对应的参数
method.invoke(u, "Carle");
System.out.println(u.getName()); // Carle

获得User对象的内部属性

Class c1 = Class.forName("demo.User");
User u = (User) c1.newInstance();
// 通过反射获取属性
Field field = c1.getDeclaredField("name");
// 开启暴力反射,设置可访问性,否则无法操作private修饰的属性
field.setAccessible(true);
// 设置属性值
field.set(u, "Carle");
System.out.println(u.getName()); // Carle

通过反射操作注解

public class Test04 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c = Class.forName("demo.User");
        // 通过反射获得类的注解and参数值
        TableAnno anno = (TableAnno) c.getAnnotation(TableAnno.class);
        System.out.println(anno); // @demo.TableAnno(value=db_Table)
        System.out.println(anno.value()); // db_Table
        // 通过反射获得类属性的注解and参数值
        Field f = c.getDeclaredField("id");
        FieldAnno anno2 = f.getAnnotation(FieldAnno.class);
        System.out.println(anno2); // @demo.FieldAnno(columnName=db_id, type=int, len=16)
        System.out.println(anno2.columnName()
                + "," + anno2.type()
                + "," + anno2.len()); // db_id,int,16
    }
}

/**
 * 自定义User类,使用自定义的一些注解
 */
@TableAnno("db_Table")
class User {
    @FieldAnno(columnName = "db_id",type = "int",len = 16)
    private int id;
    @FieldAnno(columnName = "db_name",type = "String",len = 10)
    private String name;
}

/**
 * 自定义作用在类上的注解TableAnno
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableAnno {
    String value();
}

/**
 * 自定义作用在属性上的注解FieldAnno
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldAnno {
    String columnName();
    String type();
    int len();
}
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页