Java反射——反射机制问题——第一章
Java反射——Class类——第二章
Java反射——类加载——第三章
Java反射——反射获取类的结构信息——第四章
1:Class类基本介绍
-
Class也是类,因此也继承Object类
-
Class类对象不是new出来的,而是系统创建的
如下代码演示,可以在7,12行分别进行断点调试,可以追到ClassLoader加载器中的loadClass方法
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
//2. Class类对象不是new出来的,而是系统创建的
//(1)传统new对象
// public Class<?> loadClass(String name) throws ClassNotFoundException {
// return loadClass(name, false);
// }
7 People people = new People();
//(2) 反射方式
// public Class<?> loadClass(String name) throws ClassNotFoundException {
// return loadClass(name, false);
// }
12 Class<?> cls = Class.forName("com.class_.Class01");
-
对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
在第二点中,我们如果没有注释掉第7行的代码,那么我们在第12行进行断点调试,就不会追到ClassLoader加载器中的loadClass方法,因为对于某个类的Class类对象,在内存中只有一份,因为类只加载一次。 -
每个类的实例都会记得自己是由哪个Class实例所生成
-
通过Class对象可以完整地得到一个类的完整结构,通过一系列API
-
Class对象是存放在堆的
-
类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括方法代码,变量名, 方法名,访问权限等等)
当我们类加载完成以后,除了会在堆生成class类对象,在方法区还会生成class类的字节码二进制数据,方法区会引用到class类对象
2:Class常用方法演示
代码演示
public class Class02 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
String name="com.reflection.People";
//<?> 表示不确定的Java类型
//1:获取到People类,对应的Class对象
Class<?> cls = Class.forName(name);
//2:输出cls
System.out.println(cls);//class com.reflection.People 显示class对象,是哪个类的class对象
System.out.println(cls.getClass());//class java.lang.Class 输出cls运行实例
//3:通过cls创建对象实例
Object o = cls.newInstance();
System.out.println(o);
Field name1 = cls.getField("name");
System.out.println(name1.get(o));
name1.set(o,"zlj");
System.out.println(name1.get(o));
//4:得到类的名字
System.out.println(cls.getName());
//5:获取类加载器
System.out.println(cls.getClassLoader());
//6:获取所有的属性(字段),同理也可以获取所有的构造器和方法
Field[] fields = cls.getFields();
for (Field f:fields){
System.out.println(f.getName());
}
// Constructor<?>[] constructors = cls.getConstructors();
// for (Constructor constructor:constructors){
// System.out.println(constructor.getName());
// }
// Method[] methods = cls.getMethods();
// for (Method method:methods){
// System.out.println(method.getName());
// }
}
}
People .java
public class People {
public String name="zlj";
public String age="zlj";
public String sum="zlj";
public People(){
this.name="zzg";
}
public People(String name){
this.name=name;
}
public void hi(){
// System.out.println("hi"+name);
}
public void cry(){
System.out.println("cry"+name);
}
}
演示
class com.reflection.People
class java.lang.Class
com.reflection.People@677327b6
zzg
zlj
com.reflection.People
sun.misc.Launcher$AppClassLoader@18b4aac2
name
age
3:获取Class对象的6种方式
在程序运行的不同阶段,我们可以使用不同的方法来获取Class对象
如下图,在代码/编译阶段,我们可以使用Class.forName();在Class加载阶段,我们可以使用类.class;在Runtime运行阶段,我们可以使用对象.getClass();在反射的时候,我们可以通过类加载器得到class对象
- 前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException,
实例: Class cls1 =Class.forName( “java.lang.People” );
应用场景:多用于配置文件,读取类全路径,加载类.
- 前提:若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能最高
实例: Class cls2 = Cat.class;
应用场景:多用于参数传递,比如通过反射得到对应构造器对象.
- 前提:已知某个类的实例,调用该实例的getClass(方法获取Class对象,
实例:Class clazz =对象.getClass();//运行类型
应用场景:通过创建好的对象,获取Class对象.
- 通过类加载获取class对象
实例:
ClassLoader cl =对象.getClass().getClassLoader();
Class clazz4 = cl.loadClass( "类的全类名”);
- 基本数据(int, char, boolean,float,double,byte,long,short)按如下方式得到Class类对象
实例:Class cls =基本数据类型.class
- 基本数据类型对应的包装类,可以通过.TYPE得到Class类对象
实例:Class cls =包装类.TYPE
如下对上面的六种方法进行代码演示
public class GetClass_6 {
public static void main(String[] args) throws ClassNotFoundException {
//1:前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
Class<?> cls1 = Class.forName("com.reflection.People");
System.out.println(cls1);
//2.前提:若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能最高实例:
Class cls2= People.class;
System.out.println(cls2);
//3.前提:已知某个类的实例,调用该实例的getClass(方法获取Class对象,
People people = new People();
Class<? extends People> cls3 = people.getClass();
System.out.println(cls3);
//4.前提:通过类加载获取class对象
//1).先得到类加载器people
ClassLoader classLoader = people.getClass().getClassLoader();
//2).通过类加载器得到class对象
Class<?> cls4 = classLoader.loadClass("com.reflection.People");
System.out.println(cls4);
//cls1 cls2 cls3 cls4是同一个对象
//5.基本数据(int, char, boolean,float,double,byte,long,short)按如下方式得到Class类对象
System.out.println(int.class);
System.out.println(char.class);
//6. 基本数据类型对应的包装类,可以通过.TYPE得到Class类对象
System.out.println(Integer.TYPE);
System.out.println(Character.TYPE);
}
}
4:那些类型有Class对象
我们来梳理一下,在Java中那些类有Class对象
如下类型有Class对象
-
外部类,成员内部类,静态内部类,局部内部类,匿名内部类
-
interface :接口
-
数组
-
enum: 枚举
-
annotation :注解
-
基本数据类型
-
void
AllTypeClass .java
public class AllTypeClass {
public static void main(String[] args) {
Class<String> cls1 = String.class;//外部类
Class<Serializable> cls2 = Serializable.class;//接口类
Class<float[][]> cls3 = float[][].class;//二维数组
Class<int[]> cls4 = int[].class;//一维数组
Class<Deprecated> cls5 = Deprecated.class;//注解
Class<Thread.State> cls6 = Thread.State.class;//枚举
Class<String> cls7 = String.class;//基本数据类型
Class<Void> cls8 = void.class;;//void
System.out.println(cls1);
System.out.println(cls2);
System.out.println(cls3);
System.out.println(cls4);
System.out.println(cls5);
System.out.println(cls6);
System.out.println(cls7);
System.out.println(cls8);
}
}
class java.lang.String
interface java.io.Serializable
class [[F
class [I
interface java.lang.Deprecated
class java.lang.Thread$State
class java.lang.String
void