1. Class类
Java程序中的各个类属于同一类事物,描述这类事物的Java类名就是Class。Class类代表各个类和接口在内存中的字节码,比如ArrayList类的字节码,一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的。
如何获得各个字节码对应的实例对象?
- 类名.class,例如,System.class
- 对象.getClass(),例如,new Date().getClass()
- Class.forName("类名"),例如,Class.forName("java.util.Date")
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<span style="white-space:pre"> </span>
2. 反射
反射就是把Java类中的各种成分映射成相应的java类。一个类中的组成部分:成员变量、方法、构造方法、包等等信息都可以用java类来表示,它们是Field、Method、Contructor、Package。
3.Constructor
3.1 获取某个类的所有构造方法:Constructor [] constructors = Class.forName("java.lang.String").getConstructors();
3.2 获取某一个构造方法
Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class); //这个StringBuffer表示选择哪个构造方法
3.3 创建实例对象
通常方式:String str = new String (new StringBuffer("abc"));
反射方式:String str = (String) constructor.newInstance(new StringBuffer("abc"));
String str = (String)Class.forName("java.lang.String").newInstance();
该方法内部会先得到默认的构造方法,然后用该构造方法创建实例对象。
问题:通过反射创建类的对象实例
public class MyTest {
public static void main(String[] args) throws Exception {
Class ret = Class.forName("StrObj");
StrObj strObj = (StrObj) ret.newInstance();
strObj.display();
}
}
class StrObj {
private String name = "Tom";
private int age = 12;
public StrObj() {
}
public StrObj(String name, int age) {
super();
this.name = name;
this.age = age;
}
public void display() {
System.out.println("StrObj [name=" + name + ", age=" + age + "]");
}
}
注意:如果StrObj没有空的构造方法,则程序报错。在利用反射创建对象的实例时,一定要写无参的构造方法。
4. Field
Field类代表某个类中的一个成员变量。Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而对象可以有多个,如果是与对象关联,那关联的是哪一个对象呢?所以Field代表的是类的成员变量,而不是具体对象的。
问题:将一个对象中所有String类型的成员变量所对应的字符串内容中的"b"改为"a"?
public class MyTest {
public static void main(String[] args) throws Exception {
StrObj strObj = new StrObj();
Class clazz = strObj.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
//处理String类型变量
if (field.getType() == String.class) {
if (!field.isAccessible()) {
//处理private成员变量
field.setAccessible(true);
}
String str = (String) field.get(strObj);
field.set(strObj, str.replaceAll("b", "a"));//替换字符
String newStr = (String) field.get(strObj);
System.out.println(newStr);
}
}
}
}
class StrObj {
private String name = "12abcb";
public String email = "aabbcc";
public int age = 11;
}
注意:
getFields()与getDeclaredFields()区别:getFields()只能访问类中声明为公有的字段,私有的字段它无法访问,能访问从其它类继承来的公有方法。getDeclaredFields()能访问类中所有的字段,与public,private,protect无关,不能访问从其它类继承来的方法。
5. Method
Method类代表某个类中的一个成员方法。
Method charAtMethod = Class.forName("java.lang.String").getMethod("charAt", int.class);
5.2 调用方法
通常方式:str.charAt(1)
反射方式:charAtMethod.invoke(str, 1)
如果传递给invoke()方法的第一个参数为null,说明给Method对象对应的是一个静态方法。
问题:利用反射调用一个类的静态方法?
Method m1 = Math.class.getMethod("abs", double.class);
m1.invoke(null, -2.3);