JavaSE进阶十一 反射机制二

1,可变长度参数

  • 语法:类型... (注意:一定是3个点)

  • 可变长度参数要求参数个数是:0-N个。

  • 可变长度参数在参数列表中必须在最后一个位置上,而且可变长度参数只能有1个。

  • 可变长度参数可以当做一个数组来看

代码示例
public class ArgsTest {
    public static void main(String[] args) {
        m(100,"abc");
        m(200,"abc","def","xyz");
        // 传数组
        String[] strings = {"我","是","中","国","人"};
        m(300,strings);
    }
    public static void m(int a, String... args){
        System.out.println(a);

        // args有length属性,说明args是一个数组
        // 可以将可变长度参数当做一个数组来看。
        for (int i = 0;i < args.length;i++){
            System.out.println(args[i]);
        }
    }
}

2,反射方法Method(了解内容)

2.1,通过反射机制获取一个对象的方法

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class ReflectTest08 {
    public static void main(String[] args) throws Exception {
        Class us = Class.forName("com.javaSE.reflects.UserService");

        // 获取所有的Method(包括私有的)
        Method[] methods = us.getDeclaredMethods();

        // 遍历Method
        for (Method method : methods){
            // 获取修饰符列表
            System.out.println("修饰符列表:" + Modifier.toString(method.getModifiers()));
            // 获取方法返回值类型
            System.out.println("返回值类型:" + method.getReturnType().getName());
            // 获取方法名
            System.out.println("方法名:" + method.getName());
            // 获取方法的参数列表
            Class[] parameterTypes = method.getParameterTypes();
            for (Class pt : parameterTypes){
                // 获取参数类型名字
                System.out.println("参数类型名字:" + pt.getSimpleName());
            }
        }
        System.out.println("-------------通过反射机制,反编译一个类的方法---------------------------------------------");
        // 通过反射机制,反编译一个类的方法Method
        fbyMethod();
    }

    private static void fbyMethod() throws ClassNotFoundException {
        Class us = Class.forName("com.javaSE.reflects.UserService");
        // 创建可变字符串对象
        StringBuilder sr = new StringBuilder();
        sr.append(Modifier.toString(us.getModifiers()) + " class " + us.getSimpleName() + "{\n");
        // 获取所有的Method(包括私有的)
        Method[] methods = us.getDeclaredMethods();
        for (Method method : methods){
            sr.append("\t");
            sr.append(Modifier.toString(method.getModifiers()));
            sr.append(" ");
            sr.append(method.getReturnType().getSimpleName());
            sr.append(" ");
            sr.append(method.getName());
            sr.append("(");
            for (Class c : method.getParameterTypes()) {
                sr.append(c.getSimpleName());
                sr.append(",");
            }
            // 删除指定下标位置的字符
            sr.deleteCharAt(sr.length() - 1);

            sr.append("){\n");
            sr.append("\t}");
            sr.append("\n");
        }
        sr.append("}");
        System.out.println(sr);

    }


}

class UserService{
    /**
     * 登录方法
     * @param name 用户名
     * @param password 密码
     * @return true登录成功,false登录失败。
     */
    public boolean login(String name ,String password){
        if ("admin".equals(name) && "123".equals(password)){
            return true;
        }
        return false;
    }

    /**
     * 退出登录
     */
    public  void loginOut(){
        System.out.println("已成功退出登录!");
    }
}

2.2,通过反射机制调用一个对象的方法

import java.lang.reflect.Method;

public class ReflectTest09 {
    public static void main(String[] args) throws Exception {
        Class us = Class.forName("com.javaSE.reflects.UserService");
        // 创建对象
        Object obj = us.newInstance();

        // 获取UserService对象的方法Method
        Method loginM = obj.getClass().getDeclaredMethod("login",String.class,String.class);
        // 调用方法
        Object invKV = loginM.invoke(obj,"admin","123");
        System.out.println(invKV);

    }
}

反射构造方法

  • 通过反射机制,获取一个类的父类
  • 通过反射机制,获取一个类实现的所有接口
  • 通过反射机制,调用一个类的构造方法
  • 通过反射机制,反编译一个类的构造方法
代码示例
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

public class ReflectTest10 {
    public static void main(String[] args) throws Exception{
        // 创建VipUser对象
        Class cc = Class.forName("com.javaSE.reflects.VipUser");


        System.out.println("-------------通过反射机制,获取一个类的父类---------------------------------------------");
        Class superClass = cc.getSuperclass();
        // 获取父类名字
        System.out.println(superClass.getName());
        System.out.println(superClass.getSimpleName());

        System.out.println("-------------通过反射机制,获取一个类实现的所有接口---------------------------------------------");

        Class strClass = Class.forName("java.lang.String");
        // 获取一个类实现的所有接口
        Class[] interfaces = strClass.getInterfaces();
        for (Class i : interfaces){
            System.out.println(i.getName());
        }

        System.out.println("-------------通过反射机制,调用一个类的构造方法---------------------------------------------");
        // 调用无参构造方法
        Object obj0 = cc.newInstance();
        System.out.println(obj0);

        // 获取无参构造方法
        Constructor c0  = cc.getDeclaredConstructor();
        Object obj00  = c0.newInstance();
        System.out.println(obj00);

        // 获取带有参数的构造方法
        Constructor c1 = cc.getDeclaredConstructor(int.class);
        Constructor c2 = cc.getDeclaredConstructor(int.class,String.class);
        Constructor c3 = cc.getDeclaredConstructor(int.class,String.class,String.class);
        Constructor c4 = cc.getDeclaredConstructor(int.class,String.class,String.class,boolean.class);
        // 调用构造方法new对象
        Object obj1 = c1.newInstance(112);
        Object obj2 = c2.newInstance(112,"admin");
        Object obj3 = c3.newInstance(112,"admin","2020-02-20");
        Object obj4 = c4.newInstance(112,"admin","2020-02-20",true);
        // 打印输出
        System.out.println(obj1);
        System.out.println(obj2);
        System.out.println(obj3);
        System.out.println(obj4);

        System.out.println("-------------通过反射机制,反编译一个类的构造方法---------------------------------------------");
        // 创建可变字符串对象
        StringBuilder sr = new StringBuilder();
        sr.append(Modifier.toString(cc.getModifiers()) + " class " + cc.getSimpleName() + "{\n");

        // 拼接构造方法
        Constructor[] cs = cc.getDeclaredConstructors();
        for (Constructor c : cs){
            sr.append("\t");
            sr.append(Modifier.toString(c.getModifiers()));
            sr.append(" ");
            sr.append(cc.getSimpleName());
            sr.append("(");
            // 拼接参数
            for (Class cp : c.getParameterTypes()){
                sr.append(cp.getSimpleName());
                sr.append(",");
            }
            if (c.getParameterTypes().length > 0){
                sr.deleteCharAt(sr.length() - 1);
            }
            sr.append("){}\n");

        }
        sr.append("}");
        System.out.println(sr);
    }
}
class VipUser{
    int no;
    String name;
    String birth;
    boolean sex;

    public VipUser() {
    }

    public VipUser(int no) {
        this.no = no;
    }

    public VipUser(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public VipUser(int no, String name, String birth) {
        this.no = no;
        this.name = name;
        this.birth = birth;
    }

    public VipUser(int no, String name, String birth, boolean sex) {
        this.no = no;
        this.name = name;
        this.birth = birth;
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "VipUser{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", birth='" + birth + '\'' +
                ", sex=" + sex +
                '}';
    }
}

3,注解

  • 1,注解:或者叫做注释,英文单词:Annotation

  • 2,注释Annotation是一种引用数据类型;编译之后也是生成.class文件

  • 3,怎么自定义注解,语法格式

    • [修饰符列表] @interface 注解类型名{}
  • 4,注解怎么使用,用在什么地方

    • 1,注解使用是的语法结构:
      @注解类型名
    • 2,注解可以用在类上、属性上、方法上、变量上...等;注解还可以出现在注解类型上。
    • 3,注解中的属性是value,并且只有一个属性,该属性名可以省略不写。
    • 4,注解中属性是数组,数组中只有一个元素,大括号可以省略不写。
  • 5,注解当中的属性类型:

    • byte,short,int,long,float,double,boolean,char,String,class,枚举类型以及以上每一种的数组形式。
  • 6,关于jdk lang包下的Override注解

    • 这个注解只能注释方法,是给编译器参考的,和运行阶段没关系;
    • 凡是java中带有这个注解的方法,编译器都会进行编译检查,如果这个方法不是重写父类的方法,编译器报错。
  • 7,元注解:用来标注"注解类型"的"注解",称为元注解。

  • 8,常见的元注解类型

    • Target:用来标注"被标注的注解"可以出现在哪些位置上。

      • @Target(ElementType.METHOD) 表示"被标注的注解"只能出现在方法上。
    • Retention:用来标注"被标注的注解"最终保存在哪里。

      • @Retention(RetentionPolicy.SOURCE) 表示该注解只能被保留在java源文件中。
      • @Retention(RetentionPolicy.CLASS) 表示该注解被保留在class文件中。
      • @Retention(RetentionPolicy.RUNTIME) 表示该注解被保留在class文件中,并且可以被反射机制所读取。
    • Deprecated注解:表示标注的内容已过时。

      • 这个注解主要是向其他程序员传递一个信息,告知已过时,有更好的解决方案存在。
代码示例
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;


public class AnnotationTest01 {
/*
    报错了:如果一个注释当中有属性,那么必须给属性赋值(除非该属性使用了default指定了默认值)
    @MyAnnotation
    public void doSome(){

    }
 */
    // @MyAnnotation(属性名=属性值)
    // 需给属性赋值
    @MyAnnotation(name = "a",color = "red")
    public void doSome(){

    }

    // 注解中的属性是value,并且只有一个属性,该属性名可以省略不写
    // @AnnotationValue(value = "a")
    @AnnotationValue("a")
    public void doOther(){

    }

    public static void main(String[] args) throws Exception {

        // 获取被注解的类
        Class c = Class.forName("com.javaSE.annotation.MyAnnotationTest");

        //========通过反射机制,反射类注解==========================================================================
        // 判断类上面是否有@MyAnnotation2注解
        System.out.println(c.isAnnotationPresent(AnnotationValue.class));// true
        if (c.isAnnotationPresent(AnnotationValue.class)){
            AnnotationValue av = (AnnotationValue)c.getAnnotation(AnnotationValue.class);
            System.out.println("类上面的注解对象:" + av);
            // 获取注解对象的属性
            String value = av.value();
            System.out.println(value);
        }

        //========通过反射机制,反射方法注解==========================================================================
        Method method = c.getDeclaredMethod("doSome");
        // 判断该方法上是否存在注解
        if (method.isAnnotationPresent(MyAnnotation2.class)){
            MyAnnotation2 ma2 = (MyAnnotation2)method.getAnnotation(MyAnnotation2.class);
            System.out.println("name:" + ma2.name() + ";password:" + ma2.password());
        }
    }
}

@AnnotationValue("测试反射类注解")
class MyAnnotationTest{
    @MyAnnotation2(name = "admin",password = "123")
    public void doSome(){

    }
}

/**
 * Target:只允许该注解可以标注类、方法
 * Retention:这个注解可以被反射
 */
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
    String name();
    String password();
}

/**
 * Target:只允许该注解可以标注类、方法
 * Retention:这个注解可以被反射
 * value属性的注解
 */

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface AnnotationValue{
    String value();
}

@interface MyAnnotation {
    /**
     * 在注解中定义属性,一下这个是MyAnnotation的name属性
     * 看着像一个方法,实际上是属性
     * @return
     */
    String name();

    String color();

    int age() default 24; // 属性指定默认值
}

4,开发中如何使用注解

需求:假设有一个注解叫做:Uid;这个注解只能出现在类上面,当这个类上有这个注解的时候,
要求这个类中必须有一个int类型的uid属性,如果没有这个属性就报异常,如果有正常执行。

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

public class AnnotationTest02 {
    public static void main(String[] args) throws Exception {
        // 获取类
        Class uc = Class.forName("com.javaSE.annotation.User");
        boolean isOk = false; // 设置一个默认boolean标记
        // 判断类上是否有Uid注解
        if (uc.isAnnotationPresent(Uid.class)){
            // 有Uid注解 要求必须存在int类型的uid属性
            // 获取类的属性
            Field[] fields = uc.getDeclaredFields();
            for (Field field : fields){
                // 表示这个类的是合法的类,有@Uid注解,类中存在int类型的uid
                if ("uid".equals(field.getName()) && "int".equals(field.getType().getSimpleName())){
                    isOk = true;// 表示合法
                    break;
                }
            }
            // 判断是否合法
            if (!isOk){//不合法
                throw  new HasNotUidPropertyException("被@Uid注解的类必须要有一个int类型的uid属性");
            }

        }
    }

}
/*
自定义异常
 */
class HasNotUidPropertyException extends RuntimeException{
    public HasNotUidPropertyException() {
    }

    public HasNotUidPropertyException(String message) {
        super(message);
    }
}

/*
自定对象
 */
@Uid
class User{
//    int uid;
    String name;
    String password;
}

/**
 * Target:只允许该注解可以标注类
 * Retention:这个注解可以被反射
 *
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Uid{

}

上篇:JavaSE进阶十一 反射机制一

你可能感兴趣的:(JavaSE进阶十一 反射机制二)