进击的Android工程师之Java基础: 反射
2018-03-14 13:54
471 查看
反射机制呢就是在程序运行时,动态的获取类(class),类的方法(method)属性(field)等。主要的注意点就是程序运行时动态的获取。
这里主要是从代码的角度来讲解Java反射。在使用中我们用的较多的几个类有
下面我们分别介绍下。
cat.getClass
Cat.class
Class.forName(“xyz.magicer.Cat”)
在使用中根据实际情况选择,获取
不过改方法会抛出两个异常:
- InstantiationException :当该Class不能被实例化的时候抛出该异常,例如,为抽象类、接口、数组类、基本类、Void等时。
- IllegalAccessException:当无参构造为私有时
还有一种创建实体的方式是使用
-
-
-
-
通过上面的代码我们能看到,getMethods()可以获取父类的方法,但是不能获取私有方法,而getDeclaredMethod()方法不可以获取父类的方法,但是可以获取私有的方法。getMethod也是一样,可以获取父类父接口方法,但是无法获取私有方法,而getDeclaredMethod可以获取私有方法不能获取父类父接口方法。
而带s和不带s的区别是带s返回值为
invoke接收两个参数,第一个是调用该方法的实体,第二个是方法的参数。参数类型多个时顺序要跟方法参数相同。
我们会发现当私有方法invoke调用时会抛出IllegalAccessException,不是可以获取么为什么不能调用?因为方法有权限修饰符,我们需要设置成我们可以调用的。如下:
在调用前设置为可以调用就解决了。
在前面我们接触到了两个Method类的方法了(getName,和invoke)。
getAnnotations(): 可以获取父类的注解
getDeclaredAnnotations(): 不可以返回父类的注解
getAnnotation(Class annotationClass)
getDeclaredAnnotation(Class annotationClass)
getParameters(): 返回Parameter[] (java1.8加入)
在使用反射设置属性的时候一定要注意,可能在代码中用到该属性的地方较多,改变了值之后引起一些意想不到的效果。
getConstructors(),getDeclaredConstructors,getConstructor(Class
到这里我们看到,通过反射创建一个对象有两种方式:(1)class.newInstance()和(2)consturctor.newInstance(Object … initargs)。那么他们有什么区别呢?
方式(1)只能调用无参构造创建对象,并且无参构造不能为私有,而方式(2)可以调用所有
这里主要是从代码的角度来讲解Java反射。在使用中我们用的较多的几个类有
Class,
Method,
Field,
Constructor,
Annotation等。
下面我们分别介绍下。
获取Class
获取class对象有如下三种方式:cat.getClass
Cat.class
Class.forName(“xyz.magicer.Cat”)
//方式1 调用对象的getClass()方式,该方法属于Object类 Class<? extends Cat> aClass = cat.getClass(); //方式2 直接类.class获取。 Class<Cat> catClass = Cat.class; //方式3 通过Class类的静态方法forName获取,参数为想要获取的类的全名(含包名,不然会报ClassNotFoundException) try { Class<?> cat2 = Class.forName("xyz.magicer.Cat"); } catch (ClassNotFoundException e) { e.printStackTrace(); }
在使用中根据实际情况选择,获取
Class对象是我们使用反射的第一步。不过还是很简单的。获取了
Class对象后,怎么创建一个实体呢?
catClass.newInstance()
不过改方法会抛出两个异常:
InstantiationException和
IllegalAccessException
- InstantiationException :当该Class不能被实例化的时候抛出该异常,例如,为抽象类、接口、数组类、基本类、Void等时。
- IllegalAccessException:当无参构造为私有时
还有一种创建实体的方式是使用
Constructor,在下边在介绍。
Method
获取Method
类或接口的方法对应这Method这个类。我们通过Class对象来获取。主要方法有
-
getMethods(): 返回
Method[]返回所有
public的方法。
包含父类或父接口的方法。
-
getDeclaredMethods(): 返回
Method[]返回所有的方法。包括
private
public
default和
protected的。
不包含父类或父接口的方法
-
getMethod(String name, Class<?>... parameterTypes): 返回
Method, 根据方法名和类型获取Method。类或接口的及父类父接口公共成员方法。
-
getDeclaredMethod(String name, Class<?>... parameterTypes): 返回
Method。根据方法名和类型返回Method。类和接口的所有方法。
//sleep是private的 Method[] methods = catClass.getMethods(); for (Method method : methods) { //method.getName() 返回方法名,不包括修饰符,参数和返回值。 System.out.printf(method.getName()+" "); } // 打印toString getName setName setColor eat eat getAge setAge getColor wait wait wait equals hashCode getClass notify notifyAll System.out.println(); Method[] declaredMethods = catClass.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.printf(declaredMethod.getName()+" "); } //打印 toString getName setName sleep setColor eat eat getAge setAge getColor //抛出NoSuchMethodException 因为sleep的访问权限为private //Method sleep1 = catClass.getMethod("sleep", null); Method hashCode = catClass.getMethod("hashCode", null); //抛出NoSuchMethodException,因为hashCode是父类的方法。 //Method hashCode1 = catClass.getDeclaredMethod("hashCode", null); Method eat2 = catClass.getMethod("eat",null); Method sleep1 = catClass.getDeclaredMethod("sleep", null);
通过上面的代码我们能看到,getMethods()可以获取父类的方法,但是不能获取私有方法,而getDeclaredMethod()方法不可以获取父类的方法,但是可以获取私有的方法。getMethod也是一样,可以获取父类父接口方法,但是无法获取私有方法,而getDeclaredMethod可以获取私有方法不能获取父类父接口方法。
而带s和不带s的区别是带s返回值为
Method[],不带返回的是
Method。
调用Method
既然我们获取到了方法(Method)当然是想调用它,那么怎么调用呢?Method有个方法invoke(Object obj, Object... args).
invoke接收两个参数,第一个是调用该方法的实体,第二个是方法的参数。参数类型多个时顺序要跟方法参数相同。
Method eat1 = catClass.getMethod("eat"); eat1.invoke(catInstance,null); //打印:我只吃小鱼干。 Method eat = catClass.getDeclaredMethod("eat"); eat.invoke(catInstance,null); //打印: 我只吃小鱼干。 Method sleep = catClass.getDeclaredMethod("sleep"); //IllegalAccessException sleep.invoke(catInstance,null);
我们会发现当私有方法invoke调用时会抛出IllegalAccessException,不是可以获取么为什么不能调用?因为方法有权限修饰符,我们需要设置成我们可以调用的。如下:
sleep.setAccessible(true); sleep.invoke(catInstance,null);
在调用前设置为可以调用就解决了。
在前面我们接触到了两个Method类的方法了(getName,和invoke)。
Method常用方法
getModifiers(): 返回方法修饰符getAnnotations(): 可以获取父类的注解
getDeclaredAnnotations(): 不可以返回父类的注解
getAnnotation(Class annotationClass)
getDeclaredAnnotation(Class annotationClass)
getParameters(): 返回Parameter[] (java1.8加入)
Field
获取Field对象的方式跟Method一样,用法和规律都一样。无非是现在方法改为getFields()、getDeclaredFields()、getField(String)、getDeclaredField(String)。设置Field
可以通过set方法来设置值public void set(Object obj, Object value)每种基本数据类型都有的setxxx()方法。
//name 为私有 Field name = catClass.getDeclaredField("name"); name.setAccessible(true); name.set(cat,"啦啦啦"); System.out.println("\n"+cat.toString());
在使用反射设置属性的时候一定要注意,可能在代码中用到该属性的地方较多,改变了值之后引起一些意想不到的效果。
Constructor
获取Constructor对象的方式跟Field和Method一样。有四个方法:getConstructors(),getDeclaredConstructors,getConstructor(Class
Constructor<Cat> constructor1 = catClass.getDeclaredConstructor(String.class, int.class, String.class); Cat cat1 = constructor1.newInstance("喵喵2", 3, "white"); System.out.println(cat1.toString());
到这里我们看到,通过反射创建一个对象有两种方式:(1)class.newInstance()和(2)consturctor.newInstance(Object … initargs)。那么他们有什么区别呢?
方式(1)只能调用无参构造创建对象,并且无参构造不能为私有,而方式(2)可以调用所有
Constructor<Cat> constructor1 = catClass.getDeclaredConstructor(String.class, int.class, String.class); Cat cat1 = constructor1.newInstance("喵喵2", 3, "white"); System.out.println(cat1.toString());
//调用私有构造
Constructor<Cat> constructor2 = catClass.getDeclaredConstructor(String.class);
constructor2.setAccessible(true);
Cat miaomiao = constructor2.newInstance("miaomiao");
System.out.println(miaomiao.toString());
相关文章推荐
- 进击的Android工程师之Java基础: 注解
- 面试复习——Android工程师之Java基础
- android基础篇------------java基础(5) 类的反射
- Android开发工程师必看面试题:java基础知识盘点
- android反射组件 (一)java 自定义annotation基础知识
- Android开发工程师必看笔试题:Java基础选择题(一)
- android反射组件 (一)java 自定义annotation基础知识
- android反射组件 (一个)java 它们的定义annotation基础知识
- 面试复习——Android工程师之Java基础
- Android框架常用java基础知识:反射,注解,动态代理
- JAVA基础--JAVA中的反射机制详解
- JAVA基础--JAVA中的反射机制详解
- day01 ,Java 基础加强(反射)
- Java基础——反射
- java获取http:图片下载代码——android基础编
- java获取http:图片下载代码——android基础编
- java基础加强--反射
- Android系统原理与源码分析(1):利用Java反射技术阻止通过按钮关闭对话框
- Java EE WEB工程师培训-JDBC+Servlet+JSP整合开发之12.Servlet基础(3)
- Android系统原理与源码分析(1):利用Java反射技术阻止通过按钮关闭对话框