1.Class类(字节码文件)
1.1.概念理解
Java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例对象来确定的,不同的实例对象有不同的属性值。Java程序中的各个Java类,它们是否属于同一类事物,所以可以用一个类来描述这类事物,这个类的名字就是Class,要注意与小写class关键字的区别。
Class类描述了哪些方面的信息:
类的名字,类的访问属性,类所属于的包名,字段名称的列表、方法名称的列表,等等。学习反射,首先就要明白Class这个类。
写如下代码进行对比理解:
每个java类都是Class的一个实例对象,它们的内容不同,但是,它们的特征相同,譬如,都有方法,有字段,有父类,有包。
每个java类都是Class的一个实例对象,它们的内容不同,但是,它们的特征相同,譬如,都有方法,有字段,有父类,有包。
1.2.Class类获得方法
类名.class
对象名.getClass();
Class.forName(类名);
这三种方法,最常用的为第二种,第三种.第三种在后期可以通过配置文件读取,所以更为常用.第一中在反射方法的参数类型中常使用.
1.3.注意问题
加载了字节码,并调用了其getMethods之类的方法,但是没有看到类的静态代码块被执行,只有在第一个实例对象被创建时,这个静态代码才会被执行。所以准确的说,静态代码块不是在类加载时被调用的,而是第一个实例对象时加载字节码被创建时才执行的。
1.4.Class类方法
Class类
2.反射
2.1.概念理解
反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后可以通过将对象,参数作为该反射出来对象的参数,进行正向操作.
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后可以通过将对象,参数作为该反射出来对象的参数,进行正向操作.
2.2.构造.成员.方法的对应封装类
Constructor类:构造
得到某个类所有的构造方法:例子:Constructor [] constructors= Class.forName("java.lang.String").getConstructors();
得到某一个构造方法:
例子: Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
//获得方法时要用到类型
创建实例对象:
通常方式:String str = new String(new StringBuffer("abc"));
反射方式: String str = (String)constructor.newInstance(new StringBuffer("abc"));
//调用获得的方法时要用到上面相同类型的实例对象
Class.newInstance()方法:
例子:String obj = (String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象。
Filed类:成员变量
问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?所以字段fieldX 代表的是x的定义(或者说声明),而不是具体的x变量。所以,反射出的东西的操作,必须依托一个对象来体现.
示例代码:ReflectPoint point = new ReflectPoint(1,7);
Field y = Class.forName("cn.itcast.corejava.ReflectPoint").getField("y");
System.out.println(y.get(point));
//Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getField("x");
Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x");
x.setAccessible(true);
System.out.println(x.get(point));
Method类:成员方法
得到类中的某一个方法:
例子: Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式: System.out.println(charAt.invoke(str, 1));
如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法!
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方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, new Object[]{1})形式。
例子: Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式: System.out.println(charAt.invoke(str, 1));
如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法!
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方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, new Object[]{1})形式。
4.数组的反射
3.反射----内省----JavaBean
3.1.概念
JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。
如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问,大家觉得这些方法的名称叫什么好呢?JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。如果方法名为setId,中文意思即为设置id,至于你把它存到哪个变量上,用管吗?如果方法名为getId,中文意思即为获取id,至于你从哪个变量上取,用管吗?去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的(就代表是定义get,set方法是将首字母大写了),则把剩余部分的首字母改成小的。
如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问,大家觉得这些方法的名称叫什么好呢?JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。如果方法名为setId,中文意思即为设置id,至于你把它存到哪个变量上,用管吗?如果方法名为getId,中文意思即为获取id,至于你从哪个变量上取,用管吗?去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的(就代表是定义get,set方法是将首字母大写了),则把剩余部分的首字母改成小的。
3.2.涉及到的几个类和接口
Introspector:
The Introspector class provides a standard way for tools to learn about the properties, events, and methods supported by a target Java Bean.
(我理解他就像一个静态方法库一样的概念,给想要运用内省操作的其他类或者接口等提供静态方法支持)
MethodDescriptor:
A MethodDescriptor describes a particular method that a Java Bean supports for external access from other components.
(我理解就是,一个该类的实例对象,就是封装某些信息,描述某些个符合JavaBean规则的类的某个成员属性的赋值获取等方法的信息)
PropertyDescriptor:(目前不知道MethodDescriptor什么用,有空上网研究下)
A PropertyDescriptor describes one property that a Java Bean exports via a pair of accessor methods.
(我的理解就是,一个该类的实例对象,就是疯涨了描述一个符合JavaBean规则的类的某个成员属性的信息)
BeanInfo:
A bean implementor who wishes to provide explicit information about their bean may provide a BeanInfo class that implements this BeanInfo interface and provides explicit information about the methods, properties, events, etc, of their bean.
(这个就是每个实例就是封装了所有的跟某个成员属性相关的变量声明,方法(赋值,获取方法),等.每个BeanInfo应该对应一对存储器,一个PropertyDescriptor,一个MethodDescriptor.)
他们之间的关系:
我们可以通过对一个类,调用Introspector中的静态方法,获得他类中所有的BeanInfo(返回值理所当然是个数组.).
在通过BeanInfo方法,可以选择性的拿到PropertyDescriptor.
然后再通过PropertyDescriptor中的方法,可以执行对该属性的赋值.或者了解各种信息.
(下面第二个代码用的就是这写步骤)
3.3.代码
/*
需求:
学习内省,JavaBean的使用
*/
import java.beans.*;
import java.lang.reflect.*;
class Student{
private String name;
private int age;
// public void setName(String name){
// this.name=name;
// }
public void setAge(int age){
this.age = age;
}
// public String getName(){
// return name;
// }
public int getAge(){
return age;
}
}
class JavaBeanDemo{
public static void main(String[] args)throws Exception{
Student s1 = new Student();
//JavaBean的内省方式设置属性值.
// Student s1 = new Student();
// String propertyName = "name";
// PropertyDescriptor pd = new PropertyDescriptor(propertyName,s1.getClass());
// Method methodSetName = pd.getWriteMethod();
// Method methodGetName = pd.getReadMethod();
// methodSetName.invoke(s1,"高富帅");
// System.out.println(methodGetName.invoke(s1));
//反射方式设置属性值.
Class studentClass = Class.forName("Student");
Field name = studentClass.getDeclaredField("name");
name.setAccessible(true);
name.set(s1,"屌丝");
// System.out.println(s1.getName());
System.out.println(name.get(s1));
}
}
package com.back.han;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
/**
* 存在一个JavaBean,它包含以下几种可能的属性: 1:boolean/Boolean 2:int/Integer 3:String
* 4:double/Double 属性名未知,现在要给这些属性设置默认值,以下是要求的默认值: String类型的默认值为字符串
* www.itheima.com int/Integer类型的默认值为100 boolean/Boolean类型的默认值为true
* double/Double的默认值为0.01D.
* 只需要设置带有getXxx/isXxx/setXxx方法的属性,非JavaBean属性不设置,请用代码实现
*
*/
public class Test6 {
public static void main(String[] args) {
try {
Bean bean = new Bean();
init(bean);
System.out.println(bean);
} catch (Exception e) {
e.printStackTrace();
}
}
private static Bean init(Bean bean) throws Exception {
// TODO Auto-generated method stub
BeanInfo bi = Introspector.getBeanInfo(bean.getClass());
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
Method rm = pd.getWriteMethod();
if (String.class == pd.getPropertyType()) {
rm.invoke(bean, "www.itheima.com");
} else if (int.class == pd.getPropertyType()) {
rm.invoke(bean, 100);
} else if (boolean.class == pd.getPropertyType()) {
rm.invoke(bean, true);
} else if (double.class == pd.getPropertyType()) {
rm.invoke(bean, 0.01d);
}
}
return bean;
}
}
class Bean {
String company;
int number;
boolean good;
double cash;
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public boolean isGood() {
return good;
}
public void setGood(boolean good) {
this.good = good;
}
public double getCash() {
return cash;
}
public void setCash(double cash) {
this.cash = cash;
}
@Override
public String toString() {
return "Bean [company=" + company + ", number=" + number + ", good="
+ good + ", cash=" + cash + "]";
}
}