Java反射详解

对象的编译类型和运行类型

对象有编译类型和运行类型

1
Object obj = new Date();

编译类型:Object
运行类型(其实就是obj对象真实的类型):Date
需求:根据对象obj调用Date类中的一个方法,toLocaleString,如何来做?
obj.toLocaleString()代码在编译阶段去编译类型Object中检查是否有该方法,若没有,编译失败。

解决方案:强制转为obj为Date类型,前提:必须知道对象的真实类型是什么?

12
Date d = (Date)obj;d.toLocaleString();

万物皆对象:从概念分析类也是一种对象,新的问题,既然类是一种对象,那么谁又来描述该对象呢?而我们又说描述对象的类都是对象
元数据:metadata描述数据的描述数据
反射:得到元数据的行为,既然Class是对一切类共同功能行为和状态的抽象
那么Class重有应该有类具备的成员:
getPackage() 表示类的包
getSuperClass() 表示类的父类
getMethods() 类的方法
getField() 类的字段

Class类和Class实例

Class类:用于描述一切类/接口,枚举是一种类,注解是一种借口。
Class实例:就是指JVM中的一份字节码
问题:那Class实例到底表示的是哪一份字节码,为了明确区分出Class实例表示的是谁的字节码。Class类提供了泛型。
Class clz1 = Date.class // clz1表示的是Date的字节码
Class clz2 = String.class // clz2表示的是String的字节码

如何得到Class的实例?
1、类型.class(就是一份字节码)
2、Class.forName(String className);根据一个类的全限定名来构建Class对象
3、每一个对象都有getClass()方法,obj.getClss();返回对象的真实类型

9个预定义Class对象

基本的Java类型(boolean、byte、char、short、int、long、float和double)和关键字void也表示为Class对象
表示int的Class对象:Class clz = int.class;
表示boolean的Class对象:boolean.class;
表示void的Class对象:void.class;

所有的数据类型都有class属性,表示都是Class对象。
在八大基本数据类型的包装类中都有一个常量:TYPE
TYPE表示的是该包装类对应的基本数据类型的Class实例
如Integer.TYPE == int.class //true
Integer.class == int.class //false

数组的Class实例

String[] sArr = {“A”, “C”};
String[] sArr2 = {};
String[][] sArr3 = {};
int[] sArr4 = {};
表示数组的Class实例:
所有具有相同元素类型和维数的数组都共享该Class对象。
注意:和数组中的元素没有一点关系。

反射的实例

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
package 面试题;

import java.util.Arrays;

/** * Created by piqiu on 3/3/16. */public class User {

private String name;    private int age;    private int sex;

public User() {        System.out.println("public User()");    }

private User(String name) {        this.name = name;        System.out.println("private User(String name): " + name);    }

public User(String name, int age, int sex) {        this.name = name;        this.age = age;        this.sex = sex;        System.out.println("public User(String name, int age, int sex): " + name + " " + age + " " + sex);    }

public String getName() {        return name;    }

public void setName(String name) {        this.name = name;    }

public int getAge() {        return age;    }

public void setAge(int age) {        this.age = age;    }

public int getSex() {        return sex;    }

public void setSex(int sex) {        this.sex = sex;    }

private void sayHello() {        System.out.println("hello...");    }

public void sayHi(String name) {        System.out.println("hi..." + name);    }

public double getMoney(String name) {        double money = 200.12;        System.out.println("get money " + money + " for " + name);        return money;    }

public static void staticMethod() {        System.out.println("invoke static method...");    }

public static int show(int... args) {        int ret = 0;        for (int i : args) {            ret += i;        }        return ret;    }

public static void show2(String... args) {        System.out.println(Arrays.toString(args));    }

@Override    public String toString() {        return "User -> name: " + ((name == null)?"无名氏":name) + " age: " +                ((age == 0)?"无年龄":age) + " sex: " + ((sex == 1)?"男":(sex == 2)?"女":"无性别");    }}
1234567891011
package 面试题;

import java.util.Map;

/** * Created by piqiu on 3/7/16. */public class OOXX {

public Map<String, Object> cache;}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
package 面试题;

import java.lang.reflect.*;import java.util.Arrays;import java.util.List;

/** * Created by piqiu on 3/3/16. */public class ReflectionDemo {

private static Class<User> clz = User.class;    private static Class<OOXX> ooxxClass = OOXX.class;

private ReflectionDemo(){}

public static void main(String[] args) throws Exception {//        getConstructors();//        getConstructor();//        getDeclaredConstructors();//        getDeclaredConstructor();//        invokeConstructor();//        getAllMethods();//        getOneMethod();//        invokeMethod();//        invokeStaticMethod();//        invokeVariableLengthMethod();//        getAllFields();//        invokeField();//        getFieldValue();//        getOtherAPI();//        invokeGenericMethod();        getGenericFieldType();    }

/**     * 获取所有的【public修饰】的构造器     */    private static void getConstructors() {        Constructor<?>[] constructors = clz.getConstructors();        for (Constructor c : constructors) {            System.out.println(c);            System.out.println(Arrays.toString(c.getParameterTypes()));            System.out.println(c.getDeclaringClass());        }        /**         public 面试题.User(java.lang.String,int,int)         [class java.lang.String, int, int]         class 面试题.User         public 面试题.User()         []         class 面试题.User         */    }

/**     * 根据构造器参数的Class类型获得对应的Constructor,只能获取【public修饰】的     * @throws NoSuchMethodException     */    private static void getConstructor() throws NoSuchMethodException {        Constructor<User> constructor1 = clz.getConstructor();        System.out.println(constructor1);    // public 面试题.User()        Constructor<User> constructor3 = clz.getConstructor(String.class, int.class, int.class);        System.out.println(constructor3);   // public 面试题.User(java.lang.String,int,int)    }

/**     * 获取所有构造器,和访问权限无关     */    private static void getDeclaredConstructors() {        Constructor<?>[] declaredConstructors = clz.getDeclaredConstructors();        for (Constructor c : declaredConstructors) {            System.out.println(c);            System.out.println(Arrays.toString(c.getParameterTypes()));            System.out.println(c.getDeclaringClass());        }        /**         public 面试题.User(java.lang.String,int,int)         [class java.lang.String, int, int]         class 面试题.User         public 面试题.User(java.lang.String)         [class java.lang.String]         class 面试题.User         private 面试题.User()         []         class 面试题.User         */    }

/**     * 获取指定参数类型的构造器,和访问权限无关     * @throws NoSuchMethodException     */    private static void getDeclaredConstructor() throws NoSuchMethodException {        Constructor<User> declaredConstructor = clz.getDeclaredConstructor(String.class);        System.out.println(declaredConstructor);    // private 面试题.User(java.lang.String)    }

private static void invokeConstructor() throws Exception {        // 这种newInstance方法只能作用于 public 的 无参构造方法,局限性太大        User user1 = clz.newInstance();        System.out.println(user1);

Constructor<User> constructor1 = clz.getDeclaredConstructor();        User user2 = constructor1.newInstance();        System.out.println(user2);

Constructor<User> constructor2 = clz.getDeclaredConstructor(String.class);        constructor2.setAccessible(true);   // 不加这句就实例化不了私有(private)的构造器        User user3 = constructor2.newInstance("呵呵");        System.out.println(user3);

Constructor<User> constructor3 = clz.getDeclaredConstructor(String.class, int.class, int.class);        User user4 = constructor3.newInstance("哈哈", 22, 2);        System.out.println(user4);

/**         public User()         User -> name: 无名氏 age: 无年龄 sex: 无性别         public User()         User -> name: 无名氏 age: 无年龄 sex: 无性别         private User(String name): 呵呵         User -> name: 呵呵 age: 无年龄 sex: 无性别         public User(String name, int age, int sex): 哈哈 22 2         User -> name: 哈哈 age: 22 sex: 女         */    }

/**     * getDeclaredMethods和getMethods区别     *      getMethods获得包括自身和继承过来的所有public方法     *      getDeclaredMathods获取自身所有的方法,不包括继承的,和访问权限无关     */    private static void getAllMethods() {        Method[] methods = clz.getDeclaredMethods();        for (Method m : methods) {            System.out.println(m);        }        /**         public java.lang.String 面试题.User.toString()         public java.lang.String 面试题.User.getName()         public void 面试题.User.setName(java.lang.String)         public int 面试题.User.getAge()         public void 面试题.User.setAge(int)         public int 面试题.User.getSex()         public void 面试题.User.setSex(int)         private void 面试题.User.sayHello()         public void 面试题.User.sayHi(java.lang.String)         */    }

/**     * 只有通过方法签名才能找到唯一的方法     * 方法名 + 参数列表     * 得到私有方法必须使用 getDeclaredMethod     */    private static void getOneMethod() throws NoSuchMethodException {        Method method1 = clz.getMethod("sayHi", String.class);        System.out.println(method1); // public void 面试题.User.sayHi(java.lang.String)

Method method2 = clz.getDeclaredMethod("sayHello");        System.out.println(method2);    // private void 面试题.User.sayHello()    }

private static void invokeMethod() throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {        Method method = clz.getMethod("getMoney", String.class);        double money = (Double)method.invoke(clz.newInstance(), "benjamin");        System.out.println(money);        /**         public User()         get money 200.12 for benjamin         200.12         */    }

/**     * 调用静态方法     * 如果方法是静态的,那么可以忽略指定的obj参数,将obj参数设为null即可     */    private static void invokeStaticMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {        Method method = clz.getMethod("staticMethod");        method.invoke(null);    // invoke static method...    }

/**     * 调用可变参数的静态方法     */    private static void invokeVariableLengthMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {        Method method = clz.getMethod("show", int[].class);        int result = (Integer)method.invoke(null, new int[]{2, 4});        System.out.println(result); // 6

Method method2 = clz.getMethod("show2", String[].class);        // 下面这么写会报Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments        // 基本类型和引用类型不同,引用类型会自动解包        // 对于数组类型的引用类型的参数,底层会自动进行解包,为了解决该问题,我们使用Object的一维数组把实际参数包装起来        // method2.invoke(null, new String[]{"A", "B", "C"});

method2.invoke(null, new Object[]{new String[]{"A", "B", "C"}});    // [A, B, C]    }

/**     * 获取所有字段,包括私有的     * 如果想只获取public的字段以及父类的public字段,使用getFields()方法     */    private static void getAllFields() {        Field[] declaredFields = clz.getDeclaredFields();        for (Field field : declaredFields) {            System.out.println(field);        }        /**         private java.lang.String 面试题.User.name         private int 面试题.User.age         private int 面试题.User.sex         */    }

/**     * 设置字段的值     */    private static void invokeField() throws NoSuchFieldException, IllegalAccessException, InstantiationException {        Field ageField = clz.getDeclaredField("age");        ageField.setAccessible(true);        Object obj = clz.newInstance();        ageField.set(obj, 12);        System.out.println(obj);        /**         public User()         User -> name: 无名氏 age: 12 sex: 无性别         */    }

/**     * 获取字段值     */    private static void getFieldValue() throws NoSuchFieldException, IllegalAccessException, InstantiationException {        Field ageField = clz.getDeclaredField("age");        ageField.setAccessible(true);        Object obj = clz.newInstance();        Object age = ageField.get(obj);        System.out.println(age);        /**         public User()         0         */    }

private static void getOtherAPI() {        int modifiers = clz.getModifiers();        System.out.println(modifiers);  // 1        System.out.println(Modifier.toString(modifiers));   // public

System.out.println(clz.getName());  // 面试题.User        System.out.println(clz.getSimpleName());    // User        System.out.println(clz.getPackage());   // package 面试题        System.out.println(clz.getSuperclass());    // class java.lang.Object        System.out.println(clz.isArray());  // false        System.out.println(clz.isEnum());   // false    }

/**     * 调用泛型参数的方法     */    private static void invokeGenericMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {        Class clz = Arrays.class;        Method asListMethod = clz.getDeclaredMethod("asList", Object[].class);        List result = (List) asListMethod.invoke(null, new Object[]{new Object[]{"A", "B", "C"}});        System.out.println(result); // [A, B, C]    }

/**     * 得到泛型字段的类型     */    private static void getGenericFieldType() throws NoSuchFieldException {        Field cacheField = ooxxClass.getDeclaredField("cache");        Type genericType = cacheField.getGenericType();        System.out.println(genericType);    // java.util.Map<java.lang.String, java.lang.Object>        ParameterizedType parameterizedType = (ParameterizedType) genericType;        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();        System.out.println(Arrays.toString(actualTypeArguments));   // [class java.lang.String, class java.lang.Object]    }}
时间: 2024-11-02 08:41:17

Java反射详解的相关文章

Java Annotation详解(二): 反射和Annotation

前面一篇文<Java Annotation详解(一): 理解和使用Annotation>中,我们或许会觉得,Annotation注释其实并没有多大的作用,除了几个内建的Annotation偶尔为了消除警告会使用下,自定义Annotation大家在实际的开发中应该都没有用过.其实呢,我在毕业后一年的工作里,也从未自定义使用过Annotation,只是在多处开发中使用过注释方便的内容,比如Servlet,Spring以及一些优秀的Android开源类库. 如果从简单的开发来讲,大家基本会使用一些开

Java虚拟机详解----JVM常见问题总结

[正文] 声明:本文只是做一个总结,有关jvm的详细知识可以参考本人之前的系列文章,尤其是那篇:Java虚拟机详解04----GC算法和种类.那篇文章和本文是面试时的重点. 面试必问关键词:JVM垃圾回收.类加载机制.   先把本文的目录画一个思维导图:(图的源文件在本文末尾)   一.Java引用的四种状态: 强引用: 用的最广.我们平时写代码时,new一个Object存放在堆内存,然后用一个引用指向它,这就是强引用. 如果一个对象具有强引用,那垃圾回收器绝不会回收它.当内存空间不足,Java

Java设计模式详解之门面模式(外观模式)_java

门面模式(Facade Pattern)也叫外观模式,它隐藏系统的复杂性,并向客户端提供一个可以访问系统的接口.这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性,为子系统中的一组接口提供了一个统一的高层访问接口,这个接口使得子系统更容易被访问或使用.这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用. 简而言之,就是把一堆复杂的流程封装成一个接口供给用户更简单的使用,这个设计模式里有三个角色: 1)门面角色( facade ):

java关键字(详解)

基本类型 1 boolean 布尔型 2 byte 字节型 3 char 字符型 4 double 双精度 5 float 浮点 6 int 整型 7 long 长整型 8 short 短整型 9 null 空 10 true 真 11 false 假 程序控制语句 1 break 跳出中断 2 continue 继续 3 return 返回 4 do 运行 5 while 循环 6 if 如果 7 else 否则 8 for 循环 9 instanceof 实例 10 switch 观察 11

Java NIO 详解(一)

NIO即新的输入输出,这个库是在JDK1.4中才引入的.它在标准java代码中提供了高速的面向块的IO操作. 一.基本概念描述 1.1 I/O简介 I/O即输入输出,是计算机与外界世界的一个借口.IO操作的实际主题是操作系统.在java编程中,一般使用流的方式来处理IO,所有的IO都被视作是单个字节的移动,通过stream对象一次移动一个字节.流IO负责把对象转换为字节,然后再转换为对象. 关于Java IO相关知识请参考我的另一篇文章:Java IO 详解 1.2 什么是NIO NIO即New

HBase Java API详解

[本文转自HBase Java API详解] HBase是Hadoop的数据库,能够对大数据提供随机.实时读写访问.他是开源的,分布式的,多版本的,面向列的,存储模型. 在讲解的时候我首先给大家讲解一下HBase的整体结构,如下图: HBase Master是服务器负责管理所有的HRegion服务器,HBase Master并不存储HBase服务器的任何数据,HBase逻辑上的表可能会划分为多个HRegion,然后存储在HRegion Server群中,HBase Master Server中存

请教:朋友跟我想写一本关于JAVA虚拟机详解方面的书。

问题描述 朋友跟我想写一本关于JAVA虚拟机详解方面的书.书的内容主要包括JVM的原理,JVM源码分析等方面的问题.书本身内容清晰,层次很分明,也很通俗易懂.目前书已经写了一半,大概6章的内容..不知道怎么联系出版社,如果出版以后销路会如何.也不知道有没有多少读者会关注JAVA虚拟机方面的知识..大家给点意见,或者渠道..谢谢. 解决方案 解决方案二:顶,一直有个小理想,自己写本jvm分析的书,不过未能实现.感觉这种书很小众.jvm原理的书还可以,但代码分析的未必对大部分java程序员有多大价值

java 多态性详解及常见面试题_java

java多态性 多态分两种: (1)   编译时多态(设计时多态):方法重载. (2)   运行时多态:JAVA运行时系统根据调用该方法的实例的类型来决定选择调用哪个方法则被称为运行时多态.(我们平时说得多的事运行时多态,所以多态主要也是指运行时多态) 运行时多态存在的三个必要条件: 一.要有继承(包括接口的实现): 二.要有重写: 三.父类引用指向子类对象. 多态的好处: 1.可替换性(substitutability).多态对已存在代码具有可替换性.例如,多态对圆Circle类工作,对其他任

Java泛型详解_java

1. Why --引入泛型机制的原因     假如我们想要实现一个String数组,并且要求它可以动态改变大小,这时我们都会想到用ArrayList来聚合String对象.然而,过了一阵,我们想要实现一个大小可以改变的Date对象数组,这时我们当然希望能够重用之前写过的那个针对String对象的ArrayList实现.     在Java 5之前,ArrayList的实现大致如下: public class ArrayList { public Object get(int i) { ... }