——- android培训、java培训、期待与您交流! ———-
类加载器:
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
1.加载:
就是指将class文件读入内存,并为之创建一个Class对象。
任何类被使用时系统都会建立一个Class对象。
2.连接:
验证是否有正确的内部结构,并和其他类协调一致
准备负责为类的静态成员分配内存,并设置默认初始化值
解析将类的二进制数据中的符号引用替换直接引用
3.初始化:
就是我们以前讲过的初始化步骤。
类加载器:
负责将.class文件加载到内存中,并为之生成对应的Class对象。
虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。
类加载器的组成:
Bootstrap ClassLoader 根类加载器:
也被称为引导类加载器,负责java核心类的加载
比如System,String等。在JDK中JRE的lib目录下rt.jar文件中。
Extension ClassLoader 扩展类加载器:
负责JRE的扩展目录中jar包的加载
在JDK中JRE的lib目录下ext目录;
System ClassLoader 系统类加载器:
负责在JVM启动时加载来自java命令的class文件,以及Classpath环境变量所指定的jar包和类路径
反射:
1.Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
2.想要解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。
反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。
要想这样使用,首先你必须得到class文件对象,其实也就是得到class类的对象。
Class类:
成员变量 Field
构造方法 Constructor
成员方法 Method
获取Class文件对象:
A:Object类的getClass()方法
B:数据类型的静态属性class
C:Class类中的静态方法:
Public static class forName(String className)
// 方式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);
}
获取构造方法:
Public Construbtor[] getConstructors():所有公共构造方法
Public Construbtor[] getDeclaredConstructors() :所有构造方法。
// 获取字节码文件对象
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();
}
}
反射的使用
A:通过反射获取构造方法并使用
* 通过反射获取构造方法并使用
*
* */
public class ReflectDemo
{
public static void main(String[] args) throws Exception
{
//获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");
//获取构造方法
//public ConStructor[] getConstructors():所有公共构造方法,private和default(既没写修饰符的情况)
//public ConStructor[] getDeclaredConstructors():所有构造方法.
//Constructor[] cons = c.getConstructors();//打印publiccn.itcast_01.Person(java.lang.String,int,java.lang.String)
//打印publiccn.itcast_01.Person()
//Constructor[] cons = c.getDeclaredConstructors();//打印publiccn.itcast_01.Person(java.lang.String,int,java.lang.String)
//cn.itcast_01.Person(java.lang.String,int)(这个就是没修修饰符的,默认)
//private cn.itcast_01.Person(java.lang.String)
//public cn.itcast_01.Person()
//for(Constructor con:cons)
//{
// System.out.println(con);
//}
//获取单个构造方法
//public Constructor<T>getConstructor(Class<?>...parameterTypes)
Constructor con = c.getConstructor();//返回的是构造方法对象,该构造器实质是加载了Person类构造器
//Person p =new Person();//代码1
//System.out.println(p);//代码1
//public T newInstance(Object...initargs)
//使用此Constructor对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例
Object obj = con.newInstance(); //得到的是Person类对象,相当于代码1
System.out.println(obj); //打印的是Person [name=null, age=0, address=null]
}
} /*
* 需求:通过反射去获取该构造方法并使用:
* public Person(String name , int age ,Stringaddress)
*
*这是一般写法
* Person p = new Person("凌青霞",27,"北京");
* System.out.println(p);
*
*
*
* */
publicclass ReflectDemo2 {
public static void main(String[]args)throws Exception
{
//获取字节码文件对象
Class c =Class.forName("cn.itcast_01.Person");
//获取带参构造方法对象
//publicConstructor<T>getConstructor(Class<?>...parameterTypes)
Constructor con =c.getConstructor(String.class , int.class ,String.class);
//通过带参构造方法对象创建对象
//public TnewInstance(Object...initargs)
Object obj = con.newInstance("凌青霞",27,"北京");
System.out.println(obj);//Person [name=凌青霞, age=27, address=北京]
}
}
/*
* 需求:通过反射获取私有构造方法并使用
* private Person(String name){}
*
* Person p = new Person("风清扬");
* System.out.println(p);
* */
publicclass ReflectDemo3 {
public static void main(String[] args)throws Exception
{
//获取字节码文件对象
Class c =Class.forName("cn.itcast_01.Person");
//获取私有构造方法对象
//NoSuchMethodException没有这个方法异常
//原因是一开始我们使用的方法只能获取公用的,下面的这种方式就可以了
//Constructor con =c.getConstructor(String.class);
//IllegalAccessException:非法的访问异常
Constructor con =c.getDeclaredConstructor(String.class);
//所以使用暴力访问
con.setAccessible(true);//这样就不会有IllegalAccessException
//值为true,则指示反射的对象在使用时应该取消Java语言访问检查
//用该私有构造方法创建对象
Object obj = con.newInstance("风清扬");
System.out.println(obj);
}
}
B:通过反射获取成员变量并使用
/*
* 通过发生获取成员变量并使用
*/
publicclass 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); //person对象
// 获取单个的成员变量
// 获取address并对其赋值
Field addressField =c.getField("address");//addressField这是一个对象
// public void set(Object obj,Objectvalue)
// 将指定对象变量上此 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);
}
}
C:通过反射获取成员方法并使用
importjava.lang.reflect.Constructor;
import java.lang.reflect.Method;
publicclass 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(Stringname,Class<?>... parameterTypes)
// 第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型
Method m1 =c.getMethod("show");
// obj.m1(); // 错误
// public Object invoke(Objectobj,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);
}
}
(4)反射案例
A:通过反射运行配置文件的内容
class.txt
className=cn.itcast.test.Student
methodName=love
/*
* 通过配置文件运行类中的方法
*
* 反射:
* 需要有配置文件配合使用.
* 用class.txt代替
* 并且你知道有两个键
* className
* methodName
*
* */
publicclass 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 = newProperties();
FileReader fr = newFileReader("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);
} <span style="font-size: 14px; line-height: 26px; font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
}
B:通过反射越过泛型检查
/*
* 我给你ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?
* */
publicclass ArrayListDemo
{
public static void main(String[] args)throws Exception
{
//创建集合对象//泛型是写给编译器看的,底层调用是泛型是E(默认是Object),真正运行的是Object
ArrayList<Integer> array = newArrayList<Integer>();
//array.add("hello");
//array.add(10);
Class c = array.getClass();//集合ArrayList的class文件对象
Method m =c.getMethod("add",Object.class);
m.invoke(array, "hello");//调用array的add方法,传入值是hello
m.invoke(array,"world");
m.invoke(array, "java");
System.out.println(array);
}
}
C:通过反射给任意的一个对象的任意的属性赋值为指定的值
*****************************************************
//执行
public class ToolDemo {
public static void main(String[] args)throws Exception
{
Person p = new Person();
Tool t = new Tool();
t.setProperty(p, "name","凌青霞");//修改私有的成员变量
t.setProperty(p, "age",27);
System.out.println(p);//凌青霞---27//
}
classPerson
{
private String name;
public int age;
@Override
public String toString()
{
return name+"---"+age
}
*****************************************************
//工具类
importjava.lang.reflect.Field;
importjavax.activation.FileDataSource;
publicclass Tool
{
public void setProperty(Object obj,StringpropertyName,Object value) throws Exception
{
//根据对象获取字节码文件对象
Class c = obj.getClass();
//获取该对象的propertyName成员变量
Field field =c.getDeclaredField(propertyName);
//取消访问检查
field.setAccessible(true);
//给对象的成员变量赋值为指定的值
field.set(obj, value);
}
}
*********************************************************
//student类
publicclass Student
{
public void love()
{
System.out.println("爱生活,爱java");
}
}
**********************************************************
//teacher
publicclass Teacher
{
public void love()
{
System.out.println("爱生活,爱青霞");
}
}
***********************************************************
//工人类
publicclass Worker
{
public void love()
{
System.out.println("爱生活,要女朋友");
}
}
动态代理
1.在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib
2.Proxy类中的方法创建动态代理类对象
public static ObjectnewProxyInstance(ClassLoader loader,Class<?>[]interfaces,InvocationHandler h)
最终会调用InvocationHandler的方法
InvocationHandler
Object invoke(Object proxy,Methodmethod,Object[] args)
***********************************************************************
//
importjava.lang.reflect.Proxy;
importcn.itcast.test.Student;
publicclass Test {
public static void main(String[]args)throws Exception
{
UserDao ud = new UserDaoImpl();
ud.add();
ud.delete();
ud.update();
ud.find();
System.out.println("------");
//我们要创建一个动态代理对象
//Proxy类中有一个方法可以创建动态代理对象
//Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类
//static objectnewProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
//返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
//InvocationHandler 是代理实例的调用处理程序 实现的接口(!!!)
//我准备对ud对象做一个代理对象
MyInvocationHandler handler = newMyInvocationHandler(ud);
UserDao proxy =(UserDao)Proxy.newProxyInstance(ud.getClass().getClassLoader(),
ud.getClass().getInterfaces(),handler);//返回的是一个代理对象,但是也应该是UserDao,他可以做一些额外的事情
proxy.add();
proxy.delete();
proxy.update();
proxy.find();
System.out.println("---------");
StudentDao sd = newStudentDaoImpl();
MyInvocationHandler handler2 = newMyInvocationHandler(sd);
StudentDao proxy2 =(StudentDao)Proxy.newProxyInstance(sd.getClass().getClassLoader(),
sd.getClass().getInterfaces(),handler2);
proxy2.login();
proxy2.regist();
}
}
************************************************************
//interfaceStudentDao
publicinterface StudentDao {
public abstract void login();
public abstract void regist();
}
****************************************************
//实现上面接口的类
publicclass StudentDaoImpl implements StudentDao{
@Override
public void login() {
// TODO Auto-generated method stub
System.out.println("登陆功能");
}
@Override
public void regist() {
// TODO Auto-generated method stub
System.out.println("注册功能");
}
}
************************************************
//interface
/*
* 用户操作接口
*
* */
publicinterface UserDao
{
public abstract void add();
public abstract void delete();
public abstract void update();
public abstract void find();
}
******************************************************
//实现上面用户接口的类
publicclass UserDaoImpl implements UserDao{
@Override
public void add() {
// TODO Auto-generated method stub
System.out.println("添加功能");
}
@Override
public void delete() {
// TODO Auto-generated method stub
System.out.println("删除功能");
}
@Override
public void update() {
// TODO Auto-generated method stub
System.out.println("下载功能");
}
@Override
public void find() {
// TODO Auto-generated method stub
System.out.println("查找功能"); .
}