静态语言 与 动态语言
动态语言:
- 运行时可以根据自身条件改变数据结构
- 动态语言举例:Object - c,JavaScript,C#,PHP,Python 等。
- eg(JavaScript):
静态语言:
- 运行时不可改变自身数据结构。
- 静态语言举例:Java,C,C++。
- Java不是动态语言,但Java是一门 “ 准动态语言 ” 。即可使用反射机制使Java获得类似于动态语言的特性。
Reflection(反射)
Reflection(反射)允许程序在执行期间借助于 Reflection API 获取任何类的内部信息,并能够直接操作任意对象的内部属性及方法。
Class c = Class.forName("java.lang.String");
在加载完类之后,会在堆内存的方法区生成一个Class类型的对象。这个Class对象包含了完整的类的结构信息。我们可以通过这个Class对象看到这个类的全部信息。这个Class对象就像是一面镜子,通过这个镜子看到这个类的结构。这个过程就是:Refletion(反射)
Reflection的优点和缺点:
- 优点:可以实现动态创建对象和编译,体现出很大的灵活性。
- 缺点:对性能有影响。反射是一种解释性操作,告诉JVM我们需要做什么。
Reflection主要API
Class c1 = Class.forName("FanShe.TestFS");
Class c2 = Class.forName("FanShe.TestFS");
System.out.println(c1);
System.out.println(c1.hashCode() == c2.hashCode());
- 一个类在内存中只有一个Class对象,及c1 == c2。
- 一个类在加载后,类的整个结构都会被封装在Class对象中。
Class类
简介:
- Class本身即是一个类。
- 每个类有且仅有一个Class对象,由系统生成。我们不能通过new去创建,只能通过方法获取。
- 一个Class类即对应了一个加载到JVM中的 .class 文件。
拥有Class对象的数据类型(基本所有类型都有):
Class API
获取当前 Class:
- Class c = Object.class;
Class c = TestFS.class;
- Class c = object.getClass();
TestFS testFS = new TestFS();
Class c4 = testFS.getClass();
- Class c = Class.forName(" 包名 . 类名");
Class c = Class.forName("FanShe.TestFS");
- 内置包装类特有:Class c = Object.Type;
Class c4 = Integer.TYPE;
获取父类Class:
Class getSuperClass();
class Person {
String name;
public Person(String name) {
this.name = name;
}
}
class Student extends Person {
public Student(String name) {
super(name);
}
}
public static void main(String[] args) {
Class c_student = Student.class;
Class c_person = Person.class;
System.out.println("Student类的父类为:" + c_student.getSuperclass());
System.out.println("Person类的父类为:" + c_person.getSuperclass());
}
获取类名:
- getName() 获得完整类名。(包名 + 类名)
- getSimpleName()获得简单类名。
System.out.println(c.getName());
System.out.println(c.getSimpleName());
获得属性(Field):
- getField() 获得public属性。
- getField(String name) 获得已知名字的public属性。
- getDeclaredField() 获得所有属性。
- getDeclaredField(String name) 获得已知名字的属性。
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println();
fields = c.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
获得方法(Method):
- getMethod() 获得本类及父类的全部 public 方法。
- getMethod(String name,Class 参数类型)获取指定方法。
- getDeclaredMethod()获取本类的全部方法。
- getDeclaredMethod(String name,Class 参数类型)获取指定方法。
因为有重载函数,所以在获取指定方法时,需要将参数类型传入。
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("\n");
methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println(c.getMethod("getName", null));
System.out.println(c.getMethod("setName", String.class));
获得构造器:
- getConstructor()获取 public 构造器。
- getConstructor(Class 参数类型)获取指定 public 构造器。
- getDeclaredConstructor()获取构造器。
- getDeclaredConstructor()获取指定构造器。
通过Class创造对象
- class . newInstance() 调用Class的无参构造方法。(没有就会抛异常)
Class c = Class.forName("TestNewObj.User");
User user = (User)c.newInstance(); //调用无参构造函数。
System.out.println(user);
- constructor . newInstance()通过获取的构造器,构造对象。
Constructor constructor = c.getDeclaredConstructor(String.class, int.class, int.class);
User user = (User)constructor.newInstance("杨然", 398, 20);
System.out.println(user);
通过获取的Method使用方法
- method . invoke(Object obj ,参数 ……)激活方法。
Method setName = c.getDeclaredMethod("setName", String.class);
setName.invoke(user,"YR");
开启 / 关闭安全检测(setAccessible)
- setAccessible(bool flag)设置无障碍。
- 对于Constructor,Method,Field。
- 如果为true,那么就可以访问 private 。
- 如果为false,则实施Java语言访问检测。
// Class 中name为私有属性。
private String name;
// 获取Field name,如需使用则需修改权限。
name.setAccessible(true);
通过获取Field操作属性
- field . set(Object object,参数)设置属性。
public属性:
Field name = c.getField("name");
name.set(user, "YR");
private属性:
Field name = c.getDeclaredField("name");
name.setAccessible(true);
name.set(user, "YR");
- field . get(Object object)获取属性值。(同样如果是private属性需要设置setAccessible(true)。
String str = (String)name.get(user);
创造对象性能对比
- 普通创建对象,并调用方法。
- 反射创建对象,并调用方法。
- 反射创建对象,设置Accessible,并调用方法。
public class TestXL {
public void test01() {
User user = new User();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方式执行1000000000次方法时间:" + (endTime - startTime));
}
public void test02() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class c = Class.forName("TestNewObj.User");
Constructor constructor = c.getDeclaredConstructor();
User user = (User) constructor.newInstance();
Method getName = c.getDeclaredMethod("getName");
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user);
}
long endTime = System.currentTimeMillis();
System.out.println("通过反射方式执行1000000000次方法时间:" + (endTime - startTime));
}
public void test03() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class c = Class.forName("TestNewObj.User");
Constructor constructor = c.getDeclaredConstructor();
User user = (User) constructor.newInstance();
Method getName = c.getDeclaredMethod("getName");
getName.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user);
}
long endTime = System.currentTimeMillis();
System.out.println("通过反射方式,并设置Accessible后,执行1000000000次方法时间:" + (endTime - startTime));
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
TestXL testXL = new TestXL();
testXL.test01();
testXL.test02();
testXL.test03();
}
}
获取方法参数,返回值,异常类型
参考函数:
public Map<String, Double> test01(Map<String, Integer> map, List<User> list, int num) throws ClassNotFoundException {
Class c = Class.forName("TestFX.TestFX");
return null;
}
- method . getGenericParameterTypes() 获取传参类型。
Method method01 = TestFX.class.getMethod("test01", Map.class, List.class, int.class);
Type[] genericParameterTypes = method01.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println(genericParameterType);
}
- method . getGenericExceptionTypes()获取抛出异常类型。
Method method01 = TestFX.class.getMethod("test01", Map.class, List.class, int.class);
Type[] genericExceptionTypes = method01.getGenericExceptionTypes();
for (Type genericExceptionType : genericExceptionTypes) {
System.out.println(genericExceptionType);
}
- method . getGenericReturnType()获取返回值类型。
Method method01 = TestFX.class.getMethod("test01", Map.class, List.class, int.class);
Type genericReturnType = method01.getGenericReturnType();
System.out.println(genericReturnType);
获取Type泛型的类型
- 先判断 type 是否是一个 参数化类型(ParameterizedType)。
- instanceof(实例):左边为对象,右边为类(接口)。如果该对象为该类的实例则为true,否则为false。
- 在将 type 强转为一个 ParameterizedType类型后,调用getActualTypeArguments()后返回一个Type [ ] ,即为该 type 的泛型类型
Method method01 = TestFX.class.getMethod("test01", Map.class, List.class, int.class);
Type[] genericParameterTypes = method01.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
if (genericParameterType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(genericParameterType + " " + actualTypeArgument);
}
}
}
获取注解及注解的传参
先创建注释与作用的类:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface db_Student{
String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface db_SX{
String name();
String type();
int length();
}
@db_Student("Student")
public class TestGetZJ {
@db_SX(name = "id",type = "char(10)",length = 10)
String id;
@db_SX(name = "name",type = "nchar(5)",length = 5)
String name;
@db_SX(name = "age",type = "int",length = 3)
int age;
}
获取类与属性的注解:
Class c = TestGetZJ.class;
Annotation[] annotations = c.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
System.out.println();
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
Annotation[] annotations1 = field.getAnnotations();
for (Annotation annotation : annotations1) {
System.out.println(annotation);
}
}
获取Annotation中传参的值:
Class c = TestGetZJ.class;
Field name = c.getDeclaredField("name");
db_SX annotation = name.getAnnotation(db_SX.class);
System.out.println(annotation.name());
System.out.println(annotation.type());
System.out.println(annotation.length());