类的加载:
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。一:加载
就是指将class文件读入内存,并为之创建一个Class对象。
任何类被使用时系统都会建立一个Class对象。
类加载器
负责将.class文件加载到内在中,并为之生成对应的Class对象。
( 虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。)
类加载器的组成
Bootstrap ClassLoader 根类加载器
Extension ClassLoader 扩展类加载器
Sysetm ClassLoader 系统类加载器
类加载器的作用:
Bootstrap ClassLoader 根类加载器也被称为引导类加载器,负责Java核心类的加载,比如System,String等。 在 JDK中JRE的lib目录下rt.jar文件中。
Extension ClassLoader 扩展类加载器,负责JRE的扩展目录中jar包的加载。在JDK中JRE的lib目录下ext目录
Sysetm ClassLoader 系统类加载器,负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径二:连接
验证 是否有正确的内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值
解析 将类的二进制数据中的符号引用替换为直接引用
三:初始化
创建类的实例:创建对象
访问类的静态变量,或者为静态变量赋值
调用类的静态方法
使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
初始化某个类的子类
直接使用java.exe命令来运行某个主类
反射:
JAVA反射机制是在运行状态中,对于任意一个类(Object),都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
(注:反射就是通过获取class字节码文件对象/Class的类对象,获取该字节码文件对象中的成员变量,构造方法,和成员方法)
一:通过反射获取构造方法并使用
获取构造方法
getConstructors
getDeclaredConstructors
创建对象
newInstance()
con.newInstance(“zhangsan", 20);
二:通过反射获取成员变量并使用
获取所有成员
getFields,getDeclaredFields
获取单个成员
getField,getDeclaredField
修改成员的值
set(Object obj,Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
获取所有方法
getMethods
getDeclaredMethods
获取单个方法
getMethod
getDeclaredMethod
暴力访问
method.setAccessible(true);
Field: 简称成员变量Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。)
Constructor:简称构造方法:提供关于类的单个构造方法的信息以及对它的访问权限。
Method:简称成员方法:类或接口上单独某个方法(以及如何访问该方法)的信息
三:反射应用举例
通过配置文件运行类中的方法,加入给ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?
写一个方法, public void setProperty(Object obj, String propertyName, Object value){},此方法可将obj对象中名为propertyName的属性的值设置为value。
问题:
如何获取class字节码文件对象/Class的类对象
答:
三种方式来获取这个class字节码文件对象:
1)Object中的getClass()
示例:获取class字节码文件对象
Person p1 = new Person() ;//创建Person对象Class c1 = p1.getClass() ; //获取class字节码文件对象
2)任何数据类型的静态属性class
示例://数据类型的静态属性class
Class c2 = Person.class ;
System.out.println(c3==c2);//打印true
forName(String className)
forName("类路径")
在开发中使用第三种方式,forName方法中的参数是一个String类型,以后可以用字符串类型数据作为配置文件!
示例://public static Class<?> forName(String className)
//java.lang.ClassNotFoundException: Person
// Class c4 = Class.forName("Person") ;
//org.westos_01.Person
//参数:类路径:包名.类名
Class c4 = Class.forName("org.westos_01.Person") ;
System.out.println(c4==c2);
package org.weosts_04;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
*通过获取成员方法并使用
*
*/
public class MethodReflectDemo {
public static void main(String[] args)throws Exception {
//通过反射获取Pereson字节码文件对象(包名.类名)
Class c = Class.forName("org.westos_01.Person") ;
//获取当前字节码文件对象中的所有的公共的成员方法(包括父类中的)
//public Method[] getMethods() 例句:Method[] methods = c.getMethods() ;
//public Method[] getDeclaredMethods():所有的成员方法
例句/*Method[] methods = c.getDeclaredMethods() ;
for(Method method:methods) {//增强for循环,遍历methods
System.out.println(method);}*/
/***
* 之前调用Person类中的show()
* Person p = new Person() ;
* p.show() ;
*/
//获取Constructor对象
Constructor con = c.getConstructor() ;
Object obj = con.newInstance() ;
//获取单个的成员方法,Method
//调用public void show(){}
//public Method getMethod(String name, Class<?>... parameterTypes)
//参数1: 表示方法名
//参数2:表示当前方法的参数数据类型的静态class属性
Method m1 = c.getMethod("show") ;
// obj.m1() ;
//public Object invoke(Object obj, Object... args)
//参数1:指定的哪个对象上调用底层invoke(),
//参数2:表示的调用那个方法所传递的实际参数
m1.invoke(obj) ; //在obj对象上调用m1对象所表示的成员方法
System.out.println("--------------------");
/**
* public void method(String s) {
System.out.println("method"+s);
}
*/
Method m2 = c.getMethod("method",String.class) ;
//调用底层方法
m2.invoke(obj, "hello") ;
System.out.println("-----------------------");
/**
* public String getString(String s,int i) {
return s+i ;
}
*/
Method m3 = c.getMethod("getString",String.class,int.class) ;
//调用Method类中的invoke()方法,调用底层哪个字节码文件对象的对应的成员方法
Object objgetString = m3.invoke(obj, "javaweb",100) ;
System.out.println(objgetString);
System.out.println("---------------------------");
/**
* //私有的
private void function() {
System.out.println("function Preson");
}
*/
//public Method getDeclaredMethod(String name , Class<?>... parameterTypes)
Method m4= c.getDeclaredMethod("function") ;
//取消Java语言访问检查
m4.setAccessible(true);
//调用obj 对象中的底层的function()方法
m4.invoke(obj) ;
}
}
成员方法
package org.westos_01;
public class Person {
private String name ;
int age ;
public String address ;
//公共的无参
public Person() {
}
//私有的带一个参数的构造方法
private Person(String name) {
this.name = name ;
}
//没有权限修饰符的带两个参数的构造方法
Person(String name,int age){
this.name = name ;
this.age =age ;
}
//公共的带三个参数的构造方法
public Person(String name,int age,String address) {
this.name = name ;
this.age =age ;
this.address = address;
}
//成员方法
//无参的,没有返回值
public void show() {
System.out.println("show Person");
}
//有参的,没有返回值的
public void method(String s) {
System.out.println("method"+s);
}
//有参的,并且有返回值的
public String getString(String s,int i) {
return s+i ;
}
//私有的
private void function() {
System.out.println("function Preson");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", address=" + address + "]"; }}
动态代理:
动态代理(hibernate,MyBatis都会存在代理)
代理:本来应该自己做的事情,却请了别人来做,被请的人就是代理对象。
举例:春季回家买票让人代买
动态代理:在程序运行过程中产生的这个对象
而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理
在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib
Proxy类中的方法创建动态代理类对象
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
最终会调用InvocationHandler的方法
InvocationHandler
Object invoke(Object proxy,Method method,Object[] args)