1 定义: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法,这种动态获取、调用对象方法的功能称为java语言的反射机制。
2 作用: 反射机制可以操作字节码文件,也就是说通过反射我们可以获取构造器,对象,属性,方法(原本不知道)
(1) 通过该类的对象去获取到对应的Class对象
Class string_class01 = " ".getClass();
这种方法基本不用,这里显然和反射机制相悖(已有类对象 了还去用反射获取Class类对象干嘛,多此一举)
(2) 通过全限定名来获取Class对象
Class string_class02 = Class.forName("java.lang.String");
(3) 通过类名.class
最好用,也更安全!
Class string_class03 = String.class;
public class test06 {
public static void main(String[] args) throws ClassNotFoundException {
Class string_class01 = " ".getClass();
Class string_class02 = Class.forName("java.lang.String");
Class string_class03 = String.class;
System.out.println(string_class01);
System.out.println(string_class02);
System.out.println(string_class03);
}
}
//结果
//class java.lang.String
//class java.lang.String
//class java.lang.String
public class test05 {
public static void main(String[] args) throws Exception {
Class user02 = Class.forName("fans.users1");
StringBuilder str = new StringBuilder();
str.append(Modifier.toString(user02.getModifiers())+" class "+user02.getSimpleName()+"{\n");
//通过Field类反射获取类users1属性
Field[] field = user02.getDeclaredFields();
for(Field f:field) {
str.append("\t"+Modifier.toString(f.getModifiers())
+" "+f.getType().getSimpleName()
+" "+f.getName()+" \n");
}
//通过Constructor类反射获取类users1构造方法
Constructor[] con = user02.getConstructors();
str.append("\n");
for(Constructor c :con) {
str.append("\t"+Modifier.toString(c.getModifiers())+" "
+user02.getSimpleName()+"(");
Class[] pp = c.getParameterTypes();
for(Class cc:pp) {
str.append(cc.getSimpleName()+",");
}
if(pp.length>0) {
str.deleteCharAt(str.length()-1);
}
str.append("){}\n");
}
//通过Method类反射获取类users1方法
Method[] method = user02.getDeclaredMethods();
str.append("\n");
for(Method m:method) {
str.append("\t"+Modifier.toString(m.getModifiers())+" "
+m.getReturnType().getSimpleName()+" "
+m.getName());
str.append("( ");
Class[] p = m.getParameterTypes();
for(Class p01:p) {
str.append(p01.getSimpleName()+",");
}
str.deleteCharAt(str.length()-1);
str.append("){}\n");
}
str.append("}");
System.out.println(str);
}
}
public class test06 {
public static void main(String[] args) throws Exception {
//通过new调用users1的方法
users1 u01= new users1();
if( u01.login("admin", "Admin@123"))
System.out.println("登入成功!");
else
System.out.println("用户名或密码错误!");
System.out.println("------------------------");
//通过反射调用users1的方法
// 获取类的class
Class u02class = users1.class;
//创建对象
Object u0201 = u02class.newInstance();//该操作会默认调用无参构造
//获取method
Method loginmethod = u02class.getDeclaredMethod("login", String.class,String.class);
//获取loginmethod的invoke方法的返回值
Object retValue = loginmethod.invoke(u0201, "admin","Admin@123");
System.out.println(retValue);
boolean retlogin = (boolean) retValue;
System.out.println(retlogin?"登入成功!":"登入失败!");
Method loninmethod01 = u02class.getDeclaredMethod("login", String.class);
boolean retlogin01 = (boolean) loninmethod01.invoke(u0201, "admin");
System.out.println(retlogin01?"登入成功!":"登入失败!");
//调用无参方法
u02class.getDeclaredMethod("logout").invoke(u0201);
System.out.println("------------------------");
//通过new调用users1的构造方法
users1 u02 = new users1();
users1 u03 = new users1("张三");
users1 u04 = new users1(true, "李四");
System.out.println("------------------------");
//通过反射调用users1的构造方法
//创建class
Class u03class = Class.forName("fans.users1");
Object u0301 = u03class.newInstance();
Constructor cons = u03class.getConstructor();
cons.newInstance();
Constructor cons01 = u03class.getConstructor(String.class);
cons01.newInstance("张三");
Constructor cons02 = u03class.getConstructor(boolean.class,String.class);
cons02.newInstance(true,"李四");
Constructor cons03 = u03class.getConstructor(int.class,String.class);
Object retcons03 = cons03.newInstance(22,"赖滢");
System.out.println(retcons03);
System.out.println("------------------------");
//通过new访问users1的属性
users1 u05 = new users1();
u05.name = "张三";
u05.age = 20;
u05.sex = true;
System.out.println(u05);
System.out.println("------------------------");
//通过反射访问users1的属性
Field ff = u03class.getDeclaredField("name");
ff.set(u0301, "张三");
System.out.println(ff.get(u0301));
Field ff01 = u03class.getDeclaredField("ID");
ff01.setAccessible(true);//访问私有属性时需打破封装但会破坏其安全性
ff01.set(u0301, 303);
System.out.println(ff01.get(u0301));
//获取父类和父接口
System.out.println("------------------获取父类和父接口---------------------");
Class strclass = String.class;
Class strsupclass = strclass.getSuperclass();
System.out.println(strsupclass.getName());
Class[] strinter = strclass.getInterfaces();
for(Class c : strinter) {
System.out.println(c.getName());
}
}
}
上面案例用到users1类
public class users1 {
private int ID;
protected int age;
boolean sex;
public String name;
public static final double MATH_PI = 3.1415926;
public users1() {
super();
System.out.println("这是无参构造!");
}
public users1(String name) {
super();
this.name = name;
System.out.println(this.name);
}
public users1(boolean sex, String name) {
super();
this.sex = sex;
this.name = name;
System.out.println(this.sex+"="+this.name);
}
public users1(int age, String name) {
super();
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "users1 [ID=" + ID + ", age=" + age + ", sex=" + sex + ", name=" + name + "]";
}
/**
*
* @param name 账户
* @param password 密码
* @return
*/
public static boolean login(String name,String password) {
if("admin".equals(name)&&"Admin@123".equals(password))
return true;
return false;
}
public void logout() {
System.out.println("账户已安全退出!");
}
public boolean login(String name) {
return "admin".equals(name)? true:false;
}
}
getModifiers()
,获取字段和方法等的修饰符类型,返回值是int类型,什么都不加是0,public 是1,private是2,protected是4,static 是8,final是16,等等,多个修饰符修饰的话,返回的是每个修饰符代表的int值的和
、、、、、、、、可自行查API文档
API文档https://www.runoob.com/manual/jdk1.6/java.base/java/lang/Class.html
1 先创建一个名叫ID的注释
若还不会创建和理解的请看Java-注释详解
@Documented @Retention(RUNTIME) @Target({ TYPE, FIELD, METHOD }) public @interface ID { int id() default 205; String name(); mark chengji(); }
2 创建mark(代表成绩且该处用枚举实现)
若不知如何创建或不是很理解就评论 收藏关注后期就出相应教程!
public enum mark { 不及格,及格,良,优; }
3 创建users类并在相应的位置标识注释
@ID(name = "zwy", chengji=mark.不及格) public class users { @ID(name = "zwy", chengji = mark.优) private int ID; protected int age; boolean sex; public String name; public static final double MATH_PI = 3.1415926; }
4 创建被ID注释的类没有有int型的id的异常类
若不知如何创建或不是很理解就评论 收藏关注后期就出相应教程!
public class NotIdException extends RuntimeException{ public NotIdException() { } public NotIdException(String s) { super(s); } }
5 创建测试类test01并实现当被ID注释的类必须有int型的id 属性否则抛出异常!
public class test01 { public static void main(String[] args) throws NoSuchFieldException, SecurityException { Class userclass = users.class; Field ff = userclass.getDeclaredField("ID"); //判断userclass的ID属性是否被注释 System.out.println(ff.isAnnotationPresent(ID.class)); //获取属性的注释属性值 ID id = ff.getAnnotation(ID.class); System.out.println(id.id()); System.out.println(id.name()); System.out.println(id.chengji()); //判断userclass类是否被注释 System.out.println(userclass.isAnnotationPresent(ID.class)); //获取类的注释属性值 ID idclass = (ID) userclass.getAnnotation(ID.class) ; System.out.println(idclass.chengji()); //被ID注释的类必须有int型的id 属性否则抛出异常! boolean isid = false; if(userclass.isAnnotationPresent(ID.class)) { Field[] field = userclass.getDeclaredFields(); for(Field f:field) { if("ID".equals(f.getName())&& "int".equals(f.getType().getSimpleName())) { isid = true; break; } } if(!isid) { throw new NotIdException("被ID注释的类必须有int型的id 属性"); } } } }
1 长度个数:0~n 2 可变 长度参数必须在参数列表最后一个位置上,而且可变长度参数只能有一个 3 可将可变长度参数看作一个数组
public class test04 { public static void main(String[] args) { m(); m(1,2); m(1,2,3); m2(1,"abc"); m2(1,"abc","dc"); m3(" ","abc","de","f"); String[] strs = {"www",".baidu.","com","//"}; m3(strs); m3(new String[]{"我","是","中","国","人"}); } public static void m(int... args) { System.out.println("m方法执行"); } /* * public static void m1(int... args1 ,String... args2) { }//报错!只要一个且在最后! */ public static void m2(int a,String...args) { System.out.println("m2方法执行"); } public static void m3(String...args) { //args有length说明是一个数组 for(int i=0;i
1 通过I/O流读取users1info文件来获取字符串类名进行反射操作
//通过I/O流读取userinfo文件 FileReader reader = new FileReader("userinfo1"); File f = new File("userinfo1"); //创建属性类对象 Properties p = new Properties(); //加载 p.load(reader); //关闭流 reader.close(); Class s3 = Class.forName(p.getProperty("students")); System.out.println(s3);
2 获取userinfo文件的绝对路径(增强代码的健壮性)
String path = Thread.currentThread().getContextClassLoader().getResource("fans/userinfo2").getPath();
InputStream reader = Thread.currentThread().getContextClassLoader().getResourceAsStream("fans/userinfo2");
3 若获取的绝对路径有中文乱码进行解码
URLDecoder.decode(path,"UTF-8")
String path = Thread.currentThread().getContextClassLoader().getResource("fans/userinfo2").toURI().getPath();
4 使用绝对路径进行获取字符串类名
InputStream reader = Thread.currentThread().getContextClassLoader().getResourceAsStream("fans/userinfo2"); FileReader fr01 = new FileReader(path); Properties p01 = new Properties(); p01.load(reader); reader.close(); Class c01 = Class.forName(p01.getProperty("students")); System.out.println(c01);
5 利用Java自带的资源绑定器获取字符串类名
ResourceBundle b = ResourceBundle.getBundle("fans/userinfo2");资源绑定器 System.out.println(b.getString("students"));
6 在fans包下的txt文件userinfo2
students=fans.students
//public private protected 的简单区别 1、public:public表明该数据成员、成员函数是对所有用户开放的,所有用户都可以直接进行调用 2、private:private表示私有,私有的意思就是除了class自己之外,任何人都不可以直接使用。 3、protected:protected对于子女、朋友来说,就是public的,可以自由使用,没有任何限制,而对于其他的外部class,protected就变成private。
8 通过反射机制访问一个Java对象的属性,并给属性赋值(set)及获取属性值(get)
public class test03 extends users { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException { students stu01 = new students(); users user01 = new users(); Class usersClass = Class.forName("fans.users"); //通过new,普通访问一个对象的属性 //赋值 stu01.no=111; //获取 System.out.println(stu01.no); //使用反射机制,创建对象 Object obj = usersClass.newInstance();//会自动调用无参构造 //获取no属性 Field nofield = usersClass.getDeclaredField("no"); //给obj对象no属性赋值 nofield.set(obj, 222); System.out.println(nofield.getName()+"="+nofield.get(obj)); //访问私有属性需要打破封装(打破封装会带来安全问题)才能访问赋值获取 Field idfield = usersClass.getDeclaredField("ID"); idfield.setAccessible(true);//打破封装 idfield.set(obj, 306); System.out.println(idfield.getName()+"="+idfield.get(obj)); Field agefisld = usersClass.getDeclaredField("age"); agefisld.set(obj, 18); System.out.println(agefisld.getName()+"="+ agefisld.get(obj)); //正常new的对象不能访问私有属性,要访问须继承对象类并获取set(),get()方法 //user01.ID;//报错访问不了 //去users类下获取获取set(),get()方法,通过调用方法进行赋值和取值 user01.setID(207); System.out.println("user01ID="+ user01.getID()); } }
9 只要类加载静态代码快就会执行(所以若只执行类中的静态代码快可以使用反射机制进 行加载)
public class test02 { public static void main(String[] args) throws ClassNotFoundException, IOException, URISyntaxException { //students s = new students(); Class c = Class.forName("fans.students"); } } class students { int no; private int ID; public students() { System.out.println("这是个无参构造方法!"); } static { System.out.println("这里是静态代码块"); } }
//该通过new对象进行实例化加载会运行整代码块
//运行结果://通过反射进行类加载只会运行静态类加载块
10 获取Class之后,可以调用无参数构造方法来实例化对象
//通过反射获取class ,通过class实例化对象 Class s = Class.forName("fans.students"); Object s1 = s.newInstance();//已过时,该方法会默认调用无参构造方法,所以必须保证无参构造存在。 //通过new实例化对象 students s2 = new students();
Java的getCanonicalName和getName ,getSimpleName()https://blog.csdn.net/hustzw07/article/details/71108945