一、Class类
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。
也就是说类或接口是java.lang.Class类的实例对象。
二、获取Class类的实例对象
public class ReflectDemo1 {
public static void main(String[] args){
//获取Class类的实例对象的方式一
Class c1 = MyClass.class;
//获取Class类的实例对象的方式二
MyClass mc = new MyClass();
Class c2 = mc.getClass();
//获取Class类的实例对象的方式三
try {
Class c3 = Class.forName("com.xiao.reflect.MyClass");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class MyClass{
}
c1、c2、c3称之为MyClass类的类类型,一个类只可能是Class类的一个实例对象,所以它们相等。
System.out.println(c1 == c2);
打印结果为true。
三、通过类的类类型创建该类的对象
public class ReflectDemo1 {
public static void main(String[] args){
//获取Class类的实例对象的方式一
Class c1 = MyClass.class;
//获取Class类的实例对象的方式二
MyClass mc = new MyClass();
Class c2 = mc.getClass();
//获取Class类的实例对象的方式三
Class c3 = null;
try {
c3 = Class.forName("com.xiao.reflect.MyClass");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//通过类类型(c1 or c2 or c3) 创建该类的对象
try {
MyClass myClass = (MyClass)c1.newInstance();//需要无参构造方法
myClass.show();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
class MyClass{
public void show(){
System.out.println("MyClass");
}
}
四、动态加载类
编译时刻加载类,是静态加载类;运行时刻加载类,是动态加载类。
Class.forName(“类的全路径”)不仅表示类该类的类类型,还表示了动态加载该类。
五、类的加载
当Java虚拟机要运行某个类时,如果该类还未被加载到内存当中,虚拟机则会通过加载,连接,初始化这三个步骤实现对这个类的
初始化。
加载:指将class文件读入内存。并创建一个Class对象。任何类被使用时,虚拟机都会建立一个Class对象。
连接:验证是否具有正确的内部结构,并和其它类协调一致,准备负责为类的静态成员分配内存,并设置默认初始化值。
初始化:创建对象。
六、类的初始化时机
1.创建类的实例
2.使用类的静态成员或对其赋值(或调用静态方法)
3.使用反射方式来强制创建某个类或接口对应的Class对象
4.初始化某个子类(它的父类全部都要先于子类初始化)
5.直接使用java.exe命令来运行某个主类
七、类加载器
负责将.class文件加载到内存当中,并生成对应的Class对象。
三种类的加载器:
1.Bootstrap ClassLoader 根类加载器 也称为引导类加载器,负责Java核心类的加载。
2.Extension ClassLoader 扩展类加载器。
3.System ClassLoader 系统类加载器。
八、反射
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
九、反射获取构造方法
public class ReflectDemo2 {
//反射获取构造方法
@Test
public void test_1() throws Exception{
//获取Person类的类类型
Class c = Person.class;
//获取构造方法
// p.getConstructors(); 获得权限为public的所有构造器
//获得指定的空参构造器
Constructor con1 = c.getConstructor();
//获得指定的有参构造器
Constructor con2 = c.getConstructor(String.class);
//运行空参构造
Person p1 = (Person) con1.newInstance();
//运行有参构造
Person p2 = (Person) con2.newInstance("笑笑");
}
}
class Person{
private String name;
//空参构造
public Person(){
System.out.println("我是Person类的空参构造");
}
//有参构造
public Person(String name) {
this.name = name;
System.out.println("我是Person类的有参构造");
}
}
十、反射获取成员变量
public class ReflectDemo3 {
//反射获取成员变量
@Test
public void test() throws Exception{
//获取Cart类的类类型
Class c = Class.forName("com.xiao.reflect.Cart");
//获取所有public的成员变量
c.getFields();
//获取所有成员变量 包括private
c.getDeclaredFields();
//获取指定的私有成员变量
c.getDeclaredField("name");
//获得指定的public的成员变量
Field field = c.getField("color");
//通过Cart的类类型 创建该类对象
Cart cart = (Cart) c.newInstance();
//修改指定的成员变量的值
field.set(cart,"yellow");
}
}
class Cart{
//私有成员变量
private String name;
//共有成员变量
public String color;
}
十一、反射获取成员方法
public class ReflectDemo4 {
//反射获取成员方法
@Test
public void test() throws Exception{
//获取Dog类的类型
Class c = Dog.class;
//获取所有public的成员方法,包括继承的
c.getMethods();
//获得指定的空参成员方法
Method say = c.getMethod("say");
//获得指定的有参成员方法
Method eat = c.getMethod("eat", String.class);
//使用Gog类的类类型创建其对象
Dog dog = (Dog)c.newInstance();
//运行空参成员方法
say.invoke(dog);
//运行有参成员方法
eat.invoke(dog,"骨头");
}
}
class Dog{
//空参成员方法
public void say(){
System.out.println("汪汪汪");
}
//有参成员方法
public void eat(String food){
System.out.println("吃"+food);
}
}
十二、泛型擦除
在Java中,编译后的字节码文件中是没有泛型的。
例:加了String类型的泛型的集合,添加整型的数据。
//伪泛型
@Test
public void test_2() throws Exception{
//创建了添加了String类型的泛型的集合
ArrayList<String> array = new ArrayList<>();
//获取集合ArrayList类的类类型
Class c = array.getClass();
//获取方法add
Method method = c.getMethod("add",Object.class);
//添加整形数据
method.invoke(array, 12);
method.invoke(array, 1222);
method.invoke(array, 1000);
System.out.println(array);
}