您的位置:首页 > 编程语言 > Java开发

java-反射

2017-08-12 11:34 274 查看
反射(Reflection)是Java程序开发语言的特征之一。通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。程序中一般的对象都是在编译时期就确定下来,而Java反射机制可以动态的创建对象并调用其属性和方法。

Java反射框架主要提供以下功能:

1.在运行时判断任意一个对象所属的类
2.在运行时构造任意一个类的对象
3.在运行时判断任意一个类的成员变量和方法
4.在运行时调用任意一个类的对象的方法


反射的主要用途

反射主要用在各种通用框架的开发上。

在平时的Android开发中,用到反射的机会非常之少。但是理解一下反射,有助于借助android源码实现一些眼前一亮的功能,也有利于丰富自己的编程技能。

文中示例代码地址:

github地址

反射的基本运用

示例代码中的Person类和Base类可以从我提供的github地址中看到

获取Class对象

使用Class类的forName方法;

调用对象的getClass方法;

类名.class直接获取。

示例代码如下:

//使用Class类的forName方法
@Test
public void f1() throws NoSuchFieldException, ClassNotFoundException {
Class<?> personClass = Class.forName("person");
}

//直接获取
@Test
public void f2() {
Class<Person> personClass = Person.class;
}

//调用对象的getClas方法
@Test
public void f3() {
Person person = new Person();
Class<? extends Person> personClass = person.getClass();
}


判断对象是否属于某一个类

可以用instanceOf来判断对象是否是某个类的实例,也可以实用反射中Class对象的isInstance()方法来判断。

代码示例:

@Test
public void f1() {
try {
Class<?> personClass = Class.forName("bean.Person");
System.out.println(personClass.isInstance(new Person()));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}


使用反射来生成对象

使用Class对象的newInstance()来创建Class对象对应的类的对象

通过Class对象获取到指定的Constructor对象,在调用Constructor对象的newInstance()方法来创建对象。

代码示例:

public void createObjByClass() {
Class personClass = null;
try {
personClass = Class.forName("bean.Person");
Person person = (Person) personClass.newInstance();
System.out.println(person);
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}

}

public void createObjByConstructor() {
try {
Class<?> personClass = Class.forName("bean.Person");
//获取构造函数来创建对象
Constructor<?> constructor = personClass.getConstructor();
try {
Person newInstance = (Person) constructor.newInstance();
System.out.println(newInstance.toString());
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException e) {
e.printStackTrace();
}
}


获取类的方法

获取某个Class对象的方法集,主要有以下几个方法:

getDeclaredMethods()

getMethods()

getMethod(String name, Class… parameterTypes)

getDeclaredMethod(String name, Class… parameterTypes)

getDeclaredMethods()方法返回类或接口声明的所有方法,包括public,protected,default,private,但不包括继承的方法。示例代码如下:

@Test
public void f1() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
Class<?> personClass = Class.forName("bean.Person");
Person person = (Person) personClass.newInstance();
//通过getDeclaredMethods方法获取到类或者接口的所有方法,包括public、private、default、protected,但是不包括继承的方法
Method[] declaredMethods = personClass.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
}


运行结果如图所示:



getMethods()方法返回类的所有的公共方法(public修饰),包括继承来的公用方法。代码示例:

@Test
public void f2() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class<?> personClass = Class.forName("bean.Person");
Person person = (Person) personClass.newInstance();
//通过getMethods方法获取类的所有的公共方法,包括继承的public方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}


运行结果如图所示:



getMethod()返回的是一个特定的方法,第一个参数是方法名字,第二个参数是方法的参数类型对应的class对象。示例代码

@Test
public void f3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> personClass = Class.forName("bean.Person");
Person person = (Person) personClass.newInstance();
//通过getMethod获取特定的公共方法。
Method setWeight = personClass.getMethod("setWeight", float.class);
setWeight.invoke(person, 12);
System.out.println(person);
}


运行结果如图所示:



getDeclaredMethod()可以获取到私有的方法。下面是一段获取到私有方法并执行的示例代码

//通过反射获取私有方法并执行
@Test
public void f4() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> personClass = Class.forName("bean.Person");
Person person = (Person) personClass.newInstance();
Method sys = personClass.getDeclaredMethod("sys", String.class);
sys.setAccessible(true);
sys.invoke(person, "HAHAHA");
}


结果如图所示:



获取类的属性

getFields—获取所有的public属性,包括继承来的。

getDeclaredFields—获取所有的属性,不包括继承来的。

getField()和getDeclaredField()

getFields获取所有的public属性,示例代码如下:

@Test
public void f1() throws IllegalAccessException, InstantiationException {
Class<Person> personClass = Person.class;
Person person = personClass.newInstance();
//获取公共属性
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
}


输入结果如下图所示:



getDeclaredFields()获取所有的属性,不包括继承来的。

@Test
public void f2() throws IllegalAccessException, InstantiationException {
Class<Person> personClass = Person.class;
Person person = personClass.newInstance();
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
}


输出如下图所示:



getField()可以获取指定的public属性

getDeclaredField()可以获取指定的public、protected、default、private属性,不包括继承来的。

下面用一段代码说明如何获取到指定的私有属性并修改其属性值

//修改私有属性的值
@Test
public void f3() throws IllegalAccessException, InstantiationException, NoSuchFieldException {
Class<Person> personClass = Person.class;
Person person = personClass.newInstance();
Field age = personClass.getDeclaredField("age");
age.setAccessible(true);
age.setInt(person, 19);
System.out.println(person.toString());
}


输入如下图所示:



使用反射生成数组

示例代码:

import java.lang.reflect.Array;

/**
* Desc:
* Created by WangGuoku on 2017/8/11 16:13.
*/
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> stringClass = Class.forName("java.lang.String");
Object array = Array.newInstance(stringClass, 10);
Array.set(array, 0, "Java");
Array.set(array, 1, "Php");
Array.set(array, 2, "C++");
Array.set(array, 3, "Python");
Array.set(array, 4, "Go");
System.out.println(Array.get(array, 3));
System.out.println(Array.getLength(array));
}
}


反射会额外消耗一定的系统资源,因此如果没有必要,就不要用反射。反射还会忽略权限检查,因此可以绕过泛型,还会破坏封装性。

附Base类和Person类代码:

package bean;

/**
* Desc:
* Created by WangGuoku on 2017/8/11 16:05.
*/
public class Base {
public String addr;

public String getAddr() {
return addr;
}

public void setAddr(String addr) {
this.addr = addr;
}

@Override
public String toString() {
return "Base{" +
"addr='" + addr + '\'' +
'}';
}
}


package bean;

import bean.Base;

/**
* Desc:
* Created by WangGuoku on 2017/8/11 1:48.
*/
public class Person extends Base {
public String name;
public String sex;
private int age;
private float weight;
protected String hobby;

public Person(String name, String sex, int age, float weight, String hobby) {
this.name = name;
this.sex = sex;
this.age = age;
this.weight = weight;
this.hobby = hobby;
}

public Person() {

}

public String getHobby() {
return hobby;
}

public void setHobby(String hobby) {
this.hobby = hobby;
}

private void sys(String msg) {
System.out.println(msg);
}

private void sys() {
System.out.println("测试无参数私有方法");
}

public String getName() {
return name;
}

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

public String getSex() {
return sex;
}

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

public int getAge() {
return age;
}

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

public float getWeight() {
return weight;
}

public void setWeight(float weight) {
this.weight = weight;
}

@Override
public String toString() {
return "bean.Person{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
", weight=" + weight +
", hobby='" + hobby + '\'' +
'}';
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 反射基础