标签:反射 java class System public 使用 println Class out
java 反射使用
前言
这里简单学习java反射的使用,后面会结合注解再一起在进行学习,后面几篇文章会集合retrofft一起讲解,主要是学习retrofft的思想以及使用到的Java技术,如有纰漏之处,万望指出。
反射的定义
反射的定义:在运行的状态中,对于一个实体类,都能知道这个类的所有属性和方法;对于任意对象,都能够调用任意方法和属性,这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
理解虚拟机加载过程
java程序经过javac编译器编译,生产.class字节码文件,.class字节码文件是一个二进制文件,包含了java虚拟机指令集和符号表以及若干其他辅助信息。这是一个虚拟机能识别的加载的文件。
而反射获取的数据就是经过虚拟机加载后生产的Class文件中的数据,这里的Class文件和编译后生成的.class文件并不是同一个文件,要理解这个我们得先知道虚拟机的类加载机制。
虚拟机加载过程
加载–>链接(–>验证–>准备–>解析)–>初始化–>使用–>卸载
加载:通过一个类的全限定名来获取定义此类的二进制字节流,并将这个字节流所代表的静态结构转换成方法区运行的数据结构,并在堆中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。java反射获取的就是这个Class对象中的数据。也就是说在使用反射的时候,是需要首先获取到这个类的二进制字节流。
验证:主要做4个验证动作1、文件格式验证、元数据验证、字节码验证和符号引用验证。
准备:这是正式为类变量(static修饰的变量)分配内存并设置类变量初始值的阶段,
解析:虚拟机将常量池内的符号引用替换成直接引用的过程,主要动作针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号。
初始化:初始化阶段是执行类构造器()方法的过程。()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块()中的语句构成的。在初始化的过程中,首先初始化的是父类的()方法,因此虚拟机中第一个执行的()方法的一定是java.lang.Object
剩下的就是使用和卸载,详细了解请查看《深入理解java虚拟机》
反射支持类
这里我知道反射获取的就是加载后生成的Class对象中的数据,那么获取到这些信息需要哪些核心类的支持呢
- Class类:代表一个类
- Field类:代表一个类的成员变量
- Method类:代表类的成员方法
- Constructor类:代表类的构造方式
- Array类:提供了动态创建数组,以及访问数组的元素的静态方法
Class类
首先我们看下java.lang包下的部分Class类源码,Class类封装一个对象和接口运行时的状态,当虚拟机加载类时,Class类型的对象自动创建。Class没有公共构造方法。Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的,因此不能显示地声明一个Class对对象。
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {
private static final int ANNOTATION= 0x00002000;
private static final int ENUM = 0x00004000;
private static final int SYNTHETIC = 0x00001000;
private static native void registerNatives();
static {
registerNatives();
}
/*
* Private constructor. Only the Java Virtual Machine creates Class objects.
* This constructor is not used and prevents the default constructor being
* generated.
*/
private Class(ClassLoader loader) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
}
. . .
}
Class类的常用方法
getName() :获得类的完整名称
getFields():获得类的public类型的属性
getDeclaredFields():获得类的所有属性
getMethod():获得类的public类型方法
getDeclaredFiedMethods():获得类的所有方法
getMethod(String name,Class[] parameterTypes):获得类的特定方法,name参数制定方法的名字,parameterTypes 参数制定方法参数类型
getConstructors():获得类的public类型的构造方法
getConstructor(Class[] parameterTypes):获得类的特定构造方式,parameterTypes 参数指定构造方法的参数类型
newInstance():通过类的不带参数的构造方法创建这个类的一个对象
使用核心类提供方法
public class Animal {
private String name;
private int age;
private String msg = "hello wrold";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Animal() {
}
private Animal(String name) {
this.name = name;
System.out.println("我是私有构造方法传入一个String参数:" + name);
}
public void fun() {
System.out.println("fun");
}
public void fun(String name, int age) {
System.out.println("我叫" + name + ",今年" + age + "岁");
}
private void run() {
System.out.println("我是私有方法");
}
}
public class Test {
public static void main(String[] args) throws Exception {
String a = "abc";
Class c1 = a.getClass();
Animal animal = new Animal();
Class c2 = animal.getClass();
Class c3 = c2.getSuperclass();
//根据类的全限定名加载class
Class c4 = Class.forName("com.reflection.Animal");
Class c9 = Animal.class;
System.out.println(c2);
System.out.println(c4);
System.out.println(c9);
System.out.println(c9.getModifiers());
Class c5 = String.class;
Class c6 = int.class;
Class c7 = boolean.class;// 还有其他基本数据类型class可以获取
Class c8 = void.class;
// Constructor 类:代表类的构造方法。
// Field 类:代表类的成员变量(成员变量也称为类的属性)。
// Method类:代表类的方法。
System.out.println("==========调用Animal的公共方法fun");
Object o = c4.newInstance();
Method m = c4.getMethod("fun", String.class, int.class);
m.invoke(o, "tian", 10);
System.out.println("==========调用Animal的私有方法run");
Method m1 = c4.getDeclaredMethod("run");
m1.setAccessible(true);
System.out.println("方法名称:" + m1.getName());
System.out.println("方法类型:" + m1.getModifiers());
m1.invoke(o);
System.out.println("==========获取Animal所有的public方法,包括父类的");
Method[] m2 = c4.getMethods();// 得到该类所有的public方法,包括父类的
for (Method med : m2) {
String methodName = med.getName();
System.out.println("++" + methodName);
}
System.out.println("==========获取Animal所有的方法,不包括父类的");
Method[] methods = c4.getDeclaredMethods(); // 得到该类所有的方法,不包括父类的
for (Method med : methods) {
String methodName = med.getName();
System.out.println("==" + methodName);
}
Field field = c4.getDeclaredField("msg");
Object o2 = c4.newInstance();
field.setAccessible(true);// 设置是否允许访问,因为该变量是private的,所以要手动设置允许访问,如果msg是public的就不需要这行了。
Object msg = field.get(o2);
System.out.println("==========获取Animal的msg属性");
System.out.println("" + msg);
System.out.println("==========获取Animal所有所属");
Field[] fiel = c4.getDeclaredFields();//// 获取所有成员变量的数组:
for (Field field2 : fiel) {
field2.setAccessible(true);
Object msgs = field2.get(o2);
System.out.println("所有属性" + msgs);
}
System.out.println("==========调用Animal的所有的构造器,不包括其父类的构造器 (构造方法必须声明传递参数)");
Constructor constructor = c4.getDeclaredConstructor(String.class);// 访问一个有String
// 参数的构造方法
constructor.setAccessible(true);// 设置是否允许访问,因为该构造器是private的,所以要手动设置允许访问,如果构造器是public的就不需要这行了。
constructor.newInstance("tian");// 传入一个参数值为 tian
System.out.println("==========调用Animal的所有的构造器,包括其父类的构造器");
Constructor[] con = c4.getDeclaredConstructors();
for (Constructor cons : con) {
System.out.println(cons);
}
System.out.println("==========反射对泛型的理解");
List list = new ArrayList<>();
List<String> list2 = new ArrayList<String>();
list2.add("长度");
System.out.println(list2.size());
Class cl1 = list.getClass();
Class cl2 = list2.getClass();
System.out.println(list == list2); // 结果:true,说明类类型完全相同
Method mlist = cl2.getMethod("add", Object.class);
mlist.invoke(list2, 10);
System.out.println("list2长度:" + list2.size());
}
}
标签:反射,java,class,System,public,使用,println,Class,out 来源: https://blog.csdn.net/oheg2010/article/details/88564266
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。