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

【Java基础知识】Java反射--Class、Constructor、Filed、Method类的使用

2017-01-22 19:12 1106 查看

1、反射概念

是程序可以访问、检测和修改它本身状态或行为的一种能力。Java中的反射,能够创建灵活的代码,这些代码可在运行时装配,无需在组件之间进行源代码链接。简单的说就是:通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。每个类都有一个Class对象,每当编写并且编译了一个新类,就会产生一个Class对象【被保存在一个同名的.class文件中】所有的类都是在对其第一次使用的时候,动态加载到JVM中。Class对象仅在需要的时候才被加载,static初始化是在类加载时进行的。一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。Class类与java.lang.reflect类库一起对反射的概念进行了支持,该类包含了Filed,Method,Constructor类,这些类型的对象由JVM在运行时创建,用以表示未知类里对应的成员。这样就可以使用Constructor创建新的对象,使用它get( ), set( )方法读取和修改与Field对象关联的字段,用invoke( )方法调用Method对象关联的方法。另外,还可以调用getFields()、getMethods( )和getConstructor( )等方法,以返回表示字段、方法、以及构造器的对象的数组。这样匿名对象的类信息就可以在运行的时候被完全确定下来,而在编译时不需要知道任何事情。

2、如何获取Class对象的引用

获取Class对象的引用【返回表示该对象实际类型的Class引用】的方法,常用的有3种:

(1)Object类的getClass()方法:如果我们已经拥有我们所需要类型的对象,就可以通过调用getClass()方法获取Class引用。

(2)类字面常量,数据类型的静态属性class

(3)Class类中的静态方法:public static Class forName(String className).在日常的开发中,常用的是第三种方式获取Class对象,因为是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中。

获取Class对象的引用示例:

public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
/*方式1:通过getClass()方法获取Class对象
* 创建同一个类不同的对象,他们的Class对象是同一个。*/
Person person1 = new Person();
Class clazz1 = person1.getClass();

Person person2 = new Person();
Class clazz2 = person2.getClass();

System.out.println(person1 == person2);// false
System.out.println(clazz1 == clazz2);// true

// 方式2:通过class静态属性获取Class对象
Class clazz3 = Person.class;
System.out.println(clazz1 == clazz3);//true

// 方式3:Class类的静态方法forName()
Class clazz4 = Class.forName("cn.edu.Person");
System.out.println(clazz1 == clazz4);//true
}
}


3、通过Class对象获取Constructor对象,并调用构造方法创建实例

(1)获取单个构造方法

public Constructor<T> getConstructor(Class<?>... parameterTypes):
返回指定参数类型、具有public访问权限的构造函数


public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):
返回指定参数类型、所有声明的(包括private)构造函数


参数表示的是:你要获取的构造方法的,构造参数个数,及数据类型的class字节码文件对象

(2)获取多个构造方法

public Constructor[] getConstructors():所有公共构造方法
public Constructor[] getDeclaredConstructors():所有构造方法


(3)通过获得的Constructor对象,创建新实例

package cn.edu.reflect;

public class Person {
/**
* 3种范围的成员变量:private, 默认,public
* */
private String name;
int age;
public String address;
/**构造函数:无参, 有参(1,2,3个参数)*/
public Person() {
}
private Person(String name) {
this.name = name;
}
Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
/**
* 成员函数:
* ①public, private
* ②有参,无参
* ③无返回值(void),有返回值
* */
public void show() {
System.out.println("show");
}
public void method(String s) {
System.out.println("method " + s);
}
public String getString(String s, int i) {
return s + "---" + i;
}
private void function() {
System.out.println("function");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", address=" + address+ "]";
}
}


public T newInstance(Object... initargs):
使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。


通过反射获取构造方法并使用一:

package cn.edu.reflect;
import java.lang.reflect.Constructor;
/*通过反射获取构造方法并使用*/
public class ReflectDemo {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.edu.reflect.Person");
//1.获取Constructor[]
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//2.获取单个默认构造,并且使用获得的此Constructor 对象,创建类的新实例
Constructor con = clazz.getConstructor();//返回的是构造方法对象
Person person1 = new Person();
System.out.println(person1);
//调用Constructor的newInstance()方法,实例化对象
Object obj = con.newInstance();
System.out.println(obj);
Person person2 = (Person)obj;
person2.show();
}
}
/*运行结果如下:
public cn.edu.reflect.Person(java.lang.String,int,java.lang.String)
cn.edu.reflect.Person(java.lang.String,int)
private cn.edu.reflect.Person(java.lang.String)
public cn.edu.reflect.Person()
Person [name=null, age=0, address=null]
Person [name=null, age=0, address=null]
show
* */


通过反射去获取该构造方法并使用二:

/* public Person(String name, int age, String address)
Person p = new Person("张国荣",47,"香港九龙");
System.out.println(p);
*/


public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.edu.reflect.Person");
/*1.获取带参构造方法对象*/
Constructor con = clazz.getConstructor(String.class, int.class,String.class);
/*2.通过带参构造方法对象创建对象*/
Object obj = con.newInstance("张国荣",47,"香港九龙");
System.out.println(obj);
}
}
/*Person [name=张国荣, age=47, address=香港九龙]*/


通过反射获取私有构造方法并使用三:

/*
private Person(String name){}
Person p = new Person("张国荣");
System.out.println(p);
*/


public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.edu.reflect.Person");
Constructor constructor = clazz.getDeclaredConstructor(String.class);
/*用该私有构造方法创建对象,IllegalAccessException:非法的访问异常,
暴力访问,值为true则指示反射的对象在使用时应该取消Java语言访问检查。*/
constructor.setAccessible(true);
Object obj = constructor.newInstance("张国荣");
System.out.println(obj);
}
}
/* Person [name=张国荣, age=0, address=null]*/


4、通过Class实例获取成员变量对象,并且使用成员变量

通过发生获取成员变量并使用

public Field[] getFields():
返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
public Field getField(String name):
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段
public Field[] getDeclaredFields():
public Field getDeclaredField(String name):


使用代码实例:

public class ReflectDemo4 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.edu.reflect.Person");

//1.获取所有的成员变量
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}

//2.通过无参构造方法创建对象
Constructor constructor = clazz.getConstructor();
Object obj = constructor.newInstance();
System.out.println(obj);

/*3.获取单个的成员变量,获取address【public】并对其赋值
*public void set(Object obj,Object value),第一个参数是要修改字段的对象
* 正被修改对象的字段的新值, 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
* 给obj对象的addressField字段设置值为"香港.九龙" */
Field addressField = clazz.getField("address");
addressField.set(obj, "香港.九龙");
System.out.println(obj);

// 获取name【private】并对其赋值
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj, "张国荣");
System.out.println(obj);

// 获取age【默认】并对其赋值
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(obj, 47);
System.out.println(obj);
}
}
/*
private java.lang.String cn.edu.reflect.Person.name
int cn.edu.reflect.Person.age
public java.lang.String cn.edu.reflect.Person.address
Person [name=null, age=0, address=null]
Person [name=null, age=0, address=香港.九龙]
Person [name=张国荣, age=0, address=香港.九龙]
Person [name=张国荣, age=47, address=香港.九龙]
*/


5、通过Class实例获取Method对象,并调用方法

public Method[] getMethods():

返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口

(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member方法。

public Method[] getDeclaredMethods():

返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,

包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

public Method getMethod(String name,Class

public class ReflectDemo5 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.edu.reflect.Person");
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
Constructor constructor = clazz.getConstructor();
Object obj = constructor.newInstance();

/*1 、获取单个方法【public,无参数,无返回值】,并使用: public void show() */
Method method1 = clazz.getMethod("show");
method1.invoke(obj); //调用obj对象的m1方法

/*2 、获取单个方法【public,有参数,无返回值】,并使用:public void method(String s) */
Method method2 = clazz.getMethod("method", String.class);
method2.invoke(obj, "hello");

/*3 、获取单个方法【public,有参数,有返回值】,并使用:public String getString(String s, int i)*/
Method method3 = clazz.getMethod("getString", String.class, int.class);
String s =(String)method3.invoke(obj, "hello", 100);
System.out.println(s);

//4 、获取单个方法【private,无参数,无返回值】,private void function()
Method method4 = clazz.getDeclaredMethod("function");
method4.setAccessible(true);
method4.invoke(obj);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java
相关文章推荐