Java基础_类的加载机制和反射
类的使用分为三个步骤:
类的加载->类的连接->类的初始化
一、类的加载
当程序运行的时候,系统会首先把我们要使用的Java类加载到内存中。这里加载的是编译后的.class文件
每个类加载到内存中,会创建一个对应的Class对象。这个Class对象保存了这个类有哪些成员(数据成员,方法成员)
注意:这里只有在某个Java类被使用的时候,才会被加载
加载时机:任何用到这个类的时候。(实例化,使用里面的静态静态成员....)
二、类加载器(JVM里面的一个东西)
作用:将.class文件(可能在磁盘上,也可能在网络上)加载到内存中,并生成与之对应的java.lang.Class对象。
分类:
Bootstrap ClassLoader 根类加载器 加载JRE中的核心类,比如java.lang.String 。。。
Extension ClassLoader 扩展类加载器 加载JRE中的扩展类
System ClassLoader 系统类加载器 一般用来加载我们自己写的类
三、反射
解释:在程序运行的时候,查看一个类有哪些信息(包含的数据成员和方法成员)。这个过程称之为反射。
如果我们知道我们要使用哪个类,那么我们只需要只用这个对应的类创建对象,然后就可以调用获取这个对象里面的数据和调用里面的方法。
(知道类,知道这个类里面有哪些属性和方法---->使用这个对象里面对应的属性和方法)
但是我们不知道我们要使用的是哪个类,这个时候我们需要使用反射获取到类的信息,里面有哪些成员,再使用。
(不知道---->获取类信息--->使用(实例化对象,调用属性和方法))反射
四、获取Class对象(反射的第一步)
方式一:通过对象获得
方式二:通过类获得
方式三:Class.forName("类路径")//必须传递完整路径(加上包名)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.Gary2; public class User { private int id; private String username; private String password; public User() {}; public User(int id,String username,String password) { this.id = id; this.username = username; this.password = password; } public void show(){ System.out.println(username+":"+password); } public void study() { System.out.println("学习"); } public void study(String courseName) { System.out.println("正在学习"+courseName); } }
方式一:通过对象获得
Class c1 = user1.getClass();
(通过User类获取到同一个User对象,一个类只能被加载一次,产生同一个User对象。)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.Gary2; public class GaryGetClass { public static void main(String[] args) { //获取Class对象 User user1 = new User(100,"Gary","123"); User user2 = new User(200,"Gary2","456"); //获得c1对象 Class c1 = user1.getClass(); System.out.println(c1); //获得c2对象 Class c2 = user2.getClass(); System.out.println(c2); //判断两个对象是不是一样的 System.out.println(c1 == c2); } }
方式二:通过类
Class c2 = user2.getClass();
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.Gary2; public class GaryGetClass { public static void main(String[] args) { //获取Class对象 User user1 = new User(100,"Gary","123"); User user2 = new User(200,"Gary2","456"); //获得c1对象 Class c1 = user1.getClass(); System.out.println(c1); //获得c2对象 Class c2 = user2.getClass(); System.out.println(c2); //通过类获得User对象 Class c4 = User.class; System.out.println(c4 == c1); } }
方式三:Class.forName("类路径")//必须传递完整路径(加上包名)
Class c5 = Class.forName("com.Gary2.User"); //一定要加上包名
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.Gary2; public class GaryGetClass { public static void main(String[] args) { //获取Class对象 User user1 = new User(100,"Gary","123"); User user2 = new User(200,"Gary2","456"); //获得c1对象 Class c1 = user1.getClass(); System.out.println(c1); //获得c2对象 Class c2 = user2.getClass(); System.out.println(c2); //通过类获得User对象 Class c4 = User.class; //Class,forName try { Class c5 = Class.forName("com.Gary2.User"); //一定要加上包名 System.out.println(c5 == c4); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
五、利用反射构造对象
从Class对象中获取信息
getConstructors();//获取所有public构造方法信息 getConstructor(Class<?> ... parameterTypes );//根据参数类型,获取指定参数类型的public构造方法 getDeclaredConstructor(Class<?> ... parameterTypes );//忽略访问权限,获取构造方法 getDeclaredConstructors();//忽略访问权限,获取构造方法
getFields();//获得某个类的所有的公共(public)的字段,包括父类中的字段。 getDeclaredFields();//获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。 getField();//设置公共全局变量 getDeclaredField;//仅能获取类本身的属性成员(包括私有、共有、保护)
getMethod();//获取当前类及所有继承的父类的public修饰的方法 getMethods();//获取所有公有方法 getDeclaredMethod();//该方法是获取本类以及父类或者父接口中所有的公共方法(public修饰符修饰的) getDeclaredMethods();//该方法是获取本类中的所有方法,包括私有的(private、protected、默认以及public)的方法。
Constructor成员: newInstance();//静态方法来实例化对象以便操作 setAccessible();//Accessable属性是继承自AccessibleObject 类. 功能是启用或禁用安全检查 ,提高java反射速度的方法method.setAccessible(true)