100、类加载和反射

来源:互联网 发布:网络广告宣传图片 编辑:程序博客网 时间:2024/06/06 11:46
一、类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,
初始化三步来实现对这个类进行初始化。
1、加载
就是指将class文件读入内存,并为之创建一个Class对象。
任何类被使用时系统都会建立一个Class对象。
2、连接
1)、验证 是否有正确的内部结构,并和其他类协调一致
2)、准备 负责为类的静态成员分配内存,并设置默认初始化值
3)、解析 将类的二进制数据中的符号引用替换为直接引用
4)、初始化 就是我们以前讲过的初始化步骤
3、初始化(类的加载时机)
1)、创建类的实例
2)、访问类的静态变量,或者为静态变量赋值
3)、调用类的静态方法
4)、使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
5)、初始化某个类的子类
6)、直接使用java.exe命令来运行某个主类

二、类初始化时机
1、创建类的实例
2、访问类的静态变量,或者为静态变量赋值
3、调用类的静态方法
4、使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
5、初始化某个类的子类
6、直接使用java.exe命令来运行某个主类


三、类加载器
1、类加载器
负责将.class文件加载到内在中,并为之生成对应的Class对象。
虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。
2、类加载器的组成
Bootstrap ClassLoader 根类加载器
Extension ClassLoader 扩展类加载器
Sysetm ClassLoader 系统类加载器
3、类加载器的作用
1)、Bootstrap ClassLoader 根类加载器
也被称为引导类加载器,负责Java核心类的加载
比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
2)、Extension ClassLoader 扩展类加载器
负责JRE的扩展目录中jar包的加载。
在JDK中JRE的lib目录下ext目录
3)、Sysetm ClassLoader 系统类加载器
负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量
所指定的jar包和类路径

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

五、反射机制的使用-获得Class对象
/*
* 反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。
*
* Person p = new Person();
* p.使用
*
* 要想这样使用,首先你必须得到class文件对象,其实也就是得到Class类的对象。
* Class类:
* 成员变量 Field
* 构造方法 Constructor
* 成员方法 Method
*
* 获取class文件对象的方式:
* A:Object类的getClass()方法
* B:数据类型的静态属性class
* C:Class类中的静态方法
* public static Class forName(String className)
*
* 一般我们到底使用谁呢?
* A:自己玩 任选一种,第二种比较方便
* B:开发 第三种
* 为什么呢?因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中。
*/
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 方式1
Person p = new Person();
Class c = p.getClass();

Person p2 = new Person();
Class c2 = p2.getClass();

System.out.println(p == p2);// false
System.out.println(c == c2);// true

// 方式2
Class c3 = Person.class;
// int.class;
// String.class;
System.out.println(c == c3);

// 方式3
// ClassNotFoundException
Class c4 = Class.forName("cn.itcast_01.Person");
System.out.println(c == c4);
}
}

六、反射机制的使用-获得构造方法Constructor对象
/*
* 通过反射获取构造方法并使用。
*/
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");

// 获取构造方法
// public Constructor[] getConstructors():所有公共构造方法
// public Constructor[] getDeclaredConstructors():所有构造方法
// Constructor[] cons = c.getDeclaredConstructors();
// for (Constructor con : cons) {
// System.out.println(con);
// }

// 获取单个构造方法
// public Constructor<T> getConstructor(Class<?>... parameterTypes)
// 参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象
Constructor con = c.getConstructor();// 返回的是构造方法对象

// Person p = new Person();
// System.out.println(p);
// public T newInstance(Object... initargs)
// 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
Object obj = con.newInstance();
System.out.println(obj);
// Person p = (Person)obj;
// p.show();
}
}

/*
* 需求:通过反射去获取该构造方法并使用:
* public Person(String name, int age, String address)
*
* Person p = new Person("林青霞",27,"北京");
* System.out.println(p);
*/
public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");

// 获取带参构造方法对象
// public Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor con = c.getConstructor(String.class, int.class,
String.class);

// 通过带参构造方法对象创建对象
// public T newInstance(Object... initargs)
Object obj = con.newInstance("林青霞", 27, "北京");
System.out.println(obj);
}
}

/*
* 需求:通过反射获取私有构造方法并使用
* private Person(String name){}
*
* Person p = new Person("风清扬");
* System.out.println(p);
*/
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");

// 获取私有构造方法对象
// NoSuchMethodException:每个这个方法异常
// 原因是一开始我们使用的方法只能获取公共的,下面这种方式就可以了。
Constructor con = c.getDeclaredConstructor(String.class);

// 用该私有构造方法创建对象
// IllegalAccessException:非法的访问异常。
// 暴力访问
con.setAccessible(true);// 值为true则指示反射的对象在使用时应该取消Java语言访问检查。
Object obj = con.newInstance("风清扬");

System.out.println(obj);
}
}

七、反射机制的使用-获得成员变量Field对象
/*
* 通过发生获取成员变量并使用
*/
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");

// 获取所有的成员变量
// Field[] fields = c.getFields();
// Field[] fields = c.getDeclaredFields();
// for (Field field : fields) {
// System.out.println(field);
// }

/*
* Person p = new Person(); p.address = "北京"; System.out.println(p);
*/

// 通过无参构造方法创建对象
Constructor con = c.getConstructor();
Object obj = con.newInstance();
System.out.println(obj);

// 获取单个的成员变量
// 获取address并对其赋值
Field addressField = c.getField("address");
// public void set(Object obj,Object value)
// 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
addressField.set(obj, "北京"); // 给obj对象的addressField字段设置值为"北京"
System.out.println(obj);

// 获取name并对其赋值
// NoSuchFieldException
Field nameField = c.getDeclaredField("name");
// IllegalAccessException
nameField.setAccessible(true);
nameField.set(obj, "林青霞");
System.out.println(obj);

// 获取age并对其赋值
Field ageField = c.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(obj, 27);
System.out.println(obj);
}
}

八、反射的使用-获得成员方法Method对象
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");

// 获取所有的方法
// Method[] methods = c.getMethods(); // 获取自己的包括父亲的公共方法
// Method[] methods = c.getDeclaredMethods(); // 获取自己的所有的方法
// for (Method method : methods) {
// System.out.println(method);
// }

Constructor con = c.getConstructor();
Object obj = con.newInstance();

/*
* Person p = new Person(); p.show();
*/

// 获取单个方法并使用
// public void show()
// public Method getMethod(String name,Class<?>... parameterTypes)
// 第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型
Method m1 = c.getMethod("show");
// obj.m1(); // 错误
// public Object invoke(Object obj,Object... args)
// 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数
m1.invoke(obj); // 调用obj对象的m1方法

System.out.println("----------");
// public void method(String s)
Method m2 = c.getMethod("method", String.class);
m2.invoke(obj, "hello");
System.out.println("----------");

// public String getString(String s, int i)
Method m3 = c.getMethod("getString", String.class, int.class);
Object objString = m3.invoke(obj, "hello", 100);
System.out.println(objString);
// String s = (String)m3.invoke(obj, "hello",100);
// System.out.println(s);
System.out.println("----------");

// private void function()
Method m4 = c.getDeclaredMethod("function");
m4.setAccessible(true);
m4.invoke(obj);
}
}

九、反射的工具类
public class Tool {
public void setProperty(Object obj, String propertyName, Object value)
throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
// 根据对象获取字节码文件对象
Class c = obj.getClass();
// 获取该对象的propertyName成员变量
Field field = c.getDeclaredField(propertyName);
// 取消访问检查
field.setAccessible(true);
// 给对象的成员变量赋值为指定的值
field.set(obj, value);
}
}

public class ToolDemo {
public static void main(String[] args) throws NoSuchFieldException,
SecurityException, IllegalArgumentException, IllegalAccessException {
Person p = new Person();
Tool t = new Tool();
t.setProperty(p, "name", "林青霞");
t.setProperty(p, "age", 27);
System.out.println(p);
System.out.println("-----------");

Dog d = new Dog();

t.setProperty(d, "sex", '男');
t.setProperty(d, "price", 12.34f);

System.out.println(d);
}
}

十、加载配置文件
/*
* 通过配置文件运行类中的方法
*
* 反射:
* 需要有配置文件配合使用。
* 用class.txt代替。
* 并且你知道有两个键。
* className
* methodName
*/
public class Test {
public static void main(String[] args) throws Exception {
// 反射前的做法
// Student s = new Student();
// s.love();
// Teacher t = new Teacher();
// t.love();
// Worker w = new Worker();
// w.love();
// 反射后的做法

// 加载键值对数据
Properties prop = new Properties();
FileReader fr = new FileReader("class.txt");
prop.load(fr);
fr.close();

// 获取数据
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");

// 反射
Class c = Class.forName(className);

Constructor con = c.getConstructor();
Object obj = con.newInstance();

// 调用方法
Method m = c.getMethod(methodName);
m.invoke(obj);
}
}

配置文件class.txt文件里的内容
className=cn.itcast.test.Worker
methodName=love






原创粉丝点击