1.取得Class类对象的三种方式
public class Test{
public static void main(String[] args) {
try{
Class clazz1 = String.class;
Class clazz2 = "String".getClass();
Class clazz3 = Class.forName("java.lang.String");//这里写成了"java.lang.string" String类的S是大写的,要注意
}catch(ClassNotFoundException e){
e.printStackTrace();
}
}
}
写错的地方:
(1) forName方法throws ClassNotFoundException
(2) "java.lang.String"写成"java.lang.string" ,String类的S是大写的
2.预定义的九种Class对象(8种数据类型+void)
public class Test {
public static void main(String[] args) {
sop(int.class == Integer.class); // false
sop(float.class == Float.class); // false
sop(int[].class.isPrimitive()); // false
int a = 3;
sop(int.class == Integer.TYPE); // true
// Integer.TYPE → public static final Class<Integer> TYPE = (Class<Integer>)Class.getPrimitiveClass("int");
}
public static void sop(Object obj) {
System.out.println(obj);
}
}
注意的地方:
(1) 【背单词】isPrimitive() 判定指定的 Class 对象是否表示一个基本类型
(2) 是 “Integer.TYPE” 而不是 "Integer.Type" ,TYPE四个字母都是大写的
(3) 注意 “int.class == Integer.class”为false ( int和Integer虽然是基本类型与包装类的关系,
但它俩的.class是Class类的两个不同实例对象 )
(4) “Integer.TYPE” 其实就是Class的getPrimitiveClass方法得到的全局常量
(5) int.getClass()会出错 ,因为getClass()是Object类的方法,因此基本数据类型不能用getClass()方法
3.Mehod类的基本印象
import java.lang.reflect.*; //注意这里
public class Test{
public static void main(String[] args){
try{
Method string_CharAt = "abc".getClass().getMethod("charAt",int.class); //注意这里
char a = (char)string_CharAt.invoke("abc",2); //注意这里
System.out.println(a);
}catch(NoSuchMethodException e){
e.printStackTrace();
}catch(InvocationTargetException e){ //注意这里
e.printStackTrace();
}catch(IllegalAccessException e){ //注意这里
e.printStackTrace();
}
}
}
注意的地方:
(1) 要引入反射的包,并且不是 "import java.reflect.*" ,而是"import java.lang.reflect.*"
(2) getMethod(String name, Class<?>... parameterTypes) ,getMehod方法的第一个参数是String对象,第二个是Class对象
(3) 抛出的异常:getMehod抛NoSuchMethodException ,invoke抛IllegalAccessException和InvocationTargetException
注意IllegalAccessException是"爱ll"不是"爱爱爱"开头,是"InvocationTargetException"而不是"InvocationException"
(4) invoke方法的返回值是Object类型,要强制转换
4.Field类的基本印象 与 暴力反射
import java.lang.reflect.*;
public class Test{
public static void main(String[] args){
try{
Person p = new Person("Tom",12);
Field field_Name = p.getClass().getField("name");
Field field_Age = p.getClass().getDeclaredField("age");
field_Name.set(p,"Jimmy");
field_Age.setAccessible(true);
field_Age.set(p,13);
System.out.println(p.name+" - "+p.getAge());
}catch(NoSuchFieldException e){
e.printStackTrace();
}catch(IllegalAccessException e){
e.printStackTrace();
}
}
}
class Person{
public String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
public int getAge(){
return this.age;
}
}
注意的地方:
(1) getField的参数是String类型,抛NoSuchFieldException
(2) Field对象的set方法参数是(Object obj, Object value)
(3) 【背单词】 getDeclaredField 、setAccessible
5.Constructor类的基本印象
import java.lang.reflect.*;
public class Test {
public static void main(String[] args) {
try {
Constructor constructor_Person = Person.class.getConstructor(String.class, int.class);
Person p = (Person) constructor_Person.newInstance("Tom", 12);
System.out.println(p.name + " - " + p.getAge());
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
class Person {
public String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return this.age;
}
}
注意的地方:
(1) 【背单词】Constructor ,是"newInstance"而不是"newInstace"
(2) newInstance(Object... initargs)的返回值也是Object,要转换
(3) newInstance会抛出InstantiationException
6.小练习
import java.lang.reflect.*;
import java.util.*;
//题目:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的“b”改为“a”
public class Test {
public static void main(String[] args) throws IllegalArgumentException,
IllegalAccessException {
Person p = new Person("abcabc", "b", 12);
Field[] fieldsOfPerson = Person.class.getDeclaredFields(); //注意这里
for (Field f : fieldsOfPerson) {
f.setAccessible(true);
if (f.getType() == String.class) { //注意这里
String oldValue = (String) f.get(p);
String newValue = oldValue.replace('b', 'a');
f.set(p, newValue);
}
}
System.out.println(p);
}
}
class Person {
public String name;
private String className;
private int age;
public Person(String name, String className, int age) {
this.name = name;
this.className = className;
this.age = age;
}
public String getName() {
return this.name;
}
@Override
public String toString() {
return this.name + " - " + this.className + " - " + this.age;
}
}
注意的地方:
判断成员变量类型不是 if(f instanceof String)也不是 if(f.getClass()==String.class),
而是if (f.getType() == String.class)!
7.数组的反射
import java.lang.reflect.*;
public class Test {
public static void main(String[] args) {
int[] i = { 1, 2, 3 };
System.out.println(Array.getLength(i));
}
}
java.lang.reflect.Array用于完成对数组的反射操作。
8.关于反射抛的异常
刚开始没有借助Eclipse这样的软件,完全自己写try……catch,
真的没想到反射的程序居然需要捕抓这么多异常。
成员变量、成员方法、构造方法的程序,每次后面都跟着两到四个异常,
不过多写几次,就发现其中其实有规律可循。
例如反射取成员,有可能根本没有这个成员,因此就有NoSuchMethodException和NoSuchFieldException,
有例如反射使用成员方法和构造方法,有可能调用出错,或者访问权限不足,就有了 IllegalAccessException和 InvocationTargetException等等。
每次使用这些方法的时候思考一下,再多写几次,就能避免没有捕抓某个异常的情况了。