动态语言 VS 静态语言:
动态语言是一类在运行时可以改变其结构的语言,例如:新的函数对象甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化,通俗点说就是在运行时,代码可以根据某些条件改变自身结构,主要动态语言:Object-C.C#,JavaScript.PHP.Python等
静态语言与动态语言相对应的运行时结构不可改变的语言就是静态语言,如JAVA,C,C++
JAVA不是动态语言,但JAVA可以称之为"准动态语言”,即JAVA具有一定的动态性,我们可以利用反射机制获得类似动态语言的特性,JAVA的动态性让编程的时候更加灵活。
反射的概念:
Reflection[反射]是java被视为动态语言的关键反射机制,允许程序在执行期借助reflection API取得任何类的内部消息并能直接操作任意对象的内部属性及方法.
Class c=Class.forName("java.lang.String");
Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建,加载完之后再堆内存的方法,其中就产生了一个Class类型的对象,一个类只有一个Class对象,这个对象就包含了完整的类的结构信息,我们可以通过这个对象看到类的结构,这个对象就像一面镜子,透过这个镜子可以看到类的结构,所以我们形象的称之为反射.
反射机制所提供的功能:
反射的优/缺点:
优点:
可以实现动态创建对象和编译,体现出很大的灵活性.
缺点:
对性能有影响,使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么,并且他满足我们的要求,这类操作总是慢于直接执行相同的操作.
通过反射机制获取Class类:
Class.forName()方法:
1.是个静态方法 2.方法的参数是一个字符串 3.字符串需要的是一个完整的类名 4.完整类名必须带有包名
举例:
package Collections; import java.lang.annotation.*; public class reflect{ public static void main(String[]args) throws ClassNotFoundException { //创建多个Class对象,但它们都反射的类都是person类 Class class1=Class.forName("Collections.person"); System.out.println(class1); Class class2=Class.forName("Collections.person"); Class class3=Class.forName("Collections.person"); Class class4=Class.forName("Collections.person"); System.out.println(class1.equals(class2)); System.out.println(class2.equals(class3)); System.out.println(class3.equals(class4)); System.out.println(class1.hashCode()); System.out.println(class2.hashCode()); System.out.println(class3.hashCode()); System.out.println(class4.hashCode()); } }
输出:
class Collections.person true true true 363771819 363771819 363771819 363771819
通过比较class1-class4,以及输出他们的hashcode是完全相同的,这表明一个类只有一个Class对象,这个对象就包含了完整的类的结构信息。
Class类:
Class类的特点:
java有两种对象:实例对象和Class对象,其实我们的实例对象就通过Class对象来创建的每一个类都有一个Class对象,每当编译一个新类就产生一个Class对象。
1:Class本身也是一个类 2:Class对象只能由系统建立对象 3:一个加载的类在JVM中只会有一个Class实例 4:一个Class对象对应的是一个加载到JVM中的一个.class文件 5:每个类的实例都会记得自身是由那个Class实例所生成的 6:通过Class可以完整地得到一个类中的所有被加载的结构 7:Class类是Reflection的根源,针对任何你想动态加载,运行的类,唯有先获得相应的Class对象。
Class 没有公共构造方法
,Class 对象是在加载类时由Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象,也就是说,它并不能通过new的方式创建对象
虚拟机为每种类型管理一个独一无二的Class对象,也就是说,每个类(型)都有一个Class对象
,运行程序时,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载,如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。
getClass():
public final Class getClass()
以上的方法返回值的类型是一个Class类,此类是java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可实现通过对象反射求出类的名称。
package Collections; import java.lang.annotation.*; public class reflect{ public static void main(String[]args) throws ClassNotFoundException { Class class1=Class.forName("java.lang.Integer"); Class class2=Class.forName("java.util.Date"); Class class3=Class.forName("java.lang.String"); System.out.println(class1); System.out.println(class2); System.out.println(class3); System.out.println(class1.equals(class2)); System.out.println(class2.equals(class3)); System.out.println(class1.hashCode()); System.out.println(class2.hashCode()); System.out.println(class3.hashCode()); } }
输出:
class java.lang.Integer class java.util.Date class java.lang.String false false 363771819 2065951873 356573597
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象,每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和相同维数的数组都共享该 Class 对象,一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。
Class类常用的方法:
获取Class类的实例:
获得同一个Class对象的不同方法:
方式一:通过对象获得
类名.getClass();
方式二:通过forName获得
Class.forName("包名.类名");
方式3:通过类名.class获得
类名.class;
方式4:通过type属性获得[只能针对于基本内置类型的包装类]
基本内置类型.type;
获得父类类型:
Class类对象.getSuperclass();
举例:
package Collections; public class text1 { public static void main(String[]args) throws ClassNotFoundException { person1 person1=new Student(); System.out.println("这个人是:"+person1.name); Class c1=person1.getClass();//方式一:通过对象获得 System.out.println("c1的hashcode为:"+c1.hashCode()); Class c2=Class.forName("Collections.Student");//方式二:通过forName获得 System.out.println("c2的hashcode为:"+c2.hashCode()); Class c3=Student.class;//方式3:通过类名.class获得 System.out.println("c3的hashcode为:"+c3.hashCode()); System.out.println("c1和c2相等吗?"+c1.equals(c2)); System.out.println("c2和c3相等吗?"+c2.equals(c3)); System.out.println("c1和c3相等吗?"+c1.equals(c3)); Class c4=c1.getSuperclass(); System.out.println(c4); } } class person1{ public String name; public person1(String name) { this.name = name; } public person1() { } } class Student extends person1{ public Student() { this.name="学生"; } } class teacher extends person1{ public teacher() { this.name="老师"; } }
输出:
c1的hashcode为:2065951873 c2的hashcode为:2065951873 c3的hashcode为:2065951873 c1和c2相等吗?true c2和c3相等吗?true c1和c3相等吗?true class Collections.person1
通过输出结果,我们可以得出一个结论,无论使用上述三种不同方法中的哪一个均可获得同一个Class对象,即使c1/c2/c3为不同的Class对象,但他们的Class类是同一个。
那些类型可以有Class对象?
简单应用:
package Collections; import java.lang.annotation.ElementType; public class text1 { public static void main(String[]args){ Class c1=Object.class;//类 Class c2= Comparable.class;//接口 Class c3=String[].class;//一维数组 Class c4=int[][].class;//二维数组 Class c5=Override.class;//注解 Class c6= ElementType.class;//枚举 Class c7=Integer.class;//基本数据类型 Class c8=void.class;//void Class c9=Class.class;//class System.out.println(c1); System.out.println(c2); System.out.println(c3); System.out.println(c4); System.out.println(c5); System.out.println(c6); System.out.println(c7); System.out.println(c8); System.out.println(c9); //对于数组,只要元素类型和维度相同,那么就是同一个class int[] a=new int[10]; int[] b=new int[100]; System.out.println(a.getClass().hashCode()); System.out.println(b.getClass().hashCode()); } }
输出:
class java.lang.Object class Collections.Comparable class [Ljava.lang.String; class [[I interface java.lang.Override class java.lang.annotation.ElementType class java.lang.Integer void class java.lang.Class 363771819 363771819