Java--Class类相关与反射重温

一、注意点

  • 面向对象的世界中,万事万物皆对象。
  • Java中的类,是java.util.Class类的实例对象
  • 类的类类型,可从以下三种方式得到:
    1. Class<T> clazz = T.class;【因为每个.java文件在被编译成.class文件之后,T类内部就生成了一个静态属性,也就是T.class,它保存了这个类的基本信息】
    2. Class<T> clazz = t.getClass(); 【底层是native方法,用Java声明,用C语言实现,最终在Java中实现,其实就是获取这个静态属性】
    3. Class<T> clazz = Class.forName("类的全称"); 【代表动态加载类】

    动态实现装载类的方式:
    1. 隐式装载:new一个对象时,JRE检查并自动加载
    2. 显式装载:①Class.forName()ClassLoader.loadClass()

  • 基本数据类型和void关键字都存在类类型。
  • Class.getCanonicalName() 返回的是Java Language Specification中定义的基础类的规范化名称,换句话,就是返回全类名,没有就返回null。

二、Class类能给我们什么信息(常见):

  • 获取并打印所有属性信息【访问权限+属性类名+属性名】
public static Field[] getFieldList(Class clazz) {
    Field[] fields = clazz.getDeclaredFields();///获取类中所有的属性(忽略访问修饰符)
    for (Field fieid : fields) {
        Type type = fieid.getType();///获取属性类型
        System.out.println(Modifier.toString(fieid.getModifiers())+" "+type.getTypeName() + " " + fieid.getName());
    }
    return fields;
}

关键点:

  • Class.getDeclaredFields():Field[] : 获取类中所有的属性(忽略访问修饰符)

  • Fieid.getType():Type : 获取属性类型

  • 获取所有方法信息【访问权限+方法名+ 返回值类型 + 方法参数类型】

public static Method[] getMethodList(Class clazz) {
    Method[] methods = clazz.getDeclaredMethods();
    for (Method method : methods) {
        ///分析每一个方法
        getMethodMsg(method);
    }
    return methods;
}
/**
 * 获取Method的返回值类型和参数类型等信息
 * @param method
 */
public static void getMethodMsg(Method method) {
    StringBuilder sb = new StringBuilder();
    ///获取访问权限
    sb.append(Modifier.toString(method.getModifiers())+" ");
    ///返回值类型
    Class<?> returnType = method.getReturnType();
    ////参数类型
    Class[] paramsTypeList = method.getParameterTypes();
    sb.append(returnType.getName()).append("
 ").append(method.getName()).append("(");
    for (Class paramsType : paramsTypeList) {
        sb.append(paramsType.getName()).append(",");
    }
    sb.append(")");
    ///删除多余的","号
    if (sb.lastIndexOf(",") == sb.length() - 1) {
        sb.delete(sb.length() - 2, sb.length() - 1);
    }
    System.out.println(sb.toString());
}

关键点:

  • Class.getDeclaredMethods():Method[] : 获取类中所有的方法(忽略访问修饰符)

  • Method.getParameterTypes():Class[] : 获取方法的参数类类型列表

  • Method.getReturnType():Class : 获取方法的返回值类型

  • 获取构造函数信息【函数名+参数类型】

public static void getConstructorMsg(Object obj) {
    Class clazz = obj.getClass();
    ///封装了构造函数的信息
    Constructor[] constructors = clazz.getDeclaredConstructors();
    for (Constructor item:constructors){
        System.out.print(item.getName()+"(");
        Class[] paramTypes = item.getParameterTypes();
        for (Class type: paramTypes){
            System.out.print(type.getName()+",");
        }
        System.out.println(")");
    }
}

关键点:

  • Class.getDeclaredConstructors():Constructor[] : 获取这个类中所有的构造函数信息(每一个Constructor类对象拥有其中一个构造函数的信息)

  • Constructor.getParameterTypes(): Class[] : 获取这个构造函数的参数类类型列表

  • 调用无参构造方法生成类对象

//动态生成类对象(无参构造函数)
Class<MyObj> clazz = (Class<MyObj>)MyObj.getClass();
T obj = clazz.newInstance();
  • 调用有参构造方法生成类对象
//动态生成类对象(有参构造函数)
Class[] classes = new Class[]{Integer.class, String.class};
Object[] values = new Object[]{100, "hello world"};
Constructor<C> constructor = clazz.getDeclaredConstructor(classes);
C res = (C) constructor.newInstance(values);
  • 对象类型匹配
    方式一:对象 instanceof 类型
如:
Animal dog = new Dog();///Dog是Animal的子类
boolean b = dog instanceof Dog;//判断dog这个对象是不是Dog类型的实例,结果为true

方式二:class对象.isInstance(类对象)

如:
Animal dog = new Dog();///Dog是Animal的子类
boolean b = Dog.class.isInstance(dog);

三、反射的基本用法:

  1. 调用方法Object 返回值 = method.invoke(对象, 参数值列表)
    相当于:对象.method(参数值列表)
    如:
Person xiaoming  = new Person();
Class c = xiaoming.getClass();
//Method m = c.getMethod("print", new Class[]{int.class, int.class});
//m.invoke(xiaoming, new int[]{1,2});
Method m = c.getMethod("print", int.class, int.class);
m.invoke(xiaoming, 1,2);

唯一确定某个方法的因素:方法名称 + 方法参数列表

  1. 修改属性Field.set(对象, 要修改的field值)
    相当于:对象属性赋值操作
    如:
Field field = teacher.getClass().getDeclaredField("name");//获取teacher对象的name属性
field.setAccessible(true);//无视field的访问权限问题
field.set(teacher, "小明老师");

四、关于集合的反射

  • 反射都是在编译完之后的操作
  • 编译之后,有着泛型的集合类型,将去泛型化。【换句话说,Java集合类的泛型,是为了防止错误输入而设定的,只在编译时有效】
  • 通过反射,可以绕过编译,这样一来,比如: 在ArrayList<String> list上执行add(100);添加一个整型,则不会报错。【但是这样做,就不能使用for:each来遍历集合】
List<String> list = new ArrayList<>();
list.add("hello");///添加元素“hello”
try {
    Method methodAdd = list.getClass().getMethod("add", Object.class);
    methodAdd.invoke(list,1);///添加元素1
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
    e.printStackTrace();
} 
System.out.println(list.toString());
///以下遍历报错:java.lang.ClassCastException
///for (String item:list){
///    System.out.println(item);
///}

五、Java反射相关的异常

  • ClassNotFoundException:未在命名空间内找到指定类。(类名错误,或者类不存在)
  • SecurityException:修改了不允许修改的Accessible标志时
  • NoSuchMethodException:找不到特定方法
  • NoSuchFieldException:找不到特定属性
  • IllegalArgumentException:向方法传递了一个不合法或不正确的参数
  • InstantiationException:程序视图使用Class类中的newInstance方法(此方法本身不能应用于基本类型)创建一个类的实例,而指定的类对象无法被实例化时。【如:实例化抽象类或接口,或者视图创建数组类的实例】
  • IllegalAccessException:当我的程序代码想要通过反射去创建一个实例(非数组)、设置或获取一个字段,或者调用一个方法,但是当前正在执行的方法无法访问指定类、字段、方法或构造函数的定义时,抛出的异常。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 1.在C/C++中实现本地方法 生成C/C++头文件之后,你就需要写头文件对应的本地方法。注意:所有的本地方法的第...
    JayQiu阅读 2,340评论 0 3
  • Jni数据类型 Jni方法 来自 http://blog.chinaunix.net/uid-22028680-i...
    FlyDragonInSky阅读 908评论 0 0
  • 一:java概述:1,JDK:Java Development Kit,java的开发和运行环境,java的开发工...
    ZaneInTheSun阅读 2,635评论 0 11
  • 总在快乐的时候、感到微微的惶恐、在开怀大笑时、流下感动的泪水、我无法相信单纯的幸福、对人生的起伏悲喜、既坦然又不安...
    陈琳琳阅读 98评论 0 0
  • 我老公从这周开始每晚下班还上要上两小时日语课,备考四个月,我们的生活猝不及防的发生了一些变化,那就是我下班就要回家...
    柜中猫阅读 320评论 0 1