---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
1:什么是反射:反射的概念主要指类可以访问、检测和修改它本身状态或行为的一种能力,它能让java类自身进行检查,并能直接操作类的内部属性。
反射总结:就是把Java类中的所有成分反射成不同的java类
2:什么是反射机制:Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
反射的基石àClass类
1.所有的类文件都有共同属性,所以可以向上抽取,把这些共性内容封装成一个类,这个类就叫Class(描述字节码文件的对象)。
Class类中就包含属性有field(字段)、method(方法)、construction(构造函数)。
而field中有修饰符、类型、变量名等复杂的描述内容,因此也可以将字段封装称为一个对象。用来获取类中field的内容,这个对象的描述叫Field。同理方法和构造函数也被封装成对象Method、Constructor。要想对一个类进行内容的获取,必须要先获取该字节码文件的对象。该对象是Class类型。
Class类描述的信息:类的名字,类的访问属性,类所属于的包名,字段名称的列表,方法名称的列表等。每一个字节码就是class的实例对象。如:classcls=Data.class;
什么是字节码:
当源程序中用到类时,首先要从硬盘把这个类的那些二进制代码,一个类编译成class放在硬盘上以后,就是一些二进制代码,要把这些二进制代码加载到内存中里面来,再用这些字节码去复制出一个一个对象来。
2.Class和class的区别
1)class:Java中的类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由此类的实例对象确定,不同的实例对象有不同的属性值。
2)Class:指的是Java程序中的各个Java类是属于同一类事物,都是Java程序的类,这些类称为Class。例如人对应的是Person类,Java类对应的就是Class。Class是Java程序中各个Java类的总称;它是反射的基石,通过Class类来使用反射。
反射的作用(重点):
可以通过反射机制取得对象的类型
取得对象的方法、属性、构造器
可以创建对象并访问任意对象方法和属性
反射两个缺点:
性能问题。用于字段和方法介入时反射要远慢与直接的代码
使用反射会模糊程序内部实际要发生的事情,使程序对程序逻辑的可读性变差
得到字节码对象的方式有三种
(1)在源程序里直接写上类的名字.class 例:Person.class
(2)在通过对象调用getClass(),返回字节码 例:per.getClass()
(3)用Class类的静态方法去查询或加载字节码
例:Class.forName(“类名”)
PS:一般开发都用第三种,传入字符串即可得到类的字节码
问:以下得到的三个字节码是不是同一份?
String str1 = "abc";
Class cls1 = str1.getClass();
Class cls2 = String.class;
Class cls3 = Class.forName("java.lang.String");
System.out.println(cls1 == cls2);//输出true
System.out.println(cls1 == cls3); //输出true
面试提问:Class.forName(“类名”)的作用是什么?
回答:
有两个作用
1:如果该类的字节码曾经被加载过,那么直接返回该类的字节码:
2:如果该类还没有被加载进内存,那么此时就进行加载该类的字节码,缓存在内存中,并返回字节码对象
回答:得到的都是同一份字节码
isprimitive():判断一个类是不是一个基本类型的方法
isArray():判断一个类是不是数组类型的方法
代码:
String str1 = "abc";
Class cls1 = str1.getClass();
System.out.println(cls1.isPrimitive());//结果为false, 说明String不是基本类型
System.out.println(int.class.isPrimitive());//结果为true
System.out.println(int.class == Integer.class); //结果为true
System.out.println(int.class == Integer.TYPE); //结果为true
System.out.println(int[].class.isPrimitive());//结果为false
System.out.println(int[].class.isArray()); //结果为true
System.out.println(int.Class.isprimitive());//结果为true
总之,在源程序中出现的数据类型,都有各自对应的Class实例对象
九个预定义Class实例对象,即八个基本数据类型(boolean、byte、char、short、int、long、float和 double)和一个void类型的字节码对象。也就是说他们都有自己的Class对象,void的是void.class。
反射就是把Java类中的各个成分映射成相应的java类。而Class类提供了一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息。这些信息就是用相应的类的实例对象来表示的,他们是Field(变量或字段),Method(方法),Contructor(构造器),Package(包)等等
获取类中的方法
getDeclaredMethods():取得类中定义了的所有的方法列表
(包括private,public,protected、packed),但是不包括从父类中继承来的方法
使用:字节码对象.getDeclaredMethods(),返回值类型是Methods类型
getMethod(name,参数字节码):获取类的所有公有方法,包括从父类中继承来的方法,返回Method类型(这点是与getDeclaredMethods()的区别)
name为想取得的方法的名字,后面的参数的自己码为方法可能有多个重载形式,这里通过参数的字节码来识别
例:调用String类型的charAt()
String str = “abc”;
Method methodCharAt = str.getClass.getMethod(“charAt”,int.class);
System.out.println(methodCharAt.invoke(str,1));//传入要截取的字符串对象和要操作的下标
//输出是“b” ps: invoke()表示调用
如果invoke()中传入的对象是null,说明该方法对应的方法是静态方法,静态方法调用不需要对象
代码示例:
Method methodCharAt = String.class.getMethod("charAt", int.class);
System.out.println(methodCharAt.invoke(str1, 1));
System.out.println(methodCharAt.invoke(str1, new Object[]{2}));
//TestArguments.main(new String[]{"111","222","333"});
String startingClassName = args[0];
Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
//mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});
mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
获取类中的构造方法
getConstructor(A.class):取得类的构造方法(不能获取私有构造方法)
用法(字节码.getConstructor(A.class)),如果有多个构造方法,传入构造方法的所接收的类字节码,返回值类型是Constructor类型
getDeclaredConstructors():取得类中的所有构造方法(无论是私有还是公有)
用法(字节码.getDeclaredConstructors()),返回值类型是Constructor数组
PS:通过getDeclaredConstructors()获取私有的构造方法,可以突破单例模式不能创建对象的限制,由外部创建对象
代码示例:
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
String str2 = (String)constructor1.newInstance(/*"abc"*/new StringBuffer("abc"));
System.out.println(str2.charAt(2));
例:得到String的构造方法 :String.class.getConstructor()
String有不止一个构造方法,要得到哪一个构造方法,如何指定?
在getConstructor()中传入参数,传入的参数同样为字节码,想得到的构造方法有几个对象就传几个字节码文件
如:String.class.getConstructor(StringBuffer.class)//这个就是得到参数为类型为StringBuffer.的构造方法
获取方法的参数类型
Type[] getGenericParameterTypes():按照声明顺序返回Type对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型的。如果底层方法不带参数,则返回长度为 0的数组。
用法:Type[] types = method. getGenericParameterTypes();
Field:类中的成员变量
取得某个类的某个成员变量:getFields(“name”),传入的name是成员的名字,但这种只能得到公有的成员,私有的不行(得到的只是变量,但是并不是得到变量的值,要得到变量的值要得到该变量后,再通过get(指定对象)包括父类中的定义的成员
要修改值用set(指定对象)
获取类中的成员变量
per.class.getFields(“age”),这样就得到了Person这个类的成员变量age,并不是得到age的值
getDeclaredField():也是得到成员变量,与getFields(“name”)的区别在于:无论公有私有都可以得到,不受权限的控制
代码:
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class ReflectTest {
public static void main(String[] args) throws Exception {
ReflectPoint pt1 = new ReflectPoint(3,5);
Field fieldY = pt1.getClass().getField("y");
//fieldY的值是多少?是5,错!fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值
System.out.println(fieldY.get(pt1));
Field fieldX = pt1.getClass().getDeclaredField("x");
fieldX.setAccessible(true);
System.out.println(fieldX.get(pt1));
changeStringValue(pt1);
System.out.println(pt1);
}
public class ReflectPoint {
private Date birthday = new Date();
private int x;
public int y;
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "itcast";
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final ReflectPoint other = (ReflectPoint) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
@Override
public String toString(){
return str1 + ":" + str2 + ":" + str3;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
练习(重点):得到一个类中的String类型的成员变量,并把成员变量的值中的a用e来替换
private static void changeValue(Object obj)
{//注释为思路与步骤
Field[] field = objgetClass.getFields();//得到所有的成员变量的数组
For(Field field: Field)//遍历该数组,取出成员变量
{
if(field.getType()==String.class)//判断取出的成员变量是否是String类型的
{
String oldValue = field.get(obj);//取出obj该对象的String成员变量的值
String newValue = oldValue.replace(“a”,”e”);//替换字母后返回一个新的字符串
field.set(obj,newValue);//设置obj对象的String成员变量的新值
}
}
}
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net