Java反射机制
如果要通过一个对象找到一个类的名称,此时就需要用到反射机制(反射技术是用来做框架的,一般情况下Java私有对象不能被访问,但是暴力反射可以访问私有对象)。
任何一个类如果没有明确地声明继承自哪个父类的时候,则默认继承Object类,所以getClass()方法是Object类中的。
文件在包java_reflect目录下
// 类名:Y // 属性: // 方法: class Y{ }
class Y{ } //主类 //Function : GetClass_demo; public class GetClass_demo { public static void main(String[] args) { // TODO 自动生成的方法存根 Y y = new Y(); System.out.println(y.getClass().getName()); } }
输出
实例化Class类对象的3种方法
class Y{ } public class GetClass_demo { public static void main(String[] args) { // TODO 自动生成的方法存根 Class<?> c1 = null; Class<?> c2 = null; Class<?> c3 = null; try{ c1 = Class.forName("java_basic.Y"); //通过forName()方法实例化对象 }catch(ClassNotFoundException e){ e.printStackTrace(); } c2 = new Y().getClass(); //通过Object类中的方法实例 c3 = Y.class; //通过类.class实例化 System.out.println("类名称"+c1.getName()); System.out.println("类名称"+c2.getName()); System.out.println("类名称"+c3.getName()); } }
输出
Class类的使用
Class类在开发中最常见的用法就是实例化对象的操作,即可以通过一个给定的字符串(此字符串包含了完整的“包.类”的路径)来实例化一个类的对象。
1.通过无参构造实例化对象
如果要想通过Class类对象实例化其他类的对象,则可以使用newInstance()方法,但是必须要保证被实例化的类中存在一个无参构造方法
public class InstanceClass_demo { public static void main(String[] args) { // TODO 自动生成的方法存根 Class<?> c = null; //指定泛型 try{ c = Class.forName("person"); //传入要实例化类的完整包.类名称 }catch(ClassNotFoundException e){ e.printStackTrace(); } person per = null; //声明person对象 try{ per = (person)c.newInstance(); //实例化person对象 }catch(Exception e){ e.printStackTrace(); } per.setAge(30); per.setName("张三"); System.out.println(per); } }
输出
2.调用有参构造实例化对象
import java.lang.reflect.Constructor; public class InstanceClass_demo { public static void main(String[] args) { // TODO 自动生成的方法存根 Class<?> c = null; //指定泛型 try{ c = Class.forName("person"); //传入要实例化类的完整包.类名称 }catch(ClassNotFoundException e){ e.printStackTrace(); } person per = null; //声明person对象 Constructor<?> cons[] = null; //声明一个表示构造方法的数组 cons = c.getConstructors(); //通过反射取得全部构造 try{ per = (person) cons[0].newInstance("张三",30); //实例化person对象 }catch(Exception e){ e.printStackTrace(); } // per.setAge(30); // per.setName("张三"); System.out.println(per); } }
输出
可以通过反射得到一个类的完整结构,需要使用到java.lang.reflect包中的以下几个类。
Constructor:表示类中的构造方法
Field:表示类中的属性
Method:表示类中的方法
这3个类都是AccessibleObject类中的子类
interface China{ public static final String NATIONAL = "China"; public static final String AUTHOR = "张三"; public void sayChina(); public String sayHello(String name,int age); } class Person_5 implements China{ private String name; private int age; public Person_5(){ //无参构造方法 } public Person_5(String name) { //声明两个参数的构造方法 super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person_5(String name, int age) { super(); this.name = name; this.age = age; } @Override public void sayChina() { // TODO 自动生成的方法存根 System.out.println("作者:"+AUTHOR+"国籍:"+NATIONAL); } @Override public String sayHello(String name, int age) { // TODO 自动生成的方法存根 return name+"age:"+age; } } public class ConstructorClass_demo { public static void main(String[] args) { // TODO 自动生成的方法存根 Class<?> c1 = null; //指定泛型 try{ c1 = Class.forName("Person_5"); //传入要实例化类的完整包.类名称 }catch(ClassNotFoundException e){ e.printStackTrace(); } Class<?> c[] = c1.getInterfaces(); //取得实现的全部接口 for(int i=0;i<c.length;i++){ System.out.println("实现的接口名称:"+c[i].getName()); } } }
取得父类
一个类可以实现多个接口,但是只能继承一个父类,所以如果要取得一个类的父类,可以直接使用class类中的getSuperclass()方法。
interface China{ public static final String NATIONAL = "China"; public static final String AUTHOR = "张三"; public void sayChina(); public String sayHello(String name,int age); } class Person_5 implements China{ private String name; private int age; public Person_5(){ //无参构造方法 } public Person_5(String name) { //声明两个参数的构造方法 super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person_5(String name, int age) { super(); this.name = name; this.age = age; } @Override public void sayChina() { // TODO 自动生成的方法存根 System.out.println("作者:"+AUTHOR+"国籍:"+NATIONAL); } @Override public String sayHello(String name, int age) { // TODO 自动生成的方法存根 return name+"age:"+age; } } public class ConstructorClass_demo { public static void main(String[] args) { // TODO 自动生成的方法存根 Class<?> c1 = null; //指定泛型 try{ c1 = Class.forName("Person_5"); //传入要实例化类的完整包.类名称 }catch(ClassNotFoundException e){ e.printStackTrace(); } Class<?> c2 = c1.getSuperclass(); //取得父类 System.out.println("实现的接口名称:"+c2.getName()); } }
取得全部构造方法
要取得一个类中的全部构造方法,则必须使用Class类中的getConstructors()方法。
import java.lang.reflect.Constructor; interface China{ public static final String NATIONAL = "China"; public static final String AUTHOR = "张三"; public void sayChina(); public String sayHello(String name,int age); } class Person_5 implements China{ private String name; private int age; public Person_5(){ //无参构造方法 } public Person_5(String name) { //声明两个参数的构造方法 super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person_5(String name, int age) { super(); this.name = name; this.age = age; } @Override public void sayChina() { // TODO 自动生成的方法存根 System.out.println("作者:"+AUTHOR+"国籍:"+NATIONAL); } @Override public String sayHello(String name, int age) { // TODO 自动生成的方法存根 return name+"age:"+age; } } public class ConstructorClass_demo { public static void main(String[] args) { // TODO 自动生成的方法存根 Class<?> c1 = null; //指定泛型 try{ c1 = Class.forName("Person_5"); //传入要实例化类的完整包.类名称 }catch(ClassNotFoundException e){ e.printStackTrace(); } Constructor<?> c[] = c1.getConstructors(); //取得全部的构造方法 for(int i=0;i<c.length;i++){ System.out.println("全部的构造方法:"+c[i]); } } }
取得全部方法
要取得一个类中的全部方法,可以使用Class类中的getMethods()方法,此方法返回一个Method类的对象数组。
如果要进一步取得方法的具体信息,例如,方法的参数、抛出的异常声明等,则就必须依靠Method类。
import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class GetMethod_demo { public static void main(String[] args) { // TODO 自动生成的方法存根 Class<?> c1 = null; //指定泛型 try{ c1 = Class.forName("Person_5"); //传入要实例化类的完整包.类名称 }catch(ClassNotFoundException e){ e.printStackTrace(); } Method m[] = c1.getMethods(); //取得全部的方法 for(int i=0;i<m.length;i++){ //循环输出 Class<?> r = m[i].getReturnType(); //得到方法的返回值类型 Class<?> p[] = m[i].getParameterTypes(); //得到全部的参数类型 int xx = m[i].getModifiers(); //得到方法的修饰符,即public System.out.print(Modifier.toString(xx)+" "); //还原修饰符 System.out.print(r.getName()+" "); //得到方法返回值 System.out.print(m[i].getName()); //取得方法的名称 System.out.print("("); for(int x=0;x<p.length;x++){ System.out.print(p[x].getName()+" "+"arg"+x); //输出参数 if(x<p.length-1){ System.out.print(","); } } Class<?> ex[] = m[i].getExceptionTypes(); //得到全部的异常抛出 if(ex.length>0){ //判断是否有异常 System.out.print(") throws "); }else{ System.out.print(") "); } for(int j=0;j<ex.length;j++){ System.out.println(ex[j].getName()); //输出异常信息 if(j<ex.length-1){ System.out.println(","); } } System.out.println(); } } }
取得全部属性
import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class GetMethod_demo { public static void main(String[] args) { // TODO 自动生成的方法存根 Class<?> c1 = null; //指定泛型 try{ c1 = Class.forName("Person_5"); //传入要实例化类的完整包.类名称 }catch(ClassNotFoundException e){ e.printStackTrace(); } // Method m[] = c1.getMethods(); //取得全部的方法 // for(int i=0;i<m.length;i++){ //循环输出 // Class<?> r = m[i].getReturnType(); //得到方法的返回值类型 // Class<?> p[] = m[i].getParameterTypes(); //得到全部的参数类型 // int xx = m[i].getModifiers(); //得到方法的修饰符,即public // // System.out.print(Modifier.toString(xx)+" "); //还原修饰符 // System.out.print(r.getName()+" "); //得到方法返回值 // System.out.print(m[i].getName()); //取得方法的名称 // System.out.print("("); // for(int x=0;x<p.length;x++){ // System.out.print(p[x].getName()+" "+"arg"+x); //输出参数 // if(x<p.length-1){ // System.out.print(","); // } // } // Class<?> ex[] = m[i].getExceptionTypes(); //得到全部的异常抛出 // if(ex.length>0){ //判断是否有异常 // System.out.print(") throws "); // }else{ // System.out.print(") "); // } // for(int j=0;j<ex.length;j++){ // System.out.println(ex[j].getName()); //输出异常信息 // if(j<ex.length-1){ // System.out.println(","); // } // } // System.out.println(); // } { Field f[] = c1.getDeclaredFields(); //取得本类属性 for(int i=0;i<f.length;i++){ Class<?> r = f[i].getType(); //取出属性的类型 int mo = f[i].getModifiers(); //得到修饰符数字 String priv = Modifier.toString(mo); //取得属性的修饰符 System.out.print("本类属性:"); System.out.print(priv + " "); //输出修饰符 System.out.print(r.getName()+" "); //输出属性类型 System.out.print(f[i].getName()); //输出属性名称 System.out.println(" ;"); } } { Field f[] = c1.getFields(); //取得父类公共属性 for(int i=0;i<f.length;i++){ Class<?> r = f[i].getType(); //取出属性的类型 int mo = f[i].getModifiers(); //得到修饰符数字 String priv = Modifier.toString(mo); //取得属性的修饰符 System.out.print("本类属性:"); System.out.print(priv + " "); //输出修饰符 System.out.print(r.getName()+" "); //输出属性类型 System.out.print(f[i].getName()); //输出属性名称 System.out.println(" ;"); } } } }
反射机制还可以调用类中的指定方法或指定属性,并且可以通过反射完成对数组的操作。
通过反射调用类中的方法
import java.lang.reflect.Method; public class InvokeChina_demo { public static void main(String[] args) { // TODO 自动生成的方法存根 Class<?> c1 = null; //指定泛型 try{ c1 = Class.forName("Person_5"); //传入要实例化类的完整包.类名称 }catch(ClassNotFoundException e){ e.printStackTrace(); } try{ Method met = c1.getMethod("sayChina"); //取得一个Method对象 met.invoke(c1.newInstance()); //使用invoke进行调用,必须传递对象实例 }catch(Exception e){ e.printStackTrace(); } } }
可以向方法中传递两个参数
import java.lang.reflect.Method; public class InvokeChina_demo { public static void main(String[] args) { // TODO 自动生成的方法存根 Class<?> c1 = null; //指定泛型 try{ c1 = Class.forName("Person_5"); //传入要实例化类的完整包.类名称 }catch(ClassNotFoundException e){ e.printStackTrace(); } try{ Method met = c1.getMethod("sayHello",String.class,int.class); //此方法需要两个参数 String rv = null; //接收方法的返回值 rv = (String)met.invoke(c1.newInstance(),"李四",32); //使用invoke进行调用,必须传递对象实例 System.out.println(rv); }catch(Exception e){ e.printStackTrace(); } } }
调用setter和getter方法
import java.lang.reflect.Method; public class InvokeSetGet_demo { public static void main(String[] args) { // TODO 自动生成的方法存根 Class<?> c1 = null; //指定泛型 Object obj = null; //声明一个对象 try{ c1 = Class.forName("Person_5"); //传入要实例化类的完整包.类名称 }catch(ClassNotFoundException e){ e.printStackTrace(); } try{ obj = c1.newInstance(); //实例化操作对象 }catch(InstantiationException | IllegalAccessException e){ e.printStackTrace(); } setter(obj, "name", "张三", String.class); setter(obj, "age", 25, int.class); System.out.println("姓名:"); getter(obj, "name"); System.out.println("年龄:"); getter(obj, "age"); } public static void setter(Object obj,String att,Object value,Class<?> type){ try{ Method met = obj.getClass().getMethod("set"+initStr(att),type); //设置方法参数类型 met.invoke(obj, value); //调用方法 }catch(Exception e){ e.printStackTrace(); } } public static void getter(Object obj,String att){ try{ Method met = obj.getClass().getMethod("get"+initStr(att)); System.out.println(met.invoke(obj)); //接收方法的返回值 }catch(Exception e){ e.printStackTrace(); } } public static String initStr(String old){ String str = old.substring(0, 1).toUpperCase()+old.substring(1); //首字母大写 return str; } }
直接操作类中的属性
import java.lang.reflect.Field; public class InvokeField_demo { public static void main(String[] args) throws Exception { // TODO 自动生成的方法存根 Class<?> c1 = null; //声明Class对象 Object obj = null; //声明一个对象 c1 =Class.forName("Person_5"); //实例化Class对象 obj = c1.newInstance(); //实例化对象 Field nameField = null; //表示name属性 Field ageField = null; //表示age属性 nameField = c1.getDeclaredField("name"); //取得name属性 ageField = c1.getDeclaredField("age"); //取得age属性 nameField.setAccessible(true); //将name属性设置成可被外部访问 nameField.set(obj, "张三"); //设置name属性内容 ageField.setAccessible(true); //将age属性设置成可被外部访问 ageField.set(obj, 33); //设置age属性内容 System.out.println("姓名:"+nameField.get(obj)); //通过get取得属性内容 System.out.println("年龄:"+ageField.get(obj)); } }
通过反射操作数组
import java.lang.reflect.Field; import java.lang.reflect.Array; public class InvokeField_demo { public static void main(String[] args) throws Exception { // TODO 自动生成的方法存根 int temp[] = {1,2,3}; Class<?> c = temp.getClass().getComponentType(); //取得数组的Class对象 System.out.println("类型:"+c.getName()); //得到数组类型名称 System.out.println("长度:"+Array.getLength(temp)); //得到数组长度 System.out.println("第一个内容:"+Array.get(temp,0)); //得到第一个内容 Array.set(temp,0,6); //修改第一个内容 System.out.println("第一个内容:"+Array.get(temp,0)); //得到第一个内容 } }
本文只发表于博客园和tonglin0325的博客,作者:tonglin0325,转载请注明原文链接:https://www.cnblogs.com/tonglin0325/p/5292606.html