您的位置:首页 > 编程语言 > Java开发

【知了堂学习笔记】JAVA反射及注解--轻松学会反射

2018-11-04 18:26 721 查看

java的反射

反射是java的重要机制,java语言的动态性与它有着莫大的关系。
通过反射可以获得获得类、属性、构造方法、方法、注解的信息
也可以利用反射机制动态操作这些内容,可以调用构造函数、操作属性、调用方法

用反射操作类中内容的步骤:
1.获取Class对象
2.得到对应实例
3.操作实例

注:Class:该对象并不是class,它是一个类的原模板,储存了类的所有信息,一维数组和二维数组不是同一个类,对象创建自动加载Class类。
同一类对象创建的模板是一致的,都是它所属类的模板。

获取Class的方法有(返回对象是Class):
1.类名.class
2.对象名.getclass()
3.Class.forName(path) --> path是java类所属路径
举个例子:

/**
* 演示说明Class
* @author Administrator
*
*/
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class cls=Class.forName("com.zlt.test1.Test");//用Class.forName获取Class
System.out.println("打印Class的名字: "+cls.getSimpleName());
String a = "aaa";
String b = "bbb";
System.out.println("同一类创建对象的Class: " + a.getClass()+" "+b.getClass());
String aa[]= {};
String bb[][]= {};
System.out.println("一维数组和二维的Class: "+ aa.getClass() +"   "+ bb.getClass());
System.out.println("String的Class"+String.class);
}
}

运行结果:

用反射对class的操作:

1.获得类的相关信息
注:操作类的信息室,用带有Declared的方法能访问私有属性,方法,否则不能访问私有方法
类返回Class
属性返回Field
方法返回Method
构造函数返回Constructor
注解返回Annotation

操作方法基本一致:

package com.zlt.test1;

import java.lang.reflect.*;

/**
* 用反射操作类
* @author Administrator
*
*/
public class OpterClass {
public static void main(String[] args) throws Exception {
Class cls=Class.forName("com.zlt.test1.AAA"); //1.得到类
//获得类信息
String name=cls.getName();//获取包名+类名
String fullName=cls.getSimpleName();//获取类名

//获得属性,返回Field类型
Field f=cls.getDeclaredField("str1");//获取指定属性,能访问私有的
System.out.println(f.getName());

Field fid[]=cls.getFields();//获取属性,私有的访问不到
for(Field ff:fid) {
System.out.println(ff.getName());
}

//获取方法
Method method=cls.getDeclaredMethod("Print", String.class);//  方法名,参数类型列表 --> 没有参数就无须添加
Method []methods=cls.getDeclaredMethods();//获取全部方法,任何访问级别
System.out.println(method.getName());

//获取构造函数
Constructor cons=cls.getConstructor(); //不需要跟方法名,直接给参数即可,也是参数的模板Class类
System.out.println(cons.getName());

}
}

class AAA{
public String str1="aaa";
private String str2="bbb";
public AAA() {
System.out.println("无参构造");
}
public AAA(String aaa) {
this.str1=aaa;
}
public void Print(String a) {
System.out.println("print");
}
}

注:(1)在获取属性,方法,构造函数时,如果要访问私有的,需使用带Declared的get方法
(2)在获取指定方法时,要传参,分别是方法名和参数的模板类(类名.calss),如果没有参数则只需要方法名
(3)获取构造方法时,直接以模板类(类名.calss)作为参数即可
(4)如果直接获取所有属性、方法、构造函数,则返回对应类型的数组

2.操作属性,方法,构造函数

package com.zlt.test1;

import java.lang.reflect.*;

public class OpterClass2 {
public static void main(String[] args) throws Exception {
Class cls=BBB.class;//获取Class对象
Constructor<BBB> cons1=cls.getConstructor();//获取无参构造
Constructor<BBB> cons2=cls.getConstructor(String.class);//获取有参构造

//调用构造函数
BBB b1=cons1.newInstance();
BBB b2=cons2.newInstance("新新参数");

//获取方法
Method m1=cls.getDeclaredMethod("Print");//无参方法
Method m2=cls.getDeclaredMethod("Print",String.class);//有参方法

//使用方法
m1.invoke(b1);//执行b1对象的无参方法
m2.invoke(b1,"aaa");//执行b1对象的有参方法
m1.invoke(b2);//执行b2对象的无参方法
m2.invoke(b2,"aaa");//执行b2对象的有参方法

//获取属性
Field f=cls.getDeclaredField("name");

//操作属性
f.setAccessible(true);//操作私有属性要关闭安全检查
f.set(b1, "new b1");//设置b1的name属性
f.set(b2, "new b2");//设置b2的name属性
m1.invoke(b1);
m1.invoke(b2);
}
}

class BBB{
private String name="aaa";
public BBB() {
System.out.println("无参构造");
}
public BBB(String name) {
this.name=name;
System.out.println("有参构造");
}
public void Print() {
System.out.println(this.name);
System.out.println("调用无参方法");
}
public void Print(String a) {
System.out.println("调用有参构造方法");
}
}

结果如下:

注:(1)操作属性时,如果要访问私有属性,要关闭安全检查 -------- setAccessible(true)
(2)使用类的方法一般用构造函数newInstances创建对象操作,成员方法的使用都与对象离不开关系
(3)注意获得方法和使用方法传递的参数的区别

3.操作注解
步骤:
(1)先获得Class对象
(2)获得对应类、属性、方法…的注解,返回对应注解的类型
(3)获取注解的值

案例:把类映射成sql语句

先定义两个注解

package com.zlt.fluance;
/**
* 表名信息
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String data();//属于哪个数据库
String name();//表名
}
package com.zlt.fluance;

/**
* 表的每一列
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String name();//列名
String type();//数据类型
int length() default 1;//长度
String[] key() default "";//约束
}

用反射操作注解

package com.zlt.fluance;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

public class CreateTable {

public String Create(Class cls) {
String sql="";//sql语句
Table table=(Table)cls.getAnnotation(Table.class);//获得类的注解
String tableOfData=table.data();//表所在的数据库
String tableName=table.name();//表名

if(tableOfData!=null) sql+="use "+tableOfData+"\r";
sql+="create table "+tableName +" (\n\t";

Field[] f=cls.getDeclaredFields();
for(int i=0;i<f.length;i++) {//遍历属性
Field field=f[i];
Column cloumn=field.getAnnotation(Column.class);//获得属性的注解
String keys="";

for(int k=0;k<cloumn.key().length;k++) {//添加约束
keys+=" "+cloumn.key()[k];
}
String row="";//属性
if(i==(f.length-1))
row=cloumn.name()+" "+cloumn.type()+"("+cloumn.length()+")"+keys+"\r";
else
row=cloumn.name()+" "+cloumn.type()+"("+cloumn.length()+")"+keys+",\r\t";
sql+=row;
}
sql+=");";
return sql;
}
}

函数调用

package com.zlt.fluance;
/**
* 调用封装的函数
* 把类映射出对应的sql语句
* @author Administrator
*
*/
public class Test {
public static void main(String[] args) {
CreateTable ct=new CreateTable();
String sql=ct.Create(Student.class);
System.out.println(sql);
}
}

结果:

注:注解的使用遵循开头的三步走战略

总结:(1)反射操作的核心是Class对象,反射就是不断操作这个对象,再通过它的API来操作信息。
(2)反射会降低程序运行效率

(3)反射能大大提高程序开发效率,在企业常被使用,希望大家能掌握。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: