反射机制就是可以把一个类,类的成员(函数,属性),当成一个对象来操作,也就是说,类,类的成员,我们在运行的时候还可以动态地去操作他们.
获得class对象
每个Class被JVM加载后,系统就会为该类生成一个对应的Class对象,通过该Class就可以访问到JVM中的这个类.(这里注意该类可能只是被加载进了内存的方法区,并不一定进行了初始化,关于JVM加载类的知识请自行补充)Java程序中获得Class的对象通常有如下三种方式:
- 使用Class类的静态方法,该方法需要传入完整的包路径名
- 调用某个类的class属性来获取该类对应的Class对象.例如Person.class将会返回Person类对应的Class对象.
- 调用某个对象的getClass()方法,该方法是Object中的一个方法,所以任何类都可以调用.
从Class中获取信息
Class类提供了大量的实例方法来获取Class对象所对应类的详细信息,大概分为
- Method
- Connstructor
- Field
- Annotation
interface,内部类,父类等几乎所有的东西.由于具体的内容太多,无法一一列出,所以这里只进行一些演示,具体的使用可以查看Class类.
1.首先编写我们要使用的Fruit类
public class Fruit {
private String name;
private int weight;
public Fruit() {
}
public Fruit(String name, int weight) {
this.name = name;
this.weight = weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
2.定义一个接口
public interface IColor {
public void sayShape(String asker);
}
3.编写一个继承Fruit和IColor接口的类
public class Apple extends Fruit implements IColor{
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
private String color;
@Override
public void sayShape(String asker) {
System.out.println("嗨,"+asker+",我是圆形的!");
}
}
接下来进行演示:
- 通过反射机制得到类的包名和类名
public class TestDemo {
public static void main(String[] args) {
Fruit fruit = new Fruit();
System.out.println("包名:" + fruit.getClass().getPackage().getName());
System.out.println("完整类名:" + fruit.getClass().getName());
}
}
运行结果
包名:com.company.eric.ReflectDemo
完整类名:com.company.eric.ReflectDemo.Fruit
- 验证所有类都是Class类的实例
public class TestDemo {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> class1 = null;
Class<?> class2 = null;
class1 = Class.forName("com.company.eric.ReflectDemo.TestDemo");
System.out.println("包名:" + class1.getClass().getPackage().getName());
System.out.println("完整类名:" + class1.getClass().getName());
class2 = Fruit.class;
System.out.println("包名:" + class2.getClass().getPackage().getName());
System.out.println("完整类名:" + class2.getClass().getName());
}
}
输出结果
包名:java.lang
完整类名:java.lang.Class
包名:java.lang
完整类名:java.lang.Class
- 通过Java反射,使用Class创建对象
public class TestDemo {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class cs = Class.forName("com.company.eric.ReflectDemo.Fruit");
//这里的newInstance使用的时候要保证你的类有无参构造函数
Fruit fruit = (Fruit) cs.newInstance();
fruit.setName("Apple");
fruit.setWeight(5);
System.out.println("name:" + fruit.getName());
System.out.println("weight:" + fruit.getWeight());
}
}
输出结果:
name:Apple
weight:5
- 通过Java反射机制得到一个类的构造函数,并实现创建带参实例对象
public class TestDemo {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class cs = Class.forName("com.company.eric.ReflectDemo.Fruit");
//获取指定的可访问构造器
Constructor constructor = cs.getConstructor(String.class, int.class);
Fruit fruit = (Fruit) constructor.newInstance("Apple", 5);
System.out.println("name:" + fruit.getName());
System.out.println("weight:" + fruit.getWeight());
System.out.println("--------------------");
//获取所有的构造器,包括私有的
Constructor[] constructors = cs.getDeclaredConstructors();
Fruit apple = (Fruit) constructors[0].newInstance();
apple.setName("Eric");
apple.setWeight(10);
System.out.println("name:" + apple.getName());
System.out.println("weight:" + apple.getWeight());
}
}
运行结果
name:Apple
weight:5
--------------------
name:Eric
weight:10
- 通过Java反射获取变量,即使是private也可以,set,get(有点黑科技的感觉)
public class TestDemo {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class cs = Class.forName("com.company.eric.ReflectDemo.Fruit");
Fruit fruit = (Fruit) cs.newInstance();
Field field = cs.getDeclaredField("name");
field.setAccessible(true);
field.set(fruit, "apple");
System.out.println("name:" + fruit.getName());
Object obj = cs.newInstance();
Field field1 = cs.getDeclaredField("weight");
field1.setAccessible(true);
field1.setInt(obj, 10);
System.out.println("name:" + field1.get(obj));
}
}
输出结果
name:apple
name:10
- 通过Java反射机制得到类的一些属性: 继承的接口,父类,函数信息,成员信息,类型等
public class TestDemo {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class cs = Class.forName("com.company.eric.ReflectDemo.Apple");
//取得父类名
Class<?> supreClass=cs.getSuperclass();
System.out.println("父类名: "+supreClass.getName());
System.out.println();
System.out.println("------------------------------------------");
System.out.println();
//取得成员变量
Field []fields=cs.getDeclaredFields();
for (Field field:fields) {
System.out.println("类中的成员: "+field.getName());
}
System.out.println();
System.out.println("------------------------------------------");
System.out.println();
//取得类方法
Method []methods=cs.getDeclaredMethods();
for (Method m :methods) {
System.out.println("取得类的方法");
System.out.println("函数名 "+m.getName());
System.out.println("函数返回类型 "+m.getReturnType());
System.out.println("函数访问修饰符 "+ Modifier.toString(m.getModifiers()));
System.out.println("函数代码写法 "+m);
System.out.println();
}
System.out.println();
System.out.println("------------------------------------------");
System.out.println();
//类实现的接口,接口类也属于Class
Class []interfaces=cs.getInterfaces();
for (Class<?> c:interfaces) {
System.out.println("类实现的接口 "+c.getName());
}
}
}
输出结果
父类名: com.company.eric.ReflectDemo.Fruit
------------------------------------------
类中的成员: color
------------------------------------------
取得类的方法
函数名 getColor
函数返回类型 class java.lang.String
函数访问修饰符 public
函数代码写法 public java.lang.String com.company.eric.ReflectDemo.Apple.getColor()
取得类的方法
函数名 setColor
函数返回类型 void
函数访问修饰符 public
函数代码写法 public void com.company.eric.ReflectDemo.Apple.setColor(java.lang.String)
取得类的方法
函数名 sayShape
函数返回类型 void
函数访问修饰符 public
函数代码写法 public void com.company.eric.ReflectDemo.Apple.sayShape(java.lang.String)
------------------------------------------
类实现的接口 com.company.eric.ReflectDemo.IColor
- 通过Java反射机制调用类方法
public class TestDemo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class cs = Class.forName("com.company.eric.ReflectDemo.Apple");
Method method = cs.getDeclaredMethod("sayShape", String.class);
Apple apple = (Apple) cs.newInstance();
method.invoke(apple, "Eric");
}
}
输出结果
嗨,Eric,我是圆形的!
- 通过Java反射机制获得类加载器(默认的加载器是AppClassLoader,有关类加载器的知识不在这里赘述)
public class TestDemo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class cs = Class.forName("com.company.eric.ReflectDemo.Apple");
ClassLoader classLoader=cs.getClassLoader();
System.out.println(classLoader.getClass().getName());
}
}
输出结果
sun.misc.Launcher$AppClassLoader
以上演示了一些常用的方法,更多的用法请查看各个类的具体api,尤其是Class这个类.