类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,链接,初始化三步来实现对这个类进行初始化。
加载
就是指将class文件读到内存,并为之创建一个class对象
任何类被使用时系统都会建立一个class对象
链接
验证是否有正确的内部结构,并和其他类协调一致
准备负责为类的静态成员分配内存,并设置默认初始化值
初始化就是之前的初始化步骤
类初始化的加载时机:
创建类的加载实例
访问类的静态变量或为静态变量赋值
调用类的静态方法
使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
初始化某个类的子类
直接使用java.exe命令来运行某个主类
类加载器
负责将.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包和类路径
反射
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它任意一个方法阿和属性;这种动态获取的信息以及动态调用对象的方法的功能 成为Java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象,而要解剖使用的Class类中的方法,所以要先要获取到每一个字节码文件对应的Class类型的对象。
/* * 反射:就是通过class文件对象,去使用该文件中的成员变量、构造方法、成员方法 * 要使用这个对象,首先必须得到class文件对象,其实也就是得到Class类的对象 * Class类: * 成员变量 Field * 构造方法 Constructor * 成员方法 Method * 获取class文件对象的方式 * 1、Object类中的getClass()方法; * 2、数据类型的静态属性class * 3、Class类中的静态方法forName() * 一般我们使用什么呢? * 1、自己玩 任选一种,第二种比较方便 * 2、开发 第三种 这种是一个字符串,而不是一个具体的看到的类名,这样我们就可以把这样的字符串配置到配置文件中 */ public class ClassTest { public static void main(String[] args) throws Exception { //1、Object类中的getClass()方法; Person p1 = new Person(); Class c = p1.getClass(); Person p2 = new Person(); Class c2 = p2.getClass(); System.out.println(p1 == p2);//false,都是新建立的,并不相等 System.out.println(c == c2);//true,只有一个class文件,获得的class文件相等。 //方式2 Class c3 = Person.class; System.out.println(c == c3); //注意一定要写全路径,不然找不到报错 //可以下拉Person.java文件,在Person文件上右键复制限定名也可以 Class c4 = Class.forName("classDemo.Person"); } }
import java.lang.reflect.Constructor; /* Constructor<?>[] getConstructors() 返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。 Constructor<?>[] getDeclaredConstructors() 返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。 Constructor<T> getConstructor(Class<?>... parameterTypes) 参数表示你要获取构造方法的参数构造方法的class字节码 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。 T newInstance(Object... initargs) 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。 */ public class ClassDemo2 { public static void main(String[] args) throws Exception { //获取字节码 Class c = Class.forName("classDemo.Person"); //返回单个构造方法 Constructor con = c.getConstructor(); //输出的是Person类的toString()方法,所以这里返回的不是Object类,而是Person类 Object obj = con.newInstance(); System.out.println(obj); } }
import java.lang.reflect.Constructor; public class ClassDemo2 { public static void main(String[] args) throws Exception { //获取字节码 Class c = Class.forName("classDemo.Person"); //传入的是Class文件,获取带参构造方法 //public Person(String name, int age, String address) Constructor con = c.getConstructor(String.class, int.class, String.class); //构建带参构造对象 Object obj = con.newInstance("zed", 19, "akl"); System.out.println(obj); } }
获取私有构造
public class Person { String name; int age; String address; // public Person(){} private Person(String name){ this.name = name; } /* public 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 menthod(){ System.out.println("公有方法"); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", address=" + address + "]"; } private void show(){ System.out.println("私有方法"); } } //---------------------------------------------------------------- import java.lang.reflect.Constructor; public class ClassDemo2 { public static void main(String[] args) throws Exception { //获取字节码 Class c = Class.forName("classDemo.Person"); //传入的是Class文件,获取私有构造方法 //NoSuchMethodException异常 //Constructor con = c.getConstructor(String.class); //Constructor getDeclaredConstructor() 返回 Constructor 返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。 Constructor con = c.getDeclaredConstructor(String.class); //父类类 AccessibleObject中setAccessible()方法,值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。 //值为true都可以访问 con.setAccessible(true); //构建带参构造对象 Object obj = con.newInstance("zed"); System.out.println(obj); } }
获取成员变量
import java.lang.reflect.Field; //获取成员变量并使用 public class ClassDemo2 { public static void main(String[] args) throws Exception { //获取字节码 Class c = Class.forName("classDemo.Person"); //获取变量 //获取公共成员字段 Field[] fields = c.getFields(); //获取所有成员变量 //Field[] getDeclaredFields() 返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。 Field[] fieldss = c.getDeclaredFields(); for(Field f : fieldss){ System.out.println(f); } } }
public class ClassDemo2 { public static void main(String[] args) throws Exception { //获取字节码 Class c = Class.forName("classDemo.Person"); Object obj = c.newInstance(); //获取单个指定成员变量 //此处返回的是Field类对象,通过Field类中的各种set方法设置为你想要的类型 Field nameField = c.getField("name"); //set(Object obj, Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。 //这里就是讲obj类中的name的值设置为zed nameField.set(obj, "zed"); } }
获取指定成员变量并赋值
import java.lang.reflect.Field; public class ClassDemo2 { public static void main(String[] args) throws Exception { //获取字节码 Class c = Class.forName("classDemo.Person"); Object obj = c.newInstance(); System.out.println(obj); //获取单个指定成员变量 Field nameField = c.getField("name"); //Field getDeclaredField(String name) 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。 Field nameField = c.getDeclaredField("name"); //此处返回的是Field类对象,通过Field类中的各种set方法设置为你想要的类型 //set(Object obj, Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。 //这里就是讲obj类中的name的值设置为zed
nameField.setAccessible(true);用之前调用这个方法取消检查 nameField.set(obj, "zed"); System.out.println(obj); } }
获取调用方法
import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class ClassDemo2 { public static void main(String[] args) throws Exception { //获取字节码 Class c = Class.forName("classDemo.Person"); Constructor con = c.getConstructor(); Object obj = con.newInstance(); /* Method getMethod(String name, Class<?>... parameterTypes) 返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。 Method[] getMethods() 获取自己的,包括父类的公共方法 返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。 Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。 Method[] getDeclaredMethods() 返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 */ //获取方法对象 Method m = c.getDeclaredMethod("shows"); //Object invoke(Object obj, Object... args) 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。 //obj - 从中调用底层方法的对象 //args - 用于方法调用的参数,没有参数的话空着就可以。 //执行方法 m.invoke(obj); } }
public int setI(int i){ return i; } //--------------------或者强制类型转换------------------------------ Method m = c.getDeclaredMethod("setI", int.class); //m.invoke()返回的是一个Object类型 Object obj2 = m.invoke(obj, 1); System.out.println("obj2: " + obj2); //其实变量的类为Integer System.out.println(obj2.getClass());
获取执行私有方法
//获取私有方法对象 Method m = c.getDeclaredMethod("show"); //不检查是否私有 m.setAccessible(true); m.invoke(obj);
反射实现根据配置执行类方法
public class Student { public void show(){ System.out.println("爱生活,爱学习"); } } //-------------------------------------------------- public class Me { public void show(){ System.out.println("爱生活,爱编程"); } } //-------------------------------------------------- public class Other { public void show(){ System.out.println("other"); } } //-------------------------------------------------- 配置文件: ClassName=classDemo.Other Method=show
import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Properties; public class ClassDemo { public static void main(String[] args) throws IOException, Exception { //获取配置文件 Properties prop = new Properties(); FileReader fr = new FileReader("D:\\EclipseWorkSpace\\StudyDemo\\src\\classDemo\\配置.txt"); prop.load(fr); //获取配置文件中ClassName和要执行的方法Method String className = prop.getProperty("ClassName"); String method = prop.getProperty("Method"); //注意:Class c = Class.forName("className");这样是不对的,字符串直接传就可以,蛋疼 //获取字节码 Class c = Class.forName(className); //获取无参构造,并创建无参对象 Constructor con = c.getDeclaredConstructor(); Object obj = con.newInstance(); //获取要执行的方法名 Method m = c.getMethod(method); //执行方法 m.invoke(obj); } }
/* * 我给你ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢? */ public class ArrayListDemo { public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { // 创建集合对象 //泛型是给编译器看的 ArrayList<Integer> array = new ArrayList<Integer>(); // array.add("hello"); // array.add(10); Class c = array.getClass(); // 集合ArrayList的class文件对象,底层传入的其实是Object类 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); } }
动态代理
在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。以后用这个cglib。
Proxy类中的方法创建动态代理对象
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) //返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
最终会调用InvocationHandler的方法
InvocationHandler
Object invoke(Object proxy, Method method, Object[] args)
public interface StudentDao { public abstract void login(); public abstract void regist(); } //--------------------------------------- public class StudentDaoImpl implements StudentDao { @Override public void login() { System.out.println("登录功能"); } @Override public void regist() { System.out.println("注册功能"); } } //--------------------------------------- /* * 用户操作接口 */ public interface UserDao { public abstract void add(); public abstract void delete(); public abstract void update(); public abstract void find(); } //--------------------------------------- public class UserDaoImpl implements UserDao { @Override public void add() { System.out.println("添加功能"); } @Override public void delete() { System.out.println("删除功能"); } @Override public void update() { System.out.println("修改功能"); } @Override public void find() { System.out.println("查找功能"); } } //--------------------------------------- import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { private Object target; // 目标对象 public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("权限校验"); Object result = method.invoke(target, args); System.out.println("日志记录"); return result; // 返回的是代理对象 } } //------------------------------------------ import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { UserDao ud = new UserDaoImpl(); ud.add(); ud.delete(); ud.update(); ud.find(); System.out.println("-----------"); // 创建一个动态代理对象 // Proxy类中有一个方法可以创建动态代理对象 // public static Object newProxyInstance(ClassLoader loader,Class<?>[] // interfaces,InvocationHandler h) // 对ud对象做一个代理对象 //ClassLoader类加载器 //动态代理实现类 MyInvocationHandler handler = new MyInvocationHandler(ud); //传入类加载器,类方法和动态代理实现类得到一个UserDao类对象 //然后通过UserDao类对象调用方法 UserDao proxy = (UserDao) Proxy.newProxyInstance(ud.getClass() .getClassLoader(), ud.getClass().getInterfaces(), handler); proxy.add(); proxy.delete(); proxy.update(); proxy.find(); System.out.println("-----------"); StudentDao sd = new StudentDaoImpl(); MyInvocationHandler handler2 = new MyInvocationHandler(sd); StudentDao proxy2 = (StudentDao) Proxy.newProxyInstance(sd.getClass() .getClassLoader(), sd.getClass().getInterfaces(), handler2); proxy2.login(); proxy2.regist(); } }
public abstract class GetTime { // 需求:请给我计算出一段代码的运行时间 public long getTime() { long start = System.currentTimeMillis(); code(); long end = System.currentTimeMillis(); return end - start; } public abstract void code(); } //---------------------------------------------- public class IODemo extends GetTime{ @Override public void code() { try { BufferedInputStream bis = new BufferedInputStream( new FileInputStream("a.avi")); BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream("b.avi")); byte[] bys = new byte[1024]; int len = 0; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } catch (IOException e) { e.printStackTrace(); } } } //---------------------------------------------- public class GetTimeDemo { public static void main(String[] args) { // GetTime gt = new GetTime(); // System.out.println(gt.getTime() + "毫秒"); GetTime gt = new ForDemo(); System.out.println(gt.getTime() + "毫秒"); gt = new IODemo(); System.out.println(gt.getTime() + "毫秒"); } }
多态
public abstract class PersonDemo { public void show(){ System.out.println("开始运行: "); code(); System.out.println("运行结束"); } public abstract void code(); } //------------------------------------------ public class PersonDemoTest extends PersonDemo { @Override public void code() { System.out.println("运行中..."); } } //------------------------------------------ public class TestDemo { public static void main(String[] args) { //输出 //开始运行: //运行中... //运行结束 PersonDemo pd = new PersonDemoTest(); pd.show(); } }