编程语言分为动态语言和静态语言。
动态语言是能在编写代码过程中,动态改变代码结构的语言。如 js ,py等等
静态语言则不能。如Java,C ,C++
虽然java不能像动态语言那么灵活,但是可以借助反射机制来增加其灵活性。可以称之为**“准动态语言”**
反射机制的功能是运行程序时借助Reflection API获取任何类的内部信息,并能直接操作任意对象的内部属性和方法。
反射这个概念是怎么来的?
加载完类后,在堆内存的方法区中产生了一个Class类型的对象,(一个类只有一个Class对象)。
在这个Class对象中包含了完成的类结构信息。这个Class对象就像是一面镜子Mirror一样,看到类的结构。故被称为 “反射”
//因为是不确定的类型 ,所以泛型用?表示
Class<?> aClass1 = Class.forName("com.ht.Reflection.Student");
System.out.println(aClass1);
// verify the Class Object is only
Class<?> aClass12 = Class.forName("com.ht.Reflection.Student");
Class<?> aClass13 = Class.forName("com.ht.Reflection.Student");
Class<?> aClass14 = Class.forName("com.ht.Reflection.Student");
//可以看到这里的hashcode是一致的。
System.out.println(aClass12.hashCode());
System.out.println(aClass13.hashCode());
System.out.println(aClass14.hashCode());
获取Class类型的三种方式:
//class属性的获取的三种方式
//直接通过类名的class来获取
System.out.println(Student.class);
//获取一个实例对象的getClass方法来获取
Student student = new Student();
System.out.println(student.getClass());
//通过反射,Class类
System.out.println(Class.forName("com.ht.Reflection.Student"));
为什么可以通过反射来获取Class呢?
看一下java内存分布就知道了
创建的对象和数组都存放在Class中,能被所有线程共享,都能拿到堆里面的Class类型。
类如何加载。
分成三个部分:加载,将class文件字节码加载到内存中,并将这些静态数据转换到方法区,然后生成一个代表这个类的java.lang.Class对象。
链接:将Java类的二进制代码合并到JVM的运行状态
初始化:有JVM来执行类构造器()方法,来构造类信息。其中将类变量的赋值动作和静态代码块中的语句合并产生。
类加载需要注意的点:
package com.ht.Reflection;
public class testInitial {
public static void main(String[] args) throws ClassNotFoundException {
System.out.println("Main类被初始化");
teacher tt = new teacher();
// 主动通过forname进行调用也能初始化类
Class.forName("com.ht.Reflection.teacher");
// 而通过new teacher数组的方式,则不会初始类
teacher[] teachers = new teacher[5]; //此时只有main类被加载了。
//通过类名调用静态变量,也不会引起类的初始化。
}
}
class person{
int id;
String name;
static {
System.out.println("Person类被初始化");
}
public person(){
System.out.println("Person类被初始化");
}
public person(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "person{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
class teacher extends person{
String career;
static {
System.out.println("Teacher类被初始化");
}
public teacher(){
System.out.println("Teacher类被初始化");
}
public teacher(int id, String name, String career) {
super(id, name);
this.career = career;
}
}
双亲委派机制的功能,确保系统内部类不被用户改写。
比如内部已有一个String类,用户再自定义了一个String类,在类加载的时候,会去父类中检查系统中是否有String类。(这里所谓的父类,是在类加载路径中查找)
通过Reflection机制来获取它的类名,字段,方法,父类等等信息。
其中获取字段的方法有两个,一个getDeclaredFields 和 getFields方法。
两者的区别就是:
getDeclaredFields能获取所有类型的字段,包括private修饰的字段。
而getFields和getFIeld方法只能获取public的字段。
Class<?> aClass = Class.forName("com.ht.Reflection.Student");
Field[] field = aClass.getFields();
for (Field ff : field) {
System.out.println(ff);
}
Field[] fields = aClass.getDeclaredFields();
for (Field fieldee : fields) {
System.out.println(fieldee);
}
获取它的方法:
Class<?> aClass = Class.forName("com.ht.Reflection.Student");
Method[] methods = aClass.getMethods();
for (Method method : methods) {
System.out.println("normal Methods: "+method);
}
Method[] declaredMethods = aClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
getMethods是获得本类极其父类的所有public方法。
getDeclaredMethods 获得本类所有类型的方法