天天看点

java反射机制学习笔记

1、Class类进行操作

如果想要使用Class类进行操作,那么就必须返回一个Class类的实例化对象,取得实例化对象的方法:

1)Object类中提供了一个返回class对象的方法:public class<?>getClass();

2)利用"类.class"取得,日后在Hibernate上。

3)利用Class类的static 方法取得,public static Class<?>forName(String className);

利用反射实例化对象,只需要知道类的名称即可实例化对象

Class类使用了forName方法之后,可以使用Class类定义的newInstance方法进行操作。

Public T newInstance()throws InstantiationException,IllegalAccessException;此泛型使用不到。

范例:

package com.demo;

class Student{

    public Student(){

        System.out.println("this is Student Constuctor method");

    }

    public String toString(){

        return "student's toString() method";

    }

}

public class ReflectDemo {

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {

        Class<?> cls=Class.forName("com.demo.Student");

        Object obj=cls.newInstance();

        System.out.println(obj);

    }

}

2、操作构造方法Constuctor

但是如果使用反射实例化对象,必须要求类中存在有无参构造方法。因为默认Class的newInstance()只能够找到无参,这时只能够取得类之中的构造方法进行传递所需要的参数后才可以执行。

在class类中取得构造方法的的操作

1)取得类的全部构造方法 public Constructor<?>getConstructors()throws SecurityException;

2)取得类中指定参数的构造方法

public Constructor<T>getDeclaredConstructor(Class... parameterTypes)throws NoSuchMethodException  SecurityException

所以如果现在要想进行指定构造方法的调用,就必须得关注点放在Constructor类之中,在此类中定义了一个实例化对象方法,

public newInstance(Object... initargs)   throws

InstantiationException,IllegalAccessException,IllegalArgumentException,InvocationTargetException

范例:

package com.demo;

import java.lang.reflect.Constructor;

class Student {

private String name;

private Integer age;

public Student(String name, Integer age) {

this.name = name;

this.age = age;

}

public String toString() {

return "name:" + this.name + "  age:" + this.age;

}

}

public class ReflectDemo {

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

Class<?> cls = Class.forName("com.demo.Student");

Constructor<?> cons = cls.getConstructor(String.class, Integer.class);

Object obj = cons.newInstance("Smith", 20);

System.out.println(obj);

}

}

正是因为如果通过构造方法实例化对象规格不统一,所以在进行简单Java类操作的时候给出必须有无参构造方法。

3、调用类中方法Method

取得实例化对象之后,下面的主要任务是调用类中的方法,实际上由两类:

1)取得父类继承而来的方法

a. 取得全部方法

public Constructor[] getConstructors() throws SecurityException

b. 取得指定方法

public Constructor<T> getConstructor(Class... parameterTypes) throws NoSuchMethodException,SecurityException

2)取得本类定义的方法

a.取得全部方法public Method[] getDeclaredMethods()throws SecurityException

b.取得指定方法public Method getDeclaredMethod(String name, Class... parameterTypes)throws NoSuchMethodException, SecurityException

但是以上的操作方法定义上区别不大,因为大部分是public,所以两种方式取得的结果没有区别。

范例:取得全部方法

package com.demo;

import java.lang.reflect.Constructor;

import java.lang.reflect.Method;

interface Message{

public void get();

}

class Student implements Message {

public void fun(){}

public void prinf(){}

public void get(){}

}

public class ReflectDemo {

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

Class<?> cls = Class.forName("com.demo.Student");

Method met[]=cls.getMethods();

for(int i=0;i<met.length;i++)

System.out.println(met[i]);

}

}

现在程序是直接调用的Method类之中的toString方法实现输出。如果用户有需要也可自己整理方法的输出,需要使用到Method类的方法。

.取得方法修饰符:public void getModifiers();

程序之中找不到static/public等关键字,而是关键字所代表的值,但是在程序之中必须将其转换为可以读懂的信息,则可以借助于modifier类中的public static String toString(int mod),使得数字变换为关键字。

.取得方法的返回参数:public Type getGenericReturnType();

.取得方法的参数:public Type[] getGenericParameterTypes();

.取得所抛出的异常:public Type[] getGenericExceptionTypes();

范例:

package com.demo;

import java.lang.reflect.Constructor;

import java.lang.reflect.Method;

import java.lang.reflect.Type;

interface Message{

public void get();

}

class Student implements Message {

public void fun(){}

public void prinf(){}

public void get(){}

}

public class ReflectDemo {

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

Class<?> cls = Class.forName("com.demo.Student");

Method met[]=cls.getMethods();

for(int i=0;i<met.length;i++){

System.out.print(met[i].getModifiers()+"   ");

System.out.print(met[i].getReturnType().getSimpleName()+"  ");

System.out.print(met[i].getName());

Type[] params=met[i].getGenericParameterTypes();

 Type[] exs=met[i].getGenericExceptionTypes();

 if(params.length>0){//输出方法的参数

System.out.print("("+"arg- ");

for(int j=0;j<params.length;j++){

System.out.print(j+params[j].getTypeName());

if(j<params.length-1)

System.out.print(",");

}

System.out.print(")");

}

 if(exs.length>0){//输出方法的异常

 System.out.print(" throws ");

 for(int j=0;j<params.length;j++){

System.out.print(exs[j].getTypeName());

if(j<params.length-1)

System.out.print(",");

}

System.out.print(")");

}

System.out.println();

}

}

}

此类代码只会在编写开发工具的时候出现,而所谓的随笔提示功能就是根据以上代码实现的。但是与开发者密切关联最紧密的一定是利用Method调用类的方法,而且在method类有一个重要的方法,public Object invoke(Object obj,  Object... args)throws IllegalAccessException, IllegalArgumentException,InvocationTargetException;对带有指定参数的指定对象调用由此 Method 对象表示的基础方法。

范例:反射调用类中的方法

package com.demo;

import java.lang.reflect.Constructor;

import java.lang.reflect.Method;

import java.lang.reflect.Type;

class Student  {

private String name;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

}

public class ReflectDemo {

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

Class<?> cls = Class.forName("com.demo.Student");

Object obj=cls.newInstance();

Method setNameMethod=cls.getMethod("setName", String.class);

Method getNameMethod=cls.getMethod("getName");

setNameMethod.invoke(obj,"Smith");

System.out.println(getNameMethod.invoke(obj));

}

}

4、调用类中的属性(尽量不要使用)Field

关于类中的属性也可采用反射进行操作,而支持的方法有两类

.取得所继承类而来的属性

.取得全部属性public Field[] getFields() throws SecurityException

.取得指定属性public Field getField(String name) throws NoSuchFieldException,SecurityException

.取得本类定的属性

.取得全部属性public Method[] getDeclaredMethods() throws SecurityException

.取得指定属性public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException

范例:package com.demo;

import java.lang.reflect.Field;

interface Message {

public static final String INFO = "Hello World";

}

class Student extends Person implements Message {

private String school;

private Double price;

}

class Person {

private String name;

private Integer age;

}

public class ReflectDemo {

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

Class<?> cls = Class.forName("com.demo.Student");

{

// 取得全部继承而来的属性

Field fs[] = cls.getFields();

if (fs.length > 0) {

for (int i = 0; i < fs.length; i++) {

System.out.println(fs[i]);

}

}

}

{

// 取得本类属性

Field fs[] = cls.getDeclaredFields();

if (fs.length > 0) {

for (int i = 0; i < fs.length; i++) {

System.out.println(fs[i]);

}

}

}

{

// 取得父类属性

Field fs[] = cls.getSuperclass().getDeclaredFields();

if (fs.length > 0) {

for (int i = 0; i < fs.length; i++) {

System.out.println(fs[i]);

}

}

}

}

}

在Filed类里面还要定义属性调用的方法:

.设置属性内容:

public void set(Object obj, Object value) throws IllegalArgumentException,IllegalAccessException

.取得属性内容:public Object get(Object obj)throws IllegalArgumentException,IllegalAccessException

在constructor、method、field三个类上有一个共同的父类AccessibleObject这个类里面定义有取消封装操作:public void setAccessible(boolean flag) throws SecurityException;值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。

范例:package com.demo;

import java.lang.reflect.Field;

class Student {

private String school;

private Double price;

}

public class ReflectDemo {

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

Class<?> cls = Class.forName("com.demo.Student");

Object obj = cls.newInstance();

Field schoolf = cls.getDeclaredField("school");

schoolf.setAccessible(true);

schoolf.set(obj, "清华大学");

System.out.println(schoolf.get(obj));

}

}

在开发中,只需要灵活使用Class、Constructor、Method、Field就可使用反射进行一系列操作代码的实现。