类的加载过程
类的加载与ClassLoader的理解
public class Test05 { public static void main(String[] args) { A a = new A(); System.out.println(A.n); /** * 1.加载到内存,会产生一个类对应的Class对象 * 2.链接,链接结束后 n=0 * 3.初始化 * <clinit>() { n = 300; System.out.println("A类的静态代码块"); n = 100; * } * * n=100 * * * */ } } class A { static { n = 300; System.out.println("A类的静态代码块"); } static int n = 100; { System.out.println("A类的代码块"); } public A() { System.out.println("A类的构造方法"); } }
输出
A类的静态代码块 A类的代码块 A类的构造方法 100
什么时候会发生类的初始化
下面5种情况可以分别单独打开,练习一下
public class Test06 { static { System.out.println("Main类被加载"); } public static void main(String[] args) { //1.主动引用 // Son son = new Son(); //2.反射也会产生主动引用 // try { // Class.forName("kuangJava.reflects.Son"); // } catch (ClassNotFoundException e) { // e.printStackTrace(); // } //不会产生类的引用的方法 //3. // System.out.println(Son.b); //4. // Son[] sons = new Son[2]; //5. System.out.println(Son.M); } } class Father { static int b = 2; static { System.out.println("父类静态代码块"); } } class Son extends Father { static { System.out.println("子类静态代码块"); m = 300; } static int m = 100; static final int M = 1; }
输出
1. Main类被加载 父类静态代码块 子类静态代码块 2. Main类被加载 父类静态代码块 子类静态代码块 3. Main类被加载 父类静态代码块 2 4. Main类被加载 5. Main类被加载 1
类加载器的作用
类加载器的作用
类加载器作用是用来把类(class)装载进内存的。JVM规范定义了如下类型的类的加载器
public class Test07 { public static void main(String[] args) { //获取系统类加载器 ClassLoader classLoader = ClassLoader.getSystemClassLoader(); System.out.println(classLoader); //获取系统类加载器的父类加载器--》扩展类加载器 ClassLoader extendClassLoader = classLoader.getParent(); System.out.println(extendClassLoader); //获取扩展类加载器的父类加载器--》根加载器(C++) ClassLoader rootClassLoader = extendClassLoader.getParent(); System.out.println(rootClassLoader); try { //获取当前类是哪个加载器加载的 ClassLoader classLoader1 = Class.forName("kuangJava.reflects.Test07").getClassLoader(); System.out.println(classLoader1); //获取JDK内置的类是哪个加载器加载的 ClassLoader classLoader2 = Class.forName("java.lang.Object").getClassLoader(); System.out.println(classLoader2); } catch (ClassNotFoundException e) { e.printStackTrace(); } //如何获取系统类加载器的加载路径 //System.out.println(System.getProperty("java.class.path")); /** * D:\software\Java\jdk1.8.0_241\jre\lib\charsets.jar * D:\software\Java\jdk1.8.0_241\jre\lib\deploy.jar * D:\software\Java\jdk1.8.0_241\jre\lib\ext\access-bridge-64.jar * D:\software\Java\jdk1.8.0_241\jre\lib\ext\cldrdata.jar * D:\software\Java\jdk1.8.0_241\jre\lib\ext\dnsns.jar * D:\software\Java\jdk1.8.0_241\jre\lib\ext\jaccess.jar * D:\software\Java\jdk1.8.0_241\jre\lib\ext\jfxrt.jar * D:\software\Java\jdk1.8.0_241\jre\lib\ext\localedata.jar * D:\software\Java\jdk1.8.0_241\jre\lib\ext\nashorn.jar * D:\software\Java\jdk1.8.0_241\jre\lib\ext\sunec.jar * D:\software\Java\jdk1.8.0_241\jre\lib\ext\sunjce_provider.jar * D:\software\Java\jdk1.8.0_241\jre\lib\ext\sunmscapi.jar * D:\software\Java\jdk1.8.0_241\jre\lib\ext\sunpkcs11.jar * D:\software\Java\jdk1.8.0_241\jre\lib\ext\zipfs.jar * D:\software\Java\jdk1.8.0_241\jre\lib\javaws.jar * D:\software\Java\jdk1.8.0_241\jre\lib\jce.jar * D:\software\Java\jdk1.8.0_241\jre\lib\jfr.jar * D:\software\Java\jdk1.8.0_241\jre\lib\jfxswt.jar * D:\software\Java\jdk1.8.0_241\jre\lib\jsse.jar * D:\software\Java\jdk1.8.0_241\jre\lib\management-agent.jar * D:\software\Java\jdk1.8.0_241\jre\lib\plugin.jar * D:\software\Java\jdk1.8.0_241\jre\lib\resources.jar * D:\software\Java\jdk1.8.0_241\jre\lib\rt.jar * D:\IdeaProjects\mystudy\target\classes * D:\mavenRepository\org\apache\httpcomponents\httpclient\4.5.12\httpclient-4.5.12.jar * D:\mavenRepository\org\apache\httpcomponents\httpcore\4.4.13\httpcore-4.4.13.jar * D:\mavenRepository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar * D:\mavenRepository\commons-codec\commons-codec\1.11\commons-codec-1.11.jar * D:\mavenRepository\org\apache\poi\poi\4.1.2\poi-4.1.2.jar * D:\mavenRepository\org\apache\commons\commons-collections4\4.4\commons-collections4-4.4.jar * D:\mavenRepository\org\apache\commons\commons-math3\3.6.1\commons-math3-3.6.1.jar * D:\mavenRepository\com\zaxxer\SparseBitSet\1.2\SparseBitSet-1.2.jar * D:\mavenRepository\org\apache\poi\poi-ooxml\4.1.2\poi-ooxml-4.1.2.jar * D:\mavenRepository\org\apache\poi\poi-ooxml-schemas\4.1.2\poi-ooxml-schemas-4.1.2.jar * D:\mavenRepository\org\apache\xmlbeans\xmlbeans\3.1.0\xmlbeans-3.1.0.jar * D:\mavenRepository\org\apache\commons\commons-compress\1.19\commons-compress-1.19.jar * D:\mavenRepository\com\github\virtuald\curvesapi\1.06\curvesapi-1.06.jar * D:\mavenRepository\com\alibaba\fastjson\1.2.73\fastjson-1.2.73.jar * D:\mavenRepository\commons-io\commons-io\2.8.0\commons-io-2.8.0.jar * D:\software\ideaIU-2019.3.3.win\lib\idea_rt.jar */ } }
输出
sun.misc.Launcher$AppClassLoader@18b4aac2 sun.misc.Launcher$ExtClassLoader@355da254 null sun.misc.Launcher$AppClassLoader@18b4aac2 null
获取运行时类的完整结构
通过反射获取运行时类的完整结构
Field Method Construtor Superclass Interface Annotation
public class Test08 { public static void main(String[] args) { try { Class<?> c1 = Class.forName("kuangJava.reflects.User"); //获取类的名字 System.out.println(c1.getName()); System.out.println(c1.getSimpleName()); System.out.println("========"); //获取类的属性 //--只能找到public属性 Field[] fields = c1.getFields(); //--找到全部的属性 fields = c1.getDeclaredFields(); for (Field field : fields) { System.out.println(field); } //--获得指定属性的值 Field nameField = c1.getDeclaredField("name"); System.out.println(nameField); //获得类的方法 //--获取本类及其父类的全部public方法 Method[] methods = c1.getMethods(); for (Method method : methods) { System.out.println("===getMethods==="+method); } methods = c1.getDeclaredMethods(); for (Method method : methods) { System.out.println("===getDeclaredMethods==="+method); } //--获得指定的方法 Method getName = c1.getDeclaredMethod("getName", null); Method setName = c1.getDeclaredMethod("setName", String.class); System.out.println(getName); System.out.println(setName); //获取指定的构造器 Constructor<?>[] constructors = c1.getConstructors(); for (Constructor<?> constructor : constructors) { System.out.println("===getConstructors==="+constructor); } constructors = c1.getDeclaredConstructors(); for (Constructor<?> constructor : constructors) { System.out.println("===getDeclaredConstructors==="+constructor); } //获取指定构造器 Constructor<?> declaredConstructor = c1.getDeclaredConstructor(int.class, String.class); System.out.println("指定构造器:"+declaredConstructor); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } } class User { private int id; private String name; public User() { } public User(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } private void test() { } }
输出
kuangJava.reflects.User User ======== private int kuangJava.reflects.User.id private java.lang.String kuangJava.reflects.User.name private java.lang.String kuangJava.reflects.User.name ===getMethods===public java.lang.String kuangJava.reflects.User.getName() ===getMethods===public int kuangJava.reflects.User.getId() ===getMethods===public void kuangJava.reflects.User.setName(java.lang.String) ===getMethods===public void kuangJava.reflects.User.setId(int) ===getMethods===public final void java.lang.Object.wait() throws java.lang.InterruptedException ===getMethods===public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException ===getMethods===public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException ===getMethods===public boolean java.lang.Object.equals(java.lang.Object) ===getMethods===public java.lang.String java.lang.Object.toString() ===getMethods===public native int java.lang.Object.hashCode() ===getMethods===public final native java.lang.Class java.lang.Object.getClass() ===getMethods===public final native void java.lang.Object.notify() ===getMethods===public final native void java.lang.Object.notifyAll() ===getDeclaredMethods===public java.lang.String kuangJava.reflects.User.getName() ===getDeclaredMethods===public int kuangJava.reflects.User.getId() ===getDeclaredMethods===public void kuangJava.reflects.User.setName(java.lang.String) ===getDeclaredMethods===private void kuangJava.reflects.User.test() ===getDeclaredMethods===public void kuangJava.reflects.User.setId(int) public java.lang.String kuangJava.reflects.User.getName() public void kuangJava.reflects.User.setName(java.lang.String) ===getConstructors===public kuangJava.reflects.User() ===getConstructors===public kuangJava.reflects.User(int,java.lang.String) ===getDeclaredConstructors===public kuangJava.reflects.User() ===getDeclaredConstructors===public kuangJava.reflects.User(int,java.lang.String) 指定构造器:public kuangJava.reflects.User(int,java.lang.String)
有了Class对象,能做什么?
思考:难道没有无参的构造器就不能创建对象了吗?只要在操作的时候明确的调用类中的构造器,并将参数传递进去之后,才可以实例化操作。
步骤如下:
调用指定的方法
通过反射,调用类中的方法,通过Method类实现
Object invoke(Object obj, Object... args)
setAccessible
public class Test09 { public static void main(String[] args) { try { //获取Class对象 Class c1 = Class.forName("kuangJava.reflects.User"); //1.构造一个对象(本质是调用了类的无参构造器) // User user = (User) c1.newInstance(); // System.out.println(user); //2.通过构造器创建对象 // Constructor constructor = c1.getDeclaredConstructor(int.class, String.class); // User user2 = (User) constructor.newInstance(18, "zyy"); // System.out.println(user2); //3.通过反射调用普通方法 User user3 = (User) c1.newInstance(); //通过反射获取一个方法 Method setName = c1.getDeclaredMethod("setName", String.class); //invoke :激活的意思 (对象, "方法的值") setName.invoke(user3, "zyy"); System.out.println(user3.getName()); //反射静态方法 Method print = c1.getDeclaredMethod("print", String.class); print.invoke(null, "hello"); //4.通过反射操作属性 User user4 = (User) c1.newInstance(); Field name = c1.getDeclaredField("name"); //不能直接操作私有属性,我们需要关闭程序的安全监测,属性或者方法的setAccessible(true) name.setAccessible(true); name.set(user4, "zyy2"); System.out.println(user4.getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } } } class User { private int id; private String name; public User() { } public User(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } private void test() { } public static void print (String msg) { System.out.println("print:"+msg); } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; } }
public class Test10 { /** * 普通方法 */ public static void normalWay() { User user = new User(); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { user.getName(); } long endTime = System.currentTimeMillis(); System.out.println("普通方法执行10亿次用时:" + (endTime - startTime) + "ms"); } /** * 反射 */ public static void reflectWay() { try { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getDeclaredMethod("getName", null); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { getName.invoke(user, null); } long endTime = System.currentTimeMillis(); System.out.println("反射方法执行10亿次用时:" + (endTime - startTime) + "ms"); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } /** * 反射,关闭安全校验 */ public static void reflectWay2() { try { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getDeclaredMethod("getName", null); getName.setAccessible(true); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { getName.invoke(user, null); } long endTime = System.currentTimeMillis(); System.out.println("反射方法(关闭校测)执行10亿次用时:" + (endTime - startTime) + "ms"); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } public static void main(String[] args) { normalWay(); reflectWay(); reflectWay2(); } }
输出
普通方法执行10亿次用时:5ms 反射方法执行10亿次用时:3096ms 反射方法(关闭校测)执行10亿次用时:1300ms
反射操作泛型
public class Test11 { public void test01(Map<String, User> map, List<User> list) { System.out.println("test01"); } public Map<String, User> test02() { System.out.println("test02"); return null; } public static void main(String[] args) { try { System.out.println("打印test01方法形参的泛型"); Method method = Test11.class.getDeclaredMethod("test01", Map.class, List.class); Type[] genericParameterTypes = method.getGenericParameterTypes(); for (Type genericParameterType : genericParameterTypes) { System.out.println("#"+genericParameterType); if (genericParameterType instanceof ParameterizedType) { Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } System.out.println("打印test02返回值的泛型"); method = Test11.class.getDeclaredMethod("test02"); Type genericReturnType = method.getGenericReturnType(); System.out.println("#"+genericReturnType); if (genericReturnType instanceof ParameterizedType) { Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } catch (NoSuchMethodException e) { e.printStackTrace(); } } }
输出
打印test01方法形参的泛型 #java.util.Map<java.lang.String, kuangJava.reflects.User> class java.lang.String class kuangJava.reflects.User #java.util.List<kuangJava.reflects.User> class kuangJava.reflects.User 打印test02返回值的泛型 #java.util.Map<java.lang.String, kuangJava.reflects.User> class java.lang.String class kuangJava.reflects.User
反射操作注解
public class Test12 { public static void main(String[] args) { //通过反射获取注解 Class c1 = Student2.class; Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); //获取注解的value的值 if (annotation instanceof TableStudent) { TableStudent tableStudent = (TableStudent)annotation; System.out.println(tableStudent.value()); } } //获得类指定的注解 try { Field id = c1.getDeclaredField("name"); FieldStudent annotation = id.getAnnotation(FieldStudent.class); System.out.println(annotation.columnName()); System.out.println(annotation.length()); System.out.println(annotation.type()); } catch (NoSuchFieldException e) { e.printStackTrace(); } /*Field[] declaredFields = c1.getDeclaredFields(); for (Field declaredField : declaredFields) { FieldStudent annotation = declaredField.getAnnotation(FieldStudent.class); System.out.println(annotation.columnName()); System.out.println(annotation.length()); System.out.println(annotation.type()); }*/ } } /** * 属性的注解 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface FieldStudent { String columnName(); String type(); int length(); } /** * 类名的注解 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface TableStudent { String value(); } @TableStudent("t_student") class Student2 { @FieldStudent(columnName = "id", type = "int", length = 30) private int id; @FieldStudent(columnName = "name", type = "varchar", length = 20) private String name; @FieldStudent(columnName = "age", type = "int", length = 3) private int age; public Student2() { } public Student2(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student2{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
输出
@kuangJava.reflects.TableStudent(value=t_student) t_student name 20 varchar