标签:创建对象 接口 getc mem 简单 自定义 反射 generic voc
考虑到有部分大学java课程中没有收录该部分内容,因此作为一个简短的介绍。
众说周知,java代码的编译是编译为.class文件,.class文件是运行在jvm上的,而并不是像C\C++语言一样,编译为二进制语言,运行在真实的操作系统上。即然,.class文件还处于jvm中,那么就能够从其中获取信息。
JAVA反射机制是在运行状态中,对于任何一个类,都能够知道这个类的所有属性和方法;对于任何一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。
因为有反射技术的存在,也使得java这种静态语言有了动态语言的特性。
/**
* 实体类
*/
class User {
private String name;
private int id;
private int age;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
public User() {
}
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//该方式适用于知道类的包名和类名,并且未创建过对象时使用
Class clazz2 = Class.forNam("com.xgp.company.reflection.User");
User user1 = new User();
//该方式适用于已经创建了对象时使用
Class clazz2 = user1.getClass();
//该方式适用于未创建对象,知道类名时使用
Class clazz3 = User.class;
三种方式创建对象的截图如下:
System.out.println(clazz.getName());
运行结果:
com.xgp.company.reflection.User
System.out.println(clazz.getSimpleName());
运行结果:
User
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
运行结果为空,解释见后小节的暴力反射
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
运行结果:
public java.lang.String com.xgp.company.reflection.User.toString()
public java.lang.String com.xgp.company.reflection.User.getName()
public int com.xgp.company.reflection.User.getId()
public void com.xgp.company.reflection.User.setName(java.lang.String)
public void com.xgp.company.reflection.User.setId(int)
public void com.xgp.company.reflection.User.setAge(int)
public int com.xgp.company.reflection.User.getAge()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
运行结果:
public java.lang.String com.xgp.company.reflection.User.toString()
public java.lang.String com.xgp.company.reflection.User.getName()
public int com.xgp.company.reflection.User.getId()
public void com.xgp.company.reflection.User.setName(java.lang.String)
public void com.xgp.company.reflection.User.setId(int)
public void com.xgp.company.reflection.User.setAge(int)
public int com.xgp.company.reflection.User.getAge()
对于上面一节中,获取User类中的对象时,程序运行的结果为空,原因是User对象的三个属性都为私有属性。若想使用反射技术获取对象的私有属性则需要使用clazz.getDeclaredFields()方法进行暴力获取。
//暴力反射
fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
输出结果为:
private java.lang.String com.xgp.company.reflection.User.name
private int com.xgp.company.reflection.User.id
private int com.xgp.company.reflection.User.age
演示前先获取到一个User类的class对象:
Class<User> clazz = User.class;
//构造一个对象
User user = clazz.newInstance();
System.out.println(user);
//通过构造器创建对像
Constructor<User> constructor = clazz.getDeclaredConstructor(String.class, int.class, int.class);
User user = constructor.newInstance("xgp", 001, 18);
System.out.println(user);
clazz.getDeclaredConstructor() 获取有参构造器,其参数传递的是反射对象有参构造器的各个参数的类的class对象
clazz.newInstance() 该函数用于使用构造器创建对象
//通过反射调用普通方法
User user = clazz.newInstance();
Method setName = clazz.getDeclaredMethod("setName", String.class);
setName.invoke(user,"xgp"); //激活
System.out.println(user);
其中invoke()函数用于激活反射获取到的方法,激活后才能使用反射获取到的方法。
//通过反射操作属性
User user = clazz.newInstance();
Field name = clazz.getDeclaredField("name");
name.setAccessible(true); //关闭权限检测
name.set(user,"xgp");
System.out.println(user);
特别注意的一点就是,在操纵私有属性时,一定得关闭权限检测,关闭权限检测反射函数的执行效率也跟高,这在下一节将会进行实验。关闭权限检测的代码为:
name.setAccessible(true); //关闭权限检测
下面进行三种方法调用的性能对比,通过调用user对象的getName()方法执行十亿次进行实验:
//普通方式
public static void test01() {
User user = new User();
long start = System.currentTimeMillis();
for(int i = 0;i < 1000000000;i++) {
user.getName();
}
long end = System.currentTimeMillis();
System.out.println("普通方法执行10亿次:" + (end - start) + "ms");
}
//反射方式
public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class clazz = user.getClass();
Method getName = clazz.getDeclaredMethod("getName", null);
long start = System.currentTimeMillis();
for(int i = 0;i < 1000000000;i++) {
getName.invoke(user,null);
}
long end = System.currentTimeMillis();
System.out.println("反射方法执行10亿次:" + (end - start) + "ms");
}
//反射方式
public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class clazz = user.getClass();
Method getName = clazz.getDeclaredMethod("getName", null);
getName.setAccessible(true);
long start = System.currentTimeMillis();
for(int i = 0;i < 1000000000;i++) {
getName.invoke(user,null);
}
long end = System.currentTimeMillis();
System.out.println("关闭反射检测方法执行10亿次:" + (end - start) + "ms");
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
test01();
test02();
test03();
}
通过运行结果可以很明显的发现,普通方法的执行效率远远不是其他方法能够比拟的,因次在开发中慎用反射技术。
关闭了权限检测后的反射方法的调用效率是未关闭的1/3左右,因此在要使用反射技术时,并且对于安全性没有过高的要求时,可以关闭权限检测,提高效率。
public void test01(Map<String,User> map, List<User> list) {
System.out.println("test01");
}
Method method = test05.class.getMethod("test01", Map.class, List.class);
Type[] types = method.getGenericParameterTypes();
for (Type type : types) { //遍历
System.out.println(type);
}
此时运行的结果为:
java.util.Map<java.lang.String, com.xgp.company.reflection.User>
java.util.List<com.xgp.company.reflection.User>
由运行结果可知,并不是我们想要获取的形式
//获得真实类型
Type[] guns = ((ParameterizedType) type).getActualTypeArguments();
for (Type gun : guns) {
System.out.println(gun);
}
public static void main(String[] args) throws NoSuchMethodException {
Method method = test05.class.getMethod("test01", Map.class, List.class);
Type[] types = method.getGenericParameterTypes();
for (Type type : types) {
System.out.println(type);
if(type instanceof ParameterizedType) {
//获得真实类型
Type[] guns = ((ParameterizedType) type).getActualTypeArguments();
for (Type gun : guns) {
System.out.println(gun);
}
}
}
}
运行的结果为:
java.util.Map<java.lang.String, com.xgp.company.reflection.User>
class java.lang.String
class com.xgp.company.reflection.User
java.util.List<com.xgp.company.reflection.User>
class com.xgp.company.reflection.User
上面讲了这么多的反射技术,终于来到了自定义注解的核心,通过反射技术获取自定义注解上的信息。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table {
String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Field{
String columnName();
String type();
int length();
}
@Table("db_student")
class Student {
@Field(columnName = "t_id",type = "int",length = 10)
private int id;
@Field(columnName = "t_age",type = "varchar",length = 10)
private int age;
@Field(columnName = "t_name",type = "varchar",length = 3)
private String name;
public Student() {
}
public Student(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
Class<Student> clazz = Student.class;
//通过反射获取注解
Annotation[] annotations = clazz.getAnnotations();
//遍历
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
输出的结果为:
@com.xgp.company.reflection.Table(value=db_student)
//获得注解的value的值
Table table = clazz.getAnnotation(Table.class);
String value = table.value();
System.out.println(value);
输出的结果为:
db_student
java.lang.reflect.Field name = clazz.getDeclaredField("name");
Field ano = name.getAnnotation(Field.class);
System.out.println(ano.columnName());
System.out.println(ano.type());
System.out.println(ano.length());
输出的结果为:
t_name
varchar
3
public class Test06 {
public static void main(String[] args) throws NoSuchFieldException {
Class<Student> clazz = Student.class;
//通过反射获取注解
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//获得注解的value的值
Table table = clazz.getAnnotation(Table.class);
String value = table.value();
System.out.println(value);
java.lang.reflect.Field name = clazz.getDeclaredField("name");
Field ano = name.getAnnotation(Field.class);
System.out.println(ano.columnName());
System.out.println(ano.type());
System.out.println(ano.length());
}
}
完整的输出为:
@com.xgp.company.reflection.Table(value=db_student)
db_student
t_name
varchar
3
标签:创建对象 接口 getc mem 简单 自定义 反射 generic voc
原文地址:https://www.cnblogs.com/xgp123/p/12257410.html