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进阶十一 反射机制一

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容