java反射i_Java反射

反射技术

其实就是动态加载一个指定的类,并获取该类中的所有的内容。

而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,它允许程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。

简单说:反射技术可以对一个类进行解剖。

反射的好处:大大的增强了程序的扩展性。

反射的基本步骤:

获得Class对象,就是获取到指定的名称的字节码文件对象。

实例化对象,获得类的属性、方法或构造函数。

访问属性、调用方法、调用构造函数创建对象。

类类型class Class

用于描述程序中的各个类属于同一类事物的Java类,它封装了类的很多信息。

查看JDK中的源码:

public final

class Class implements java.io.Serializable,

java.lang.reflect.GenericDeclaration,

java.lang.reflect.Type,

java.lang.reflect.AnnotatedElement {

private static final int ANNOTATION= 0x00002000;

private static final int ENUM = 0x00004000;

private static final int SYNTHETIC = 0x00001000;

private static native void registerNatives();

static {

registerNatives();

}

/*

* Constructor. Only the Java Virtual Machine creates Class

* objects.

*/

private Class() {}

发现:Class类有构造器,并且它的构造方法是private的(可能是为了禁止开发者去自己创建Class类的实例)。

看到注释我们知道,这个类是JVM来创建的。如果我们拿到一个类的类型信息,就可以利用反射获取其各种成员以及方法了。

那么我们怎么拿到一个类的信息呢?【获取Class对象可以有3种方式】

如果没有对象实例的时候,主要有两种办法可以获取类类型:

Class cls1 = Show.class;//每一个数据类型(基本数据类型和引用数据类型)都有一个静态的属性class。弊端:必须要先明确该类。

Class cls2 = Class.forName("Show");//【推荐这种方法】这种方式的扩展性最强,只要将类名的字符串传入即可。如果类是在某个包中,要带上包名。

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

Class cls1 = Show.class;

Object obj1 = cls1.newInstance();

System.out.println(obj1);

Class> cls2 = Class.forName("Show");

Object obj2 = cls2.newInstance();

System.out.println(obj2);

}

这样就创建了一个对象,缺点是:

第一,我们只能利用默认构造函数,因为Class的newInstance是不接受参数的;

第二,如果类的构造函数是private的,比如Class,我们仍旧不能实例化其对象。

如果有对象实例的话,除了上面的两种方法来获取类的信息外,还有第三种方法:对象.getClass()。弊端:必须要创建该类对象,才可以调用getClass方法。

反射就是把Java类中的各种成分映射成相应的Java类:

例如,一个Java类用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示【就像汽车是一个类,汽车中的发动机,变速箱也是一个个的类】。表示Java类的Class类中提供了一系列的方法来获取其中的变量(Field),方法(Method),构造方法(Contructor),修饰符(Modifiers),包(Package)等信息。

反射的用法

1.需要获得java类的各个组成部分,首先需要获得类的Class对象,获得Class对象的三种方式:

Class.forName(classname) 用于做类加载

obj.getClass() 用于获得对象的类型

类名.class     用于获得指定的类型,传参用

2.反射类的成员方法:

public Method getMethod(String name,Class>... parameterTypes)//返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。

public Method[] getMethods()//返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口的公共 member 方法。

3.反射类的构造函数:

public Constructor>[] getConstructors()      返回类中所有的public构造器集合,默认构造器的下标为0

public Constructor getConstructor(Class>... parameterTypes)   返回指定public构造器,参数为构造器参数类型集合

public Constructor>[] getDeclaredConstructors()  返回类中所有的构造器,包括私有

public Constructor getDeclaredConstructor(Class>... parameterTypes) 返回任意指定的构造器

发现带上Declared的都是获得所有的构造方法,包括私有,这下我们就可以调用原本不允许调用的私有构造器了^_^

eg:Class cls1 = Show.class;

// 获取所有的构造方法集合

Constructor[] con1 = cls1.getDeclaredConstructors();

con1[1].setAccessible(true);// 设置可访问的权限

Object obj1 = con1[1].newInstance(new Object[] { "adanac" });

System.out.println(obj1);

// 指定参数列表获取特定的方法

Constructor con = cls1.getDeclaredConstructor(new Class[] { String.class });

con.setAccessible(true);

Object obj2 = con.newInstance(new Object[] { "lfz" });

System.out.println(obj2);

4.获取类的成员变量:

public Field getDeclaredField(String name)  获取任意指定名字的成员

public Field[] getDeclaredFields()             获取所有的成员变量

public Field getField(String name)           获取任意public成员变量

public Field[] getFields()                          获取所有的public成员变量

Class cls1 = Show.class;

// 获取所有的构造方法集合

Constructor[] con1 = cls1.getDeclaredConstructors();

con1[1].setAccessible(true);// 设置可访问的权限

Object obj1 = con1[1].newInstance(new Object[] { "adanac" });

Field nameField = cls1.getDeclaredField("name");

nameField.setAccessible(true);

System.out.println(nameField.get(obj1));// 打印结果:adanac

现在私有变量也可以访问到了哈~~

获取了字节码文件对象后,最终都需要创建指定类的对象,创建对象的两种方式(其实就是对象在进行实例化时的初始化方式):

调用空参数的构造函数:使用了Class类中的newInstance()方法。

调用带参数的构造函数:先要获取指定参数列表的构造函数对象,然后通过该构造函数的对象的newInstance(实际参数) 进行对象的初始化。

注意:第二种方式必须要先明确具体的构造函数的参数类型,不便于扩展。所以一般情况下,被反射的类,内部通常都会提供一个公有的空参数的构造函数。

Object obj = clazz.newInstance();//该实例化对象的方法调用就是指定类中的空参数构造函数,给创建对象进行初始化。

当指定类中没有空参数构造函数时,该如何创建该类对象呢?

Class> clazz = Class.forName("heimablog.Person");

// 既然类中没有空参数的构造函数,那么只有获取指定参数的构造函数,用该函数来进行实例化。

// 获取一个带参数的构造器。

Constructor> constructor = clazz.getConstructor(String.class, int.class);

// 想要对对象进行初始化,使用构造器的方法newInstance();

Object obj = constructor.newInstance("zhagnsan", 30);

// 获取所有构造器。

Constructor[] constructors = clazz.getConstructors();// 只包含公共的

constructors = clazz.getDeclaredConstructors();// 包含私有的

for (Constructor> con : constructors) {

System.out.println(con);

}

【案例】

通过class取得一个类的全部框架:

package heimablog;

import java.lang.reflect.Field;

import java.lang.reflect.Modifier;

class hello {

public static void main(String[] args) {

Class> demo = null;

try {

demo = Class.forName("heimablog.Person");

} catch (Exception e) {

e.printStackTrace();

}

System.out.println("===============本类属性========================");

// 取得本类的全部属性

Field[] field = demo.getDeclaredFields();

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

// 权限修饰符

int mo = field[i].getModifiers();//返回此类或接口以整数编码的 Java 语言修饰符。

String priv = Modifier.toString(mo);

// 属性类型

Class> type = field[i].getType();

System.out.println(priv + " " + type.getName() + " "

+ field[i].getName() + ";");

}

System.out.println("===============实现的接口或者父类的属性========================");

// 取得实现的接口或者父类的属性

Field[] filed1 = demo.getFields();

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

// 权限修饰符

int mo = filed1[j].getModifiers();

String priv = Modifier.toString(mo);

// 属性类型

Class> type = filed1[j].getType();

System.out.println(priv + " " + type.getName() + " "

+ filed1[j].getName() + ";");

}

}

}

通过反射操作属性:

package heimablog;

import java.lang.reflect.Field;

class hello {

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

Class> cls1 = Class.forName("heimablog.Person");

Object object = cls1.newInstance();

Field field = cls1.getDeclaredField("name");

field.setAccessible(true);

field.set(object, "男");

System.out.println(field.get(object));//打印结果:男

}

}

通过反射取得并修改数组的信息:

package heimablog;

import java.lang.reflect.Array;

class hello {

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

int[] temp={1,2,3,4,5};

Class>demo=temp.getClass().getComponentType();

System.out.println("数组类型: "+demo.getName());

System.out.println("数组长度 "+Array.getLength(temp));

System.out.println("数组的第一个元素: "+Array.get(temp, 0));

Array.set(temp, 0, 100);

System.out.println("修改之后数组第一个元素为: "+Array.get(temp, 0));

}

}

/**

* 数组类型: int

*数组长度 5

*数组的第一个元素: 1

*修改之后数组第一个元素为: 100

*/

通过反射修改数组大小:

package heimablog;

import java.lang.reflect.Array;

class hello{

public static void main(String[] args) {

int[] temp={1,2,3,4,5,6,7,8,9};

int[] newTemp=(int[])arrayInc(temp,12);

print(newTemp);

System.out.println("^^^^^");

String[] atr={"a","b","c"};

String[] str1=(String[])arrayInc(atr,5);

print(str1);

}

/**

* 修改数组大小

* */

public static Object arrayInc(Object obj,int len){

Class>arr=obj.getClass().getComponentType();

Object newArr=Array.newInstance(arr, len);

int co=Array.getLength(obj);

System.arraycopy(obj, 0, newArr, 0, co);

return newArr;

}

/**

* 打印

* */

public static void print(Object obj){

Class>c=obj.getClass();

if(!c.isArray()){

return;

}

System.out.println("数组长度为: "+Array.getLength(obj));

for (int i = 0; i < Array.getLength(obj); i++) {

System.out.print(Array.get(obj, i)+" ");

}

}

}

/**

*数组长度为: 10

*1 2 3 4 5 6 7 8 9 0 ^^^^^

*数组长度为: 5

*a b c null null

*/

获得类加载器:

package heimablog;

class test{

}

class hello{

public static void main(String[] args) {

test t=new test();

System.out.println("类加载器 "+t.getClass().getClassLoader().getClass().getName());

}

}

//类加载器 sun.misc.Launcher$AppClassLoader

反射小例子:

package heimablog;

import java.lang.reflect.Field;

import java.lang.reflect.Modifier;

import java.sql.Timestamp;

import java.util.Calendar;

public class ClassTest {

public static void main(String[] args) {

Calendar birthday = Calendar.getInstance();

birthday.set(1966, 9, 11, 0, 0, 0);

Student s1 = new Student("007", "Jack Brawer", true, new Timestamp(

birthday.getTimeInMillis()), 1.80);

ClassInfo classInfo = new ClassInfo();

System.out.println(classInfo.getClassInfo(s1));

}

}

// 该类可以获取任何类的元数据信息

class ClassInfo {

public String getClassInfo(Object obj) {

StringBuffer result = new StringBuffer();

// 得到参数类变量的Class引用变量

Class cls = obj.getClass();

// 得到参数类变量的属性信息

Field[] fields = cls.getDeclaredFields();

// 得到参数类变量的完整类名(含有包的名称)

String fullName = cls.getName();

// 得到去除包名称的类名

String className = fullName.substring(fullName.lastIndexOf('.') + 1);

// 如果有包的定义,可以得到包的名称

int packagePosition = fullName.lastIndexOf('.');

String packageName = null;

if (packagePosition < 0)

packageName = "";

else

packageName = fullName.substring(0, fullName.lastIndexOf('.'));

// 输出包名和类名

result.append("包的名称为:" + packageName + "\r\n");

result.append("类的名称为:" + className + "\r\n");

// 输出类中所有的属性信息

for (Field field : fields) {

// 允许访问私有成员

field.setAccessible(true);

try {

// 输出私有属性信息

if (field.getModifiers() == Modifier.PRIVATE)

result.append("私有属性" + field.getName() + ":值为"

+ field.get(obj) + "\n");

// 输出受保护属性信息

if (field.getModifiers() == Modifier.PROTECTED)

result.append("受保护属性" + field.getName() + ":值为"

+ field.get(obj) + "\n");

} catch (Exception e) {

System.out.println(e.getMessage());

}

}

return result.toString();

}

}

// 学生类

class Student {

// 学号

private String number = null;

// 姓名

private String name = null;

// 性别

private boolean sex = false;

// 生日

private Timestamp birthday = null;

// 身高

private double height = 0;

// 默认构造函数

public Student() {

}

// 该构造函数可以对学生的属性进行初始化

public Student(String number, String name, boolean sex, Timestamp birthday,

double height) {

setNumber(number);

setName(name);

setSex(sex);

setBirthday(birthday);

setHeight(height);

}

// 学号的读取函数

public String getNumber() {

return number;

}

// 学号的设置函数

public void setNumber(String number) {

this.number = number;

}

// 姓名的读取函数

public String getName() {

return name;

}

// 姓名的设置函数

public void setName(String name) {

this.name = name;

}

// 性别的读取函数

public boolean isSex() {

return sex;

}

// 性别的设置函数

public void setSex(boolean sex) {

this.sex = sex;

}

// 生日的读取函数

public Timestamp getBirthday() {

return birthday;

}

// 生日的设置函数

public void setBirthday(Timestamp birthday) {

this.birthday = birthday;

}

// 身高的读取函数

public double getHeight() {

return height;

}

// 身高的设置函数

public void setHeight(double height) {

this.height = height;

}

// 格式化字符信息输出

public String toString() {

return "学号:" + number + "/n姓名:" + name + "/n是否为男生:" + sex + "/n生日:"

+ birthday + "/n身高:" + height;

}

}

/*

包的名称为:heimablog

类的名称为:Student

私有属性number:值为007

私有属性name:值为Jack Brawer

私有属性sex:值为true

私有属性birthday:值为1966-10-11 00:00:00.267

私有属性height:值为1.8

*/

在java中有三种类类加载器:

Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。

Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类

AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值