第一部分:
类的加载机制:
1.new Person()加载到内存
2.Person.静态成员 加载到内存
class被加载到内存,那么class中的静态代码块就会被运行
3.创建了这个类的子类对象
4.使用反射技术调用这个类
5.直接在cmd中 (java 这个类)相当于运行这个类里面的main方法,也会加载进去。直接使用java.exe命令运行某个主类
第二部分:
类的加载器 ClassLoader,分为三类加载器
运行class,加载到内存,方法区
1.引导类加载器:BootClassLoder。负责加载JDK中的核心类库
jre/lib/rt.jar
2.扩展类加载器:ExtClassLoader
负责加载JDK的扩展类库
jre/lib/ext/
3.应用类加载器:AppClassLoader
加载我们自己写的类,或者是第三方jar包
第三部分:
获取类的加载器
public class MyClassLoader {
public static void main(String[] args) {
ClassLoader cl = String.class.getClassLoader();
System.out.println(cl);
}
}
输出的结果为null
这是因为类加载器是C++编写,根本和java无关,所以所有的核心类库是看不到的。
public class MyClassLoader {
public static void main(String[] args) {
//核心类库里面的类
ClassLoader cl = String.class.getClassLoader();
System.out.println(cl);
//扩展类
ClassLoader c1 = DNSNameService.class.getClassLoader();
System.out.println(c1);
//自己写的类
ClassLoader c2 = MyClassLoader.class.getClassLoader();
System.out.println(c2);
}
}
null
sun.misc.Launcher$ExtClassLoader@29453f44
sun.misc.Launcher$AppClassLoader@18b4aac2
第四部分:
双亲委派:
类加载器的特性:双亲委派,谁用谁加载
public class Test {
public static void main(String[] args) {
String s = "abc";
new Person();
}
}
java Test 运行此类,Test就要加载到内存中,App加载器加载到内存中!!
Test使用了String,道理上String是APP加载,但是APP加载任务交给他的双亲,交给Ext,Ext加载任务交给Boot加载器。
当遇到new Person()的时候,APP加载器不加载,把他交给Ext,Ext交给Boot加载器,Boot不管之后,App再加载。
第五部分:
class文件对象产生
APP加载器将class文件加载到方法区中,并且为这个class文件堆区中创建一个对象。
那么这个对象是怎么产生的呢?是由java.lang.class类产生的。
第六部分:
反射:
概念:将java代码的各个组成部分封装为其他对象,可以在程序运行的过程中操作这些对象,这就是java的反射机制。
一个类内部包含构造方法、成员变量、成员方法。所谓的反射技术,就是要打开这个类,可以直接拿取类内部的东西来使用,而不是像之前那样通过new对象来实现。拿到的构造方法为Constructor类(里面有newInstance来创建对象),拿到的成员变量为Field类(set()给变量赋值),拿到的成员方法为Method类(invoke()调用方法)。
那么如何打开class呢?其实就是获得class文件的对象。
第六部分:
获取class文件对象的三种方式
package reflect;
//1.对象方法getClass()获取 (getClass()定义在Object类)
//2.使用类的静态属性class获取
//3.Class类静态方法 forName()获取
//三个方法中第三个最常用,这个方法的扩展性最好,因为参数是字符串,字符串未必提前写好,数据源可以外来,通过IO读取
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException{
//1.对象方法getClass()获取
Student stu = new Student();
Class c1 = stu.getClass();
System.out.println(c1);
//2.使用类的静态属性class获取
//每一个数据类型,无论是基本还是引用类型,JVM赋予这个类型一个静态属性,名字就是class
Class c2 = Student.class;
System.out.println(c2);
System.out.println(c1==c2);
//3.Class类静态方法 forName()获取
//注意:字符串形式的类名,必须是全限定名 包名.类名
Class c3 = Class.forName("reflect.Student");
System.out.println(c3);
}
}
第七部分:
package reflect;
public class Student {
private String name;
private int age;
// static{
// System.out.println("静态代码块");
// }
public Student(){
}
public Student(String name, int age){
this.name = name;
this.age = age;
}
public void study(){
System.out.println("学生在学习");
}
public void eat(String s,double d){
System.out.println("带参数方法:" + s + "::" + d);
}
public String toString(){
return "Student{" + "name='" + name + '\'' + ",age=" + age + '}';
}
}
package reflect;
import java.lang.reflect.Constructor;
/**
* 反射技术:
* 1. 获取一个类class文件对象,获取到Class类的对象
* 2. Class类的对象中的方法,获取出类的成员(构造,变量,方法)
* 3. 运行获取出来的成员
*
* 反射案例一:
* 反射解剖,Student类,获取无参构造方法
* 运行无参数构造(对象创建)
*/
public class ReflectDemo2 {
public static void main(String[] args) throws Exception{
Class c = Class.forName("reflect.Student");
//获取Student类中的构造方法Class类的方法
//方法 getConstructors() 获取到类中所有公共权限的构造方法
//返回的是Constructor[]数组
// Constructor[] cons = c.getConstructors();
// for(Constructor con : cons){
// System.out.println(con);
// }
//只获取无参构造方法
Constructor con = c.getConstructor();
System.out.println(con);
//运行构造方法,创建对象,Constructor方法 Object newInstance(Object ...a) 传递实际参数
Object object = con.newInstance();
System.out.println(object);//打印对象时候,会自动调用类里面的toString方法
//以上代码的作用就相当于我new Student,但是这样就把代码写死了,采用这样方式,我只需要更换字符串,就可以建立出新的其他类的对象
}
}
第八部分:
package reflect;
import java.lang.reflect.Constructor;
/**
*反射案例2:
* 运行有参数构造(对象创建)
*/
public class ReflectDemo3 {
public static void main(String[] args) throws Exception{
Class c = Class.forName("reflect.Student");
//class方法,获取有参数的构造,String int
//传递构造方法参数列表中,数据类型的class文件对象 getConstructor(Class...p)
Constructor con = c.getConstructor(String.class,int.class);
System.out.println(con);
//运行构造方法,创建对象,Constructor方法 newInstance(传递构造方法实际参数 Object o)
Object object = con.newInstance("张三",20);
System.out.println(object);
}
}
第九部分:
package reflect;
/**
* 反射案例3:
* 反射获取Student类的无参构造方法执行
* 使用简单的方法,减少代码量
*
* 前提:
* 被反射的类,必须具备public权限的无参构造
*/
public class ReflectDemo4 {
public static void main(String[] args) throws Exception{
Class c = Class.forName("reflect.Student");
//Class类中,定义方法 Object newInstance() 运行无参数构造,创建对象
Object object = c.newInstance();
System.out.println(object);
}
}
第十部分:
package reflect;
import java.lang.reflect.Constructor;
/**
* 暴力反射:打破类的封装性
* 反射私有执行(不推荐使用)
*
* Constructor构造方法对象
* Field 成员变量对象
* Method 成员方法对象
*
* 共同继承父类 AccessibleObject
* 父类中定义方法 srtAccessible(true) 取消java的运行时期的安全检查
*/
public class ReflectDemo5 {
public static void main(String[] args) throws Exception{
Class c = Class.forName("reflect.Student");
//Class类的方法,获取Student类中的私有构造方法
//方法名字:getDeclaredConstructor()
Constructor con = c.getDeclaredConstructor(String.class);
con.setAccessible(true);
Object o = con.newInstance("张三");
System.out.println(o);
}
}
第十一部分:
package reflect;
import java.lang.reflect.Method;
/**
* 获取无参成员方法
* Method[] getMethods() 获取所有public修饰的成员方法,包括父类中
* Method getMethod("方法名",方法的参数类型...类型)
* 根据方法名和参数类型获得一个方法对象,只能获取public修饰的
*
* Method中常用方法
* Object invoke(Object obj,Object...args)
* 返回值Object 表示调用方法后,该方法的返回值
* 根据参数args调用对象obj的该成员方法
* 如果obj=null,则表示该方法为静态方法
*/
public class ReflectDemo6 {
public static void main(String[] args) throws Exception{
Class c = Class.forName("reflect.Student");
Object object = c.newInstance();
//获取study方法
Method method = c.getMethod("study");
//执行方法,传递对象
method.invoke(object);
//获得指定方法,eat
Method method1 = c.getMethod("eat",String.class,double.class);
//运行方法eat
method.invoke(object,"字符串",9.8);
}
}