Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类。Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建。
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。
虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每个类(型)都有一个Class对象。运行程序时,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。
每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。
String s = "aaa"; //1获取字节码对象 Class cla1 = s.getClass(); //2 根据类获取 Class cla2 = String.class; //3 常用 根据字符名 Class cla3 = Class.forName("java.lang.String");
一个类只对应一个Class对象:包括 基本数据类型,对象和接口,数组,void,枚举,注解 真对维度而不是长度
例如 int[] arr1 = new int[4]; int[] arr2 = new int[10]; class相同
int[] arr1 = new int[4]; int[][] arr2 = new int[10][2]; class不相同
@SuppressWarnings("all") public class ClassTest { public static void main(String[] args) throws Exception { Class<User> userClass = (Class<User>) Class.forName("reflex.User"); System.out.println(userClass.getName());//包名加类名 System.out.println(userClass.getSimpleName()); Field[] fields1 = userClass.getFields();//获取public的属性 Field field = userClass.getDeclaredField("name"); Field[] fields = userClass.getDeclaredFields();//获取所有属性包括private for (Field temp : fields) { System.out.println(temp); } Method []method = userClass.getDeclaredMethods();//获取所有方法 Method method1 = userClass.getDeclaredMethod("getName", null); Method method2 = userClass.getDeclaredMethod("setName", String.class); System.out.println(method1); Constructor[] constructors = userClass.getDeclaredConstructors();//获取所有构造器 //利用反射创建对象 User u = userClass.newInstance();//调用的是user的无参构造器 Constructor<User> c = userClass.getConstructor(int.class,String.class); User u2 = c.newInstance(100,"张三"); //利用反射调用方法 Method method3 = userClass.getDeclaredMethod("setName", String.class); method3.invoke(u2,"张三"); //利用反射操作属性 Field field1 = userClass.getDeclaredField("name"); field1.setAccessible(true);//如果是私有变量,允许访问,不做安全检查 field1.set(u2, "张三"); } }
/** * 动态编译 * @author Administrator * */ public class DynamicComplieTest { public static void main(String[] args) { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); int result = compiler.run(null, null, null, ".java文件的路径"); System.out.println(result==0?"编译成功":"编译失败"); //通过反射调用main URL [] urls = new URL[]{ new URL(".java文件路径")}; URLClassLoader loader = new URLClassLoader(urls); Class c = loader.loadClass("myjava"); Method m = c.getMethod("main",String[].class ); m.invoke(null, (Object)new String[]{}); } }
/** * java执行js 第三方实现rhino * @author Administrator * */ public class JavaScriptTest { public static void main(String[] args) throws Exception { //获取脚本引擎对象 ScriptEngineManager sem = new ScriptEngineManager(); ScriptEngine engine = sem.getEngineByName("javascript"); //在java js中都能获取到 engine.put("msg", "hello word"); engine.get("msg"); engine.eval("javascript代码"); //定义函数 engine.eval("function add(a,b){var sum = a+b;return sum;}"); Invocable invocable = (Invocable)engine; Object sum = invocable.invokeFunction("add", new Object[]{13,20}); System.out.println(sum); //执行一个js文件放到src下 URL url = JavaScriptTest.class.getClassLoader().getResource("a.js"); FileReader reader = new FileReader(url.getPath()); engine.eval(reader); reader.close(); } }
类加载器层次结构
引导类加载器 (最上层)C++,用来加载java的核心库
扩展类加载器 用来加载java的扩展库
应用程序类加载器
自定义类加载器
类加载器的代理模式
代理模式 交给其他加载器加载指定的类
双亲委托机制 委托给父类加载器
自定义类加载器
/** * 自定义文件系统类加载器 * @author Administrator * */ public class FileSystemClassLoader extends ClassLoader{ private String rootDir; public FileSystemClassLoader(String rootDir) { this.rootDir = rootDir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class c= findLoadedClass(name); if(c!=null){ return c; }else{ ClassLoader parent = this.getParent(); c = parent.loadClass(name);//为派给父类加载 if(c!=null){ return c; }else{ byte [] classData = getClassData(name); if(classData==null){ throw new ClassNotFoundException(); }else{ c = defineClass(name,classData, 0,classData.length); } } } return c; } private byte[] getClassData(String name) { String path = rootDir = "/"+name.replace(".", "/");//com.aa转成d:/aa.class InputStream is = null; ByteArrayOutputStream os = new ByteArrayOutputStream(); try { is = new FileInputStream(path); } catch (FileNotFoundException e) { e.printStackTrace(); } byte [] buffer = new byte[1024]; int temp =0; try { while((temp=is.read(buffer))!=-1){ os.write(buffer, 0, temp); } } catch (IOException e) { e.printStackTrace(); } return os.toByteArray(); } }
不同类加载器加载的类不相同
线程类加载器为了抛弃双亲委托机制
Thread.currentThread().setContextClassLoader(class);
OSGI 面向java的动态模块系统,谁定义就由谁加载
eclipse基于OSGI构建的,Equinox OSGI的实现
public class Fs1 { public static void main(String[] args) throws Exception { Class<?> c = Class.forName("fanshe.User"); System.out.println(c.getName());//获取类的全称 System.out.println(c.getSimpleName());//获取类的简称 User u1 = (User) c.newInstance();//通过反射创建对象 System.out.println(u1.getId()); Constructor con = c.getConstructor();//无参构造方法 User u2 = (User) con.newInstance();//通过反射构造方法创建对象 System.out.println(u2.getId()); Field f = c.getDeclaredField("name");//获取字段 DeclaredField包括私有 f.setAccessible(true);//设置可以调用私有属性 System.out.println(f.get(u2)); Method m = c.getDeclaredMethod("setName", String.class); Object o = m.invoke(u2, "张三");//调用方法 System.out.println(u2.getName()); System.out.println(o); } }