一、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文件
三、反射源码
在这里插入代码片