Java学习-反射

一、Class类
Class类就是类的类,类是对象的抽象和集合,Class类是类的抽象和集合;
1.Class对象:每个类都会产生一个对应的Class对象,也就是保存的.class文件;Class对象记录了相应类的信息,比如类的名字,类所在的包等等。

2.作用:Class对象就是用来创建所有“常规”对象的,Java使用Class对象来执行RTTI(Run-Time Type Identification 运行时类型识别);

3.使用类的过程

  • 加载前:ClassLoade首先会检查这个类的Class对象是否已被加载过,如果尚未加载,默认的类加载器就会根据类名查找对应的.class文件;
  • 加载:由ClassLoader完成,找到对应的字节码,创建一个Class对象;
  • 链接:验证类中的字节码,为静态域分配空间;
  • 初始化:如果该类有超类,则对其初始化,执行静态初始化器和静态初始化块;

4.获取Class对象的3种方式

  • 类名.class //此方式适合在编译前就知道操作的 Class
  • new 类名().getclass()
  • class.forname(“类名”) //如果类在一个包里,包的名字也作为类名一部分;

5.自动初始化类的静态成员

  • 通过 类名.class创建Class对象不会自动初始化类的静态成员;
  • 通过new 类名().getclass()和class.forname(“类名”)这两种方式获取Class对象会自动初始化类的静态成员;
//Person类
public class Person {
	private int age;
	public int height;
	public static int weight = 10;
	
	static {
		System.out.println("Person静态块初始化" + weight);
	}
	
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}
//Male类
public class Male extends Person{
	private int JJLen;
	public static int weight = 20;

	static {
		System.out.println("Male静态块初始化" + weight);
	}
	
	public int getJJLen() {
		return JJLen;
	}

	public void setJJLen(int jJLen) {
		JJLen = jJLen;
	}
}
//Female类
public class Female extends Person{
	private String MMSize = "B";
	public static int weight = 30;

	{
		System.out.println("非静态块初始化:" + MMSize);
	}
	
	static {
		System.out.println("Female静态块初始化:" + weight);
	}
	
	public String getMMSize() {
		return MMSize;
	}

	public void setMMSize(String mMSize) {
		MMSize = mMSize;
	}
}
//测试类
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test {

	public static void main(String[] args) throws ClassNotFoundException {
		//第一种方式:类名.class
		Class cp = Person.class;
		System.out.println("第一种:" + cp.getName());
		
		//第二种方式:new 类名().getclass()
		Person male = new Male();//注意向上转型
		Classcm = male.getClass();
		System.out.println("第二种:" + cm.getName());
		
		//第三种方式:class.forname("类名")
		Class cf = Class.forName("Female");
		System.out.println("第三种:" + cf.getName());
	}

}
console结果:
第一种:Person
Person静态块初始化10

Male静态块初始化20
第二种:Male

Female静态块初始化30
第三种:Female

二、反射机制
Class类与java.lang.reflect类库一起对反射进行了支持,该类库包含Field、Method和Constructor类,这些类的对象由JVM在启动时创建,用以表示未知类里对应的成员;
1.通过反射创建对象(区别于传统的new创建对象)
通过反射创建类对象主要有两种方式:通过 Class 对象的 newInstance() 方法、通过 Constructor 对象的 newInstance() 方法。

import java.lang.reflect.Constructor;

public class Test {

	public static void main(String[] args) {
		//传统的new创建对象
		Person p = new Person();
		
		p.setAge(20);
		System.out.println(p.getAge());
		
		//使用反射创建对象第一种方式:
		try {
			//获取类对象
			Class<Person> cp = Person.class;
			//通过类对象获取构造器对象
			Constructor<Person> construct = cp.getConstructor();
			//通过构造器对象创建Person对象
			Person newP = (Person) construct.newInstance();
			
			newP.setAge(30);
			System.out.println(newP.getAge());
		} catch (Exception e) {
			e.printStackTrace();
		} 
		
		//使用反射创建对象第二种方式:
		try {
			//获取类对象
			Class<Person> cp1 = Person.class;
			//通过newInstance()方法直接创建对象
			Person newP1 = cp1.newInstance();
			
			newP1.setAge(10);
			System.out.println(newP1.getAge());
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}
}

2.通过反射获取类属性(域/成员变量)、方法、构造器

  • 2.1 在 java.lang.reflect包中有三个类 Field、 Method 和 Constructor 分别用于描述类的域、 方法和构造器。
  • 2.2 java.lang.reflect包中的 Modifier类的静态方法分析getModifiers 返回的整型数值;用 Modifier.toString()方法将修饰符打印出来。
  • 2.3 Class 类的 getDeclareFields、getDeclareMethods 和 getDeclaredConstructors 方法将分别返回类中声明的全部域、 方法和构造器,其中包括私有和受保护成员,但不包括超类的成员。
  • 2.4 Class类中的 getFields、 getMethods 和 getConstructors 方法将分别返回类提供的public的域、方法和构造器数组, 其中包括超类的public成员。
//Person类
public class Person {
	private int age;
	private String name;
	private static int height;
	
	public Person(int age) {
		super();
		this.age = age;
	}
	
	public Person(int age, String name) {
		super();
		this.age = age;
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}
//测试类
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Test {
	public static void main(String[] args) {
		 Class<Person>  cp = Person.class;
		 printConstructors(cp);
		 printMethods(cp);
		 printFields(cp);
	}
	//打印构造函数
	public static void printConstructors(Class<?> cl) {
		Constructor<?>[] construct = cl.getDeclaredConstructors();
		
		for (Constructor<?> c : construct) {
			//构造函数格式:修饰符 函数名(参数类型);
			String format = "构造函数:%s %s(%s);%n";
			//修饰符
			int modify = c.getModifiers();
			String modifiers = Modifier.toString(modify);
			//构造函数名称
			String name = c.getName();
			//参数类型
			Class<?>[] parameterTypes = c.getParameterTypes();
			String paramTypes = null;
			String temp = null;
			for(int i = 0;i < parameterTypes.length;i++) {
				paramTypes = parameterTypes[i].getName();
				if(i > 0) paramTypes = temp + ", " + paramTypes;
				temp = paramTypes;
			}
			//打印
			System.out.printf(format,modifiers,name,paramTypes);
		}
	}
	//打印成员方法
	public static void printMethods(Class<?> cl) {
		Method[] methods = cl.getMethods();
		
		for (Method m : methods) {
			//方法格式:修饰符 返回值类型 方法名(参数类型);
			String format = "成员方法:%s %s %s(%s);%n";
			//修饰符
			int modify = cl.getModifiers();
			String modifiers = Modifier.toString(modify);
			//返回值类型
			Class<?> returnType = m.getReturnType();
			String rname = returnType.getName();
			//方法名
			String name = m.getName();
			//参数类型
			Class<?>[] parameterTypes = m.getParameterTypes();
			String paramTypes = null;
			String temp = null;
			for(int i = 0;i < parameterTypes.length;i++) {
				paramTypes = parameterTypes[i].getName();
				if(i > 0) paramTypes = temp + ", " + paramTypes;
				temp = paramTypes;
			}
			//打印
			System.out.printf(format,modifiers,rname,name,paramTypes);
		}
	}
	//打印成员变量
	public static void printFields(Class<?> cl) {
		Field[] fields = cl.getDeclaredFields();
		
		for (Field f : fields) {
			//成员变量格式:修饰符 变量类型 变量名;
			String format = "成员变量:%s %s %s;%n";
			//修饰符
			int modify = f.getModifiers();
			String modifiers = Modifier.toString(modify);
			//变量类型
			Class<?> t = f.getType();
			String type = t.getName();
			//变量名
			String name = f.getName();
			//打印
			System.out.printf(format,modifiers,type,name);
		}
	}
}
console结果:
构造函数:public More.Person(int);
构造函数:public More.Person(int, java.lang.String);
成员方法:public int getAge(null);
成员方法:public void setAge(int);
成员方法:public void wait(null);
成员方法:public void wait(long, int);
成员方法:public void wait(long);
成员方法:public boolean equals(java.lang.Object);
成员方法:public java.lang.String toString(null);
成员方法:public int hashCode(null);
成员方法:public java.lang.Class getClass(null);
成员方法:public void notify(null);
成员方法:public void notifyAll(null);
成员变量:private int age;
成员变量:private java.lang.String name;
成员变量:private static int height;

3.通过反射调用方法

在这里插入代码片

4.注意

RTTI和反射的本质区别:

  • RTTI:编译器在编译时打开和检查.class文件
  • 反射:在运行时打开和检查.class文件

三、反射源码

在这里插入代码片
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值