欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

反射

程序员文章站 2022-06-18 10:55:25
...

反射是框架设计的灵魂

(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))

什么是反射?
反射java语言中的一种机制,通过这种机制可以动态的实例化对象、读写属性、调用方法

反射的概述

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

类类

所有狗 狗类 Dog.class 狗对象 旺财

所有猫 猫类 Cat 猫对象 肥波

所有类 类类 java.lang.Class 类对象 特定类

  1. 一切反射相关的代码都从获得类对象开始

3.1 Class.forName(完整类名)

3.2 类名.class

3.3 对象.getClass()

注1:ClassNotFoundException(类名错|少jar包)

注2:同一类的、类对象只会创建一个

反射的使用(这里使用Student类做演示)

先写一个Student类。

1、获取Class对象的三种方式
1.1 Object ——> getClass();
1.2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
1.3 通过Class类的静态方法:forName(String className)(常用)

Student.java

package com.zking.reflect;

public class Student {
	private String sid;

	private String sname;

	public Integer age;
	
	static{
		System.out.println("加载进jvm中!");
	}

	public Student() {
		super();
		System.out.println("调用无参构造方法创建了一个学生对象");
	}

	public Student(String sid) {
		super();
		this.sid = sid;
		System.out.println("调用带一个参数的构造方法创建了一个学生对象");
	}

	public Student(String sid, String sname) {
		super();
		this.sid = sid;
		this.sname = sname;
		System.out.println("调用带二个参数的构造方法创建了一个学生对象");
	}

	@SuppressWarnings("unused")
	private Student(Integer age) {
		System.out.println("调用Student类私有的构造方法创建一个学生对象");
		this.age = age;
	}

	public String getSid() {
		return sid;
	}

	public void setSid(String sid) {
		this.sid = sid;
	}

	public String getSname() {
		return sname;
	}

	public void setSname(String sname) {
		this.sname = sname;
	}

	public void hello() {
		System.out.println("你好!我是" + this.sname);
	}

	public void hello(String name) {
		System.out.println(name + "你好!我是" + this.sname);
	}

	@SuppressWarnings("unused")
	private Integer add(Integer a, Integer b) {
		return new Integer(a.intValue() + b.intValue());
	}
}

package com.zking.reflect;

/**
 * 获取对象的方式 获取Java.lang.class的一个实例类 --->对于本堂课而言,Student.class
 * 1、通过对应实例的getClass()方法获取 通用增删改的时候用到
 * 2、通过Class.forBanem("类的全路径 ") JDBC的驱动加载就用到反射技术 
 * 3、类实例.class
 */

public class Demo2 {
	public static void main(String[] args) throws Exception {
		//第一种方式获取Class对象
		// Student stu = new Student();
		// Class clz = stu.getClass();
		
		//第二种方式获取Class对象
		//  Class clz = Class.forName("com.zking.reflect.Student");

		//第三种方式获取Class对象  //需要甩异常
		Class clz = Student.class;
		System.out.println(clz);

	}

}
注意:在运行期间,一个类,只有一个Class对象产生。

反射三大作用(java.lang.reflect.*)
1.实例化对象 .newInstance()

getConstructor 与 getDeclaredConstructor的区别在于
getConstructor获取public修饰的
getDeclaredConstructor 获取的所有的构造器 不管是私有化的还是公开的…都是可以获取到 ! 如果是在有参数的情况下,一定要用 getDeclaredConstructor

 package com.zking.reflect;

import java.lang.reflect.Constructor;

/**
 * 利用反射进行实例化 能够获取到Student.class 如何通过Student.calss拿到Student的一个实例
 * 
 * 
 * 反射的好处 能够将未知的类进行实例化
 * 
 */

public class Demo3 {

	public static void main(String[] args) throws Exception, Exception {
		Class clz = Student.class;
		// 通过反射的方式调用无参构造器来实例化对象
		// Student stu = (Student)clz.newInstance();

		// 通过反射的方式调用带有一个参数构造器来实例化对象
//		Constructor c = clz.getDeclaredConstructor(String.class);
//		Student stu = (Student) c.newInstance("S001");

		// 通过反射的方式调用带有两个参数构造器来实例化对象
//		Constructor c = clz.getDeclaredConstructor(String.class,String.class);
//		Student stu = (Student) c.newInstance("S001","zs");
		
		// 通过反射的方式调用私有的构造器来实例化对象
//		getConstructor 与  getDeclaredConstructor 区别
//		getConstructor 获取到的是public修饰的
//		getDeclaredConstructor获取到所有的构造器
		
		Constructor c = clz.getDeclaredConstructor(Integer.class);
		c.setAccessible(true);
		Student stu = (Student) c.newInstance(01);
		
		
		// Student stu = new Student();

	}

}

2 动态调用方法

Method m;
m.invoke
获得私有的构造方法必须要用到这个 field.setAccessible(true);

package com.zking.reflect;

import java.lang.reflect.Method;

/**
 * 动态方法调用
 * @author lenovo
 *
 */
public class Demo4 {
	
	public static void main(String[] args) throws Exception, Exception {
		Class clz = Student.class;
		
		//Method m = clz.getDeclaredMethod("hello");
		//第一个参数指的是:类的实例化
		//第二个参数:指的是调用方法课携带的可变参数
//		Method类invoke方法的返回值就是被调用的方法返回值
//		如果被调用的方法不具备返回值那么返回NULL
		//System.out.println(m.invoke(clz.newInstance()));
		
//		Method m = clz.getDeclaredMethod("hello",String.class);
//		m.invoke(clz.newInstance(), "xxx");
		
		Method m = clz.getDeclaredMethod("add",Integer.class,Integer.class);
		m.setAccessible(true);
		Object invoke = m.invoke(clz.newInstance(), 20,5);
		System.out.println(invoke);
		
	}
	
	
	
}

反射
3 读写属性

Field set/get
Field[] : 获得类所有属性
Field : 获取类指定属性

package com.zking.reflect;

import java.lang.reflect.Field;

/**
 * 反射的读写属性
 * 
 * @author lenovo
 *
 */

public class Demo5 {
	public static void main(String[] args) throws Exception {
		Student stu = new Student("S001","zs");
		stu.age = 23;
		
		Class clz = Student.class;
		
		//获取属性值
//		Field[] fields = clz.getDeclaredFields();
//		for (Field field : fields) {
//			field.setAccessible(true);
//			System.out.println(field.getName()+"  :  "+field.get(stu));
//		}
		
		//设置属性值   共有的
//		Field field = clz.getDeclaredField("age");
//		field.set(stu, 18);
//		System.out.println(stu.age);
		
		Field field = clz.getDeclaredField("sname");
		field.setAccessible(true);
		field.set(stu, "xl");
		System.out.println(stu.getSname());
		
		
		
	}
}
  1. 访问修饰符
    getModifiers():
    如何判断类或变量、方法的修饰符,可以使用Java反射机制中,Field的getModifiers()方法返回int类型值表示该字段的修饰符,即这个方法就是返回一个int型的返回值,代表类、成员变量、方法的修饰符。

    其中,该修饰符是java.lang.reflect.Modifier的静态属性。

对应表如下:

PUBLIC: 1
PRIVATE: 2
PROTECTED: 4
STATIC: 8
FINAL: 16
SYNCHRONIZED: 32
VOLATILE: 64
TRANSIENT: 128
NATIVE: 256
INTERFACE: 512
ABSTRACT: 1024
STRICT: 2048

把它们转换成二进制,可以看出,Modifier使用一个二进制的位来表示是否包含某个修饰符。

如果是public static,对应的整数就是二进制的:1001,也就是9。

如果是public static final就是11001,也就是25。

现在如果想判断是否仅有public static两个修饰符,那么就可以判断是否field.getModifiers() == 25。

OK,Java反射就到這裏了…

相关标签: 反射