1、反射的定义
Java语言中一种动态(运行时)访问、检测、修改它本身的能力。可以动态的获取类的完整结构信息,调用对象的方法。
适用地方
Java中的两种类型:编译时类型、运行时类型。
// Person为p的编译时类型,Student为p的运行时类型
Person p = new Student();
在一些极端的情况下,外部传入一个对象时,该对象的编译时类型是object,但程序又需要调用该类的运行时类型的方法。解决这个问题我们在编程时有两种方法解决。
- 我们知道传入的是类的运行时类型,就可以使用instanceof进行判断,再强制类型转换,就可以使用这个类的方法和变量。
- 我们不知道传入的对象的类型,也不了解该类的方法和属性,程序只能靠运行时信息来发现对象和类,这时候我们就必须使用反射。
反射实现步骤
反射主要通过Java的java.lang.Class类来完成。
- 获取目标对象的class,一般使用Class.forName(String clazzName);
- 通过class对象分别获得该类型的,构造函数,属性,方法。
- 通过获得的属性和方法,进行进一步操作。
2、java创建对象的四种方法
1. new一个对象
2. 克隆(clone),实现Cloneable接口:注意浅拷贝和深拷贝的区别
public class B implements Cloneable {
public void hello() {
System.out.println("hello");
}
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws Exception {
B obj2 = new B();
obj2.hello();
B obj3 = (B) obj2.clone();
obj3.hello();
}
}
3. 序列化与反序列化:
对于序列化机制需要明确其实现原理,在java中序列化可以通过实现Externalizable或者Serializable来实现.
public class C implements Serializable {
private static final long serialVersionUID = 1L;
//序列化要求有一个serialVersionUID
public void hello() {
System.out.println("hello");
}
public static void main(String[] args) throws Exception{
//对象序列化
C obj4 = new C();
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data.obj"));
out.writeObject(obj4); //写入
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
C obj5 = (C) in.readObject(); //读取
in.close();
obj5.hello();
}
}
4. 反射
//第四种 newInstance 调用构造函数
Object obj6 = Class.forName("A").newInstance();
Method m = Class.forName("A").getMethod("hello");
m.invoke(obj6);
A obj7 = (A) Class.forName("A").newInstance();
obj7.hello();
//第五种 newInstance 调用构造函数
Constructor<A> constructor = A.class.getConstructor();
A obj8 = constructor.newInstance();
obj8.hello();
3、Java获取Class的三种方式
-
通过String.getClass方法,获取Class对象
-
通过Class.forName(“类的全限定名”)
-
通过类字面常量,即类名.class
public class ClassTest {
public static void main(String[] args) throws ClassNotFoundException {
String s1 = "abc";
Class c1 = s1.getClass();//方法1
System.out.println(c1.getName());
Class c2 = Class.forName("java.lang.String");//方法2
System.out.println(c2.getName());
Class c3 = String.class;
System.out.println(c3.getName());//方法3
}
}
4、反射类
反射的完成依赖了Java提供的反射类,Class,Constructor(构造器),Field(属性), Method(方法)。
反射得到父类以及接口
public class SuperTest {
public static void main(String[] args) {
Son son = new Son();
Class c = son.getClass();
Class father = c.getSuperclass();
System.out.println(father.getName());
Class[] inters = c.getInterfaces();
for(Class inter : inters)
{
System.out.println(inter.getName());
}
}
}
class Father { }
class Son extends Father implements Cloneable, Comparable
{
protected Object clone() throws CloneNotSupportedException
{
return super.clone();
}
public int compareTo(Object o) {
return 0;
}
}
反射得成员变量
import java.lang.reflect.Field;
public class FieldTest {
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
A obj = new A(20, "Tom");
Class c = obj.getClass();
A bean = (A) c.newInstance();
//获取本类及父类所有的public字段
Field[] fs = c.getFields();
System.out.println(fs[0].getName() + ":" + fs[0].get(obj));
//获取本类所有声明的字段
Field[] fs2 = c.getDeclaredFields();
for(Field f : fs2) {
// 私有字段要设置属性可达,不然会抛出IllegalAccessException异常
f.setAccessible(true);
if(f.getName().equars("age")) {
// 设置属性值,set(Object obj, Object value) obj:应该修改其字段的对象; value:正被修改的 obj 的字段的新值
f.set(bean , 22);
}
System.out.println(f.getName() + ":" + f.get(obj));
}
}
}
class A {
public int age;
private String name;
public A(int age, String name){
this.age = age;
this.name = name;
}
}
反射得到方法
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static java.lang.System.out;
public class MethodTest {
public static void main(String[] args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
B obj = new B();
Class c = obj.getClass();
// 获取public方法 包括父类和父接口
Method[] ms = c.getMethods();
for (Method m : ms) {
if ("f1".equals(m.getName())) {
m.invoke(obj, null);
}
}
// 获得该类的所有方法
Method[] ms2 = c.getDeclaredMethods();
for (Method m : ms2) {
if ("f2".equals(m.getName())) {
// 私有方法要设置属性可达,不然会抛出IllegalAccessException异常
m.setAccessible(true);
String result = (String) m.invoke(obj, "abc");
out.println(result);
}
}
}
}
class B {
public void f1() {
out.println("B.f1()...");
}
private String f2(String s) {
out.println("B.f2()...");
return s;
}
}
反射得到构造函数
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ConstructorTest {
public static void main(String[] args)
throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
D d = new D();
Class c = d.getClass();
Constructor[] cons = c.getConstructors();
for (Constructor con : cons) {
if (con.getParameterCount() > 0) {
// 有参构造函数
D obj = (D) con.newInstance(100);
obj.printNum();
} else {
// 无参构造函数
D obj = (D) con.newInstance();
obj.printNum();
}
}
}
}
class D {
private int num;
public D() {
this.num = 10;
}
public D(int num) {
this.num = num;
}
public void printNum() {
System.out.println(this.num);
}
}