Java反射

1、反射的定义

Java语言中一种动态(运行时)访问、检测、修改它本身的能力。可以动态的获取类的完整结构信息,调用对象的方法。

适用地方

Java中的两种类型:编译时类型、运行时类型。

// Person为p的编译时类型,Student为p的运行时类型
Person p = new Student();

在一些极端的情况下,外部传入一个对象时,该对象的编译时类型是object,但程序又需要调用该类的运行时类型的方法。解决这个问题我们在编程时有两种方法解决。

  1. 我们知道传入的是类的运行时类型,就可以使用instanceof进行判断,再强制类型转换,就可以使用这个类的方法和变量。
  2. 我们不知道传入的对象的类型,也不了解该类的方法和属性,程序只能靠运行时信息来发现对象和类,这时候我们就必须使用反射。
反射实现步骤

反射主要通过Java的java.lang.Class类来完成。

  1. 获取目标对象的class,一般使用Class.forName(String clazzName);
  2. 通过class对象分别获得该类型的,构造函数,属性,方法。
  3. 通过获得的属性和方法,进行进一步操作。

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的三种方式

  1. 通过String.getClass方法,获取Class对象

  2. 通过Class.forName(“类的全限定名”)

  3. 通过类字面常量,即类名.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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值