反射:
反射就是把Java类中的各种成分映射成相应的java类。
例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。
1、反射主要用于工具的开发。所有的重要Java技术底层都会用到反射。反射是一个底层技术。
是在运行时动态分析或使用一个类的工具(是一个能够分析类能力的程序)
2、反射使我们能够在运行时决定对象的生成和对象的调用。
在反射中凡是有类型的东西,全部用类对象来表示。
java.lang.reflect .Field 对象,描述属性信息。
java.lang.reflect .Constructor 描述构造方法信息。
java.lang.reflect .Method 描述方法信息。
获得类对象的3种方式:
1,Class clazz= String.class; //通过类名获得类对象 .
2, Class clazz = s.getClass(); //类对象.getClass()通过对象获得类对象
3,Class clazz= Class.forName(“Java.lang.String”)//通过Class.forName(“类的全名”)来获得类对象; 这会强行加载类到内存里,前两种不加载 注:第三种方式是最常用最灵活的方式。第三种方式又叫强制类加载。
Constructor类代表某个类中的构造方法
//获取字节码文件
Class clazz=Class.forName("com.itheima.Person");
//该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
Person obj = (Person)clazz.newInstance();
//得到某个类所有的构造方法
Constructor [] constructors= Class.forName("com.itheima.Person").getConstructors();
//得到某一个带参数的构造方法
Constructor constructor = clazz.getConstructor(String.class);
//通过构造创建对象.
Person p = (Person) constructor.newInstance("zhangan");
//getConstructor只能获得public类型的构造函数,如果想好的private的构造函数需要用getDeclaredConstructor()私有的只有内部可以访问,但是反射可以setAccessible(true)暴力反射
Constructor constructor = clazz.getDeclaredConstructor(String.class);
//打开访问权限
constructor.setAccessible(true);
//再调用newInstance来初始化即可。
Person p = (Person)constructor.newInstance("lisi")
Method类:代表某个类中的一个方法
//clazz通过getMethod获取获取它的一个方法,第一个参数是方法名,第二个参数是参数类型的字节码
Method method = clazz.getMethod("show", int.class);
// 通过invoke方法调用某个对像的具体方法,第一个参数是指:调用对像,第二个参娄是指这个方法的参数
method.invoke(p,22);
//调用私有方法
Method m = cls.getDeclaredMethod("show",int.class);
//打开权限
m.setAccessible(true);
m.invoke(p,22);
//调用静态方法时,不需要不需要传入实际变量,静态方法可以直接调用。
Object o=m.invoke(null,"itheima.com";
Field类:类的成员变量
//通过字节码的getField方法来获取一个成员变量对应的对像
Field f = cls.getDeclaredField("age");
f.setAccessible(true);
//第一个参数是指给哪一个对像设置,第二个参数是指设置的值
f.set(p, 23);
//获取私有变量的值
System.out.println(f.get(p));
实例:将及字符a 换成b.
class Xxx
{
String name="abc";
String email="abd";
int x = 5;
}
func(Object obj)
{
Field [] fields = obj.getClass().getDeclaredFields();
for(Field field : fields)
{
if(field.getType()==java.lang.String.class)
{
field.setAccesible(true);
String original = (String)field.get(obj);
field.set(obj,original.replaceAll("b","a");
}
}
}
jdk1.4
和
jdk1.5
的
invoke
方法的区别:
Jdk1.5
:
public Object invoke(Object
obj,Object
...
args
)
Jdk1.4
:
public Object invoke(Object
obj,Object
[]
args
)
,即按
jdk1.4
的语法,需要将一个数组作为参数传递给
invoke
方法时,数组中的每个元素分别对应被调用方法中的一个参数.
数组的反射:
1,具有相同维数和元素类型的数组属于同一个类型,即具有相同的
Class
实例对象。
2,
代表数组的
Class
实例对象的
getSuperClass
()
方法返回的父类为
Object
类对应的
Class
。
3,基本类型的一维数组可以被当作
Object
类型使用,不能当作
Object[]
类型使用;非基本类型的一维数组,既可以当做
Object
类型使用,又可以当做
Object[]
类型使用。
内省
JavaBean
是一种特殊的
Java
类,主要用于传递数据信息,这种
java
类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。
如果要在两个模块之间传递多个信息,可以将这些信息封装到一个
JavaBean
中,这种
JavaBean
的实例对象通常称之为值对象(
Value Object
,简称
VO
)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问,
JavaBean
的属性是根据其中的
setter
和
getter
方法来确定的.
Sun
公司开发一套专门用于操作
JavaBean
属性的
API.
Java
属性是指必须拥有
setter/getter
方法的字段。
Java.beans.
PropertyDescriptor
是操作
JavaBean
属性的类。
反射与内省的区别:
反射可以操作各种不同的
java
类,那么内省只是通过反射操作
JavaBean
的
setter/getter
方法。
public class PropertyDemo {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.itheima.Person");
Object o = cls.newInstance();
//可通过内省进行操作了
PropertyDescriptor pd = new PropertyDescriptor("name",cls);
Method m = pd.getWriteMethod();
m.invoke(o,"Rose");
//操作一个不存在的属性,则会抛出一个异常
PropertyDescriptor pd = new PropertyDescriptor("age",cls);
Method m2 = pd.getWriteMethod();//setAge
m5.invoke(o,"999");
}
Beanutils是Apache开发的一套快速操作JavaBean getter/setter方法的API,
l
准备包:
•
commons-
beanutils.jar,commons
-
logging.jar
l
语法:
•设置:
•BeanUtils.setProperty(Object bean,StringpropertyName,StringpropertyValue);
•获取:
•BeanUtils.getProperty(Object bean,StringPropetyName);
public class BeanUtilsDemo {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.itheima.Person");
Object o = cls.newInstance();
//主要类:,使用它的静态方法
BeanUtils.setProperty(o,"name","张三");
String name = BeanUtils.getProperty(o,"name");
综合案例:
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
ReflectPoint pt1 = new ReflectPoint(3,5);
Object retVal = getProperty(pt1);
System.out.println(retVal);
PropertyDescriptor pd2 = null;
String propertyName = "y";
Object value = 7;
setProperty(pt1, propertyName, value);
//先通过调用普通java类的方法的方式获得结果,然后在这之前插入BeanUtil的get和set操作,见下面的代码。
//System.out.println(pt1.getY());
System.out.println(BeanUtils.getProperty(pt1, "y"));
BeanUtils.setProperty(pt1, "y", "99");
System.out.println(pt1.getY());
PropertyUtils.setProperty(pt1, "y", 999);
System.out.println(PropertyUtils.getProperty(pt1, "y").getClass().getName());
}
private static Object getProperty(ReflectPoint pt1) {
Object retVal = null;
PropertyDescriptor pd = null;
try {
pd = new PropertyDescriptor("y",pt1.getClass());
retVal = pd.getReadMethod().invoke(pt1);
} catch (Exception e) {
e.printStackTrace();
}
return retVal;
}
private static void setProperty(Object pt1, String propertyName,
Object value) {
/*PropertyDescriptor pd2;
try {
pd2 = new PropertyDescriptor(propertyName,pt1.getClass());
pd2.getWriteMethod().invoke(pt1,value);
} catch (Exception e) {
e.printStackTrace();
}*/
try {
BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for(PropertyDescriptor pd :pds){
if(pd.getName().equals(propertyName)){
pd.getWriteMethod().invoke(pt1,value);
break;
}
}
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IntrospectionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}