首先我们需要创建一个Student类,代码展示:
package venus;
public class Student {
public String name;
public Student() {
}
public void doHomework() {
System.out.println(name+"正在写作业");
}
}
创建一个Test类对象,代码如下:
package venus;
public class Test {
public static void main(String[] args) {
Student student = new Student();//调用构造方法
student.name="wjq";
student.doHomework();//调用普通方法
}
运行代码结果,此时,通过以上的方法可以看出,我们一般使用new+类名的方法创建对象。
什么是反射
反射是一种新的操作类中属性,构造方法和普通方法的机制(方式),两种方式等效,只是实现的过程不同。
而Class类是Java 反射机制的入口,封装了一个类或接口的运行时信息,通过调用Class类的方法可以获取这些信息。
Class类的特点
1、该类在java.lang包中;
2、该类被final所修饰,即该类不可以被子类继承;
3、该类实现了Serializable接口;
4、该类的构造方法被private所修饰,即不能通过new关键字创建该类的对象;
反射操作类属性实现
在Test类中展现:
1、Class.forname();
Class clazz=null;//clazz避免class关键字,
try {
clazz=Class.forName("venus.Student");
System.out.println("1、"+clazz.getName());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
2、类名.class;
clazz=Student.class;
System.out.println("2、"+clazz.getName());
3、对象.getClass();
clazz=new Student().getClass();
System.out.println("3、"+clazz.getName());
4、基本数据类型对应的class对象:包装类.TYPE
clazz = Integer.TYPE;
System.out.println("4、"+clazz.getName());
clazz = Integer.class;
System.out.println("4、"+clazz.getName());
5、数组类型对应class:元素类型[].class
clazz = String[].class;
System.out.println("5、"+clazz.getName());
6、某个类父类所对应的class对象
clazz = Student.class.getSuperclass();
System.out.println("6、"+clazz.getName());
如何获取方法
a.public,不仅限于本类,还包括继承自父类的方法
Method [] methods = clazz.getMethods();
for(Method method : methods) {
System.out.println(method.getName());
}
b.本类中声明的方法
Method [] methods = clazz.getDeclaredMethods();
for(Method method : methods) {
System.out.println(method.getName());
}
结果显示为:
需要注意的是:这两种方法没有明显的完全包含或完全被包含关系,两者会有部分方法重叠,但是有时候不会完全包含或被包含。
获取信息
此时修改Student类中的doHomework方法:
public static int doHomework(int a,String [] names) {
System.out.println("正在写作业");
return 1;
}
Test类中代码块为:
try {
Method method = clazz.getMethod("doHomework", Integer.TYPE,String[].class);
System.out.println(method.getDeclaringClass());
System.out.println(Modifier.toString(method.getModifiers()));
clazz = method.getReturnType();//☆
System.out.println(clazz.getName());
System.out.println(method.getName());
Class [] clazzs = method.getParameterTypes();
for(Class zz : clazzs) {
System.out.println(zz.getName());
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
结果显示为:
使用反射中的方法
反射中方法的调用不区分静态与非静态
代码展示为:
try {
Method method = clazz.getMethod("doHomework", Integer.TYPE,String[].class);
//反射中方法的调用不区分静态与非静态
Object object = method.invoke(new Student(), 1,new String[] {});
System.out.println(object);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
结果显示为:
需要注意的是:如果所调用的方法是非public的方法,则需要使用constructor.setAccessible(true);
来实现突破访问权限的影响,从而成功调用类中的方法。
获取该构造方法的信息
1、Class getDeclaringClass():返回声明Constructor对象对应构造方法的类的Class对象。
2、int getModifiers():以整数形式返回Constructor对象表示的构造函数的修饰符。
3、String getName() :以字符串形式返回Constructor对象所表示得构造方法的名称。
4、Class>[] getParameterTypes():返回由Constructor对象所表示的构造方法的形参类型对应Class对象组成的数组此 。如果构造方法没有参数,则数组长度为0。
注意:
getConstructors()和getConstructor(Class>… parameterTypes)方法均无法获取非public类中默认无参构造方法对应的Constructor对象。(参见代码1)
getDeclaredConstructors()和getDeclaredConstructor(Class>… parameterTypes)方法可以获取非public类中默认无参构造方法对应的Constructor对象。
Class clazz = Student.class;
try {
Constructor constructor = clazz.getDeclaredConstructor(String.class);
/*clazz = constructor.getDeclaringClass();
System.out.println(clazz.getName());
int mod = constructor.getModifiers();
String result = Modifier.toString(mod);
System.out.println(result);
System.out.println(constructor.getName());
Class [] clazzs = constructor.getParameterTypes();
for(Class zz:clazzs) {
System.out.println(zz);
}*/
} catch (Exception e) {
e.printStackTrace();
}
Class clazz = Student.class;
try {
Constructor constructor = clazz.getConstructor(String.class);
Object object = constructor.newInstance("957");//上转型对象
Student stu = (Student)object;
stu.doHomework();
} catch (Exception e) {
e.printStackTrace();
}
结果显示为:
此时如果将Student类中的方法权限改为private型,则会出现这种错误类型:
此时我们需要添加一段这样的代码,
constructor.setAccessible(true);//将访问权限提升至public
Object object = constructor.newInstance("957");//上转型对象
Student stu = (Student)object;
stu.doHomework();
我们知道,构造方法是用于创建对象的,而我们使用反射这种方式也是为了创建对象,此时,如果我们如果需要调用某个类中的构造方法,我们首先需要获取这个构造方法所在类中对应的Class类中的对象。
获取的方式共四种,我们可以根据其特点分为两组:
1、Constructor[] getConstrutors():返回该Class对象表示类包含的所有public构造方法(不含继承)所对应Constructor对象数组。
2、Constructor getConstrutor(Class>… parameterTypes):返回与该Class对象表示类中参数列表相匹配的public构造函数(不含继承)对应的Constructor对象。
3、Constructor>[] getDeclaredConstructors():返回一个该Class对象表示类中声明的所有构造方法(不区分访问权限)对应的Constructor对象数组。
4、Constructor getDeclaredConstructor(Class>… parameterTypes):返回与该Class对象表示类中定义的形参类型相匹配的构造方法(不区分访问权限)的Constructor对象。
为了讲述方便,在Test类中添加一段代码,以此来区分不同的构造方法。
public Student() {
}
public Student (String name)
{
this.name=name;
}
public Student(String name,Integer number ) {
this.name=name;
this.number=number;
}
public级别
Class clazz = Student.class;
try {
Constructor constructor = clazz.getConstructor();
System.out.println("1"+constructor.getName());
constructor = clazz.getConstructor(String.class);
System.out.println("2"+constructor.getName());
constructor = clazz.getConstructor(String.class,Integer.class);
System.out.println("3"+constructor.getName());
} catch (Exception e) {
e.printStackTrace();
}
不区分访问权限级别
此时我们将有参数的构造方法的访问权限改为private,
public Student() {
}
private Student (String name)
{
this.name=name;
}
private Student(String name,Integer number ) {
this.name=name;
this.number=number;
}
保留以上代码,并添加一段新的代码:
//不区分访问权
try {
Constructor constructor = clazz.getDeclaredConstructor();
System.out.println("1"+constructor.getName());
constructor = clazz.getDeclaredConstructor(String.class);
System.out.println("2"+constructor.getName());
constructor = clazz.getDeclaredConstructor(String.class,Integer.class);
System.out.println("3"+constructor.getName());
} catch (Exception e) {
e.printStackTrace();
}
结果显示为:
此时我们可以发现结果出现了异常,private级别的访问权限无法通过getConstructor()的方式实现获取其Class类。