/*
* 类也是一种对象,是java.lang.Class类的实例对象
* */
public class Test {
public static void main(String[] args) {
/*
* 表示Class类的实例有三种方法
* */
//1:
Class c1=Person.class;
//2:
Person person1=new Person();
Class c2=person1.getClass();
try {
//3:
Class c3=Class.forName("yy.study.Person");
System.out.println(c1==c2&&c1==c3&&c2==c3);
/*
* 可以看见输入true,可以得知一个类只会是Class类的一个对象。
* 所以这里的c1,c2,c3均是表示的同一个对象,即Person类的类类型;
* */
//我们可以通过类的类型来创建类的对象
Person person=(Person) c3.newInstance();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Person{
}
类的加载分为动态加载与静态加载:
- 编译时就进行加载的类是静态加载类,通常如果new的对象;
- 运行时用到才加载的类的动态加载类。
动态加载的好处在于,更加灵活。因为如果所有类都是静态加载,如果某一个类不存在就会影响到其它正常类也无法通过编译进行工作。而动态加载不会。即是我不存在,编译也不会报错,直到运行时如果用到了依旧不存在才会报错。
我们先通过获取所有类类型,然后Class c=Class.forName();进行创建的对象便是动态加载某个类;
在Java里,所有基础类型,类里声明的关键字等都有相应的类类型,例如:
Class c1=int.class;
Class c2=String.class;
Class c3=void.class;
//用于获取完整类名
c1.getName();
//用于获取去掉包名的类名
c1.getSimpleName();
通常我们使用反射机制来获取类的信息:
重点关注以下几个类:Class,reflect,reflect下的Constructor,Field,Method
package yy.study;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ClassUtil {
//获取类的名称,以及方法信息
public static void printClassMessage(Person person){
//首先获取对象的类的类类型
Class c1=person.getClass();
//获取类名称
System.out.println(c1.getSimpleName()+"{");
/*
* 通过java.lang.reflect.Method类(反射方法类)进行操作
* 获取类的方法:Method类,一个成员函数就是一个Method对象
* getMethods()获取的是类中的所有public函数,包括从父中继承而来的
* getDeclaredMethods()获取的是类自己声明的函数,包含所有权限。
* */
Method[] ms=c1.getDeclaredMethods();
for(int i=0;i<ms.length;i++){
//获取方法的返回值的类类型
Class returnType=ms[i].getReturnType();
String returnTypeString=returnType.getSimpleName();
System.out.print(returnTypeString+" ");
//得到方法名称
String name=ms[i].getName();
System.out.print(name+"(");
//获取方法参数的类类型
Class[] paramsType=ms[i].getParameterTypes();
for(int x=0;x<paramsType.length;x++){
String paramsTypeString=paramsType[x].getSimpleName();
System.out.print(paramsTypeString+",");
}
System.out.println("){}");
}
System.out.println("}");
}
//获取类的成员变量信息
public static void printClassMemberVariable(Person person){
/*
* 通过java.lang.reflect.Field类(反射领域类)进行操作
* getFields()获取所有public成员变量信息,包括从父继承的
* getDeclaredFields()获取该类自己声明的成员变量信息(所有权限)
* */
Class c1=person.getClass();
Field[] fields=c1.getDeclaredFields();
for(Field field:fields){
//获取变量类型的类类型
Class fieldType=field.getType();
//通过类类型获取变量类型的名称
String fieldTypeString=fieldType.getSimpleName();
//获取变量的名称
String fieldNameString=field.getName();
System.out.print(fieldTypeString+" ");
System.out.println(fieldNameString);
}
}
public static void printClassConstructor(Person person){
Class c1=person.getClass();
/*
* 通过java.lang.reflect.Constructor类来对构造函数进行操作
* getConstructors();return一组Constructor对象,包含该类的public构造函数
* getDeclaredConstructors;包含所有权限的构造函数
* */
Constructor[] constructors=c1.getConstructors();
for(int i=0;i<constructors.length;i++){
/*
* 同样,我们通过对Constructor操作获取需要的信息
* 例如返回值类类型
* 参数类类型
* 构造方法名称
* 。。。。。具体查阅api
* */
constructors[i].getParameterTypes();
constructors[i].getName();
System.out.println(constructors[i].getName());
}
}
}
Main函数:
package yy.study;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
Person person=new Person();
ClassUtil.printClassMessage(person);
System.out.println("*********************");
ClassUtil.printClassMemberVariable(person);
System.out.println("*********************");
ClassUtil.printClassConstructor(person);
}
}
class Father{
int a;
int b;
public String c;
}
class Person extends Father{
private int a;
public int c;
public Person(){
}
private Person(int a,int b){
}
public void start(int a,float b){}
public void hello(){
System.out.println();
}
}
方法反射操作:
- 首先获取到需要的某个方法
- 接着调用method.invoke(对象,参数列表);
public class Test {
public static void main(String[] args) {
// Person person=new Person();
// Class c1=person.getClass();
Class c1=Person.class;
Person person=null;
try {
person = (Person) c1.newInstance();
} catch (InstantiationException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IllegalAccessException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//获取指定函数
try {
/*
* getDeclaredMethod()与getMethod()
* 区别在于前者能控制所有权限函数,后者只能调用public权限函数
* 如果需要调用private,必须setAccessible(true)
* */
Method method=c1.getDeclaredMethod("hello",int.class,int.class);
method.setAccessible(true);
method.invoke(person,3,5);
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Person {
//通过反射调用此private函数
private void hello(int a,int b){
System.out.println("Hello,I am private;"+(a+b));
}
}
我们前面已知反射是绕过编译进行的,而集合的泛型作用是防止错误的输入。我们可以通过反射绕过编译来证明泛型的效用是存在于编译前的。
public class Test {
public static void main(String[] args) {
List a=new ArrayList();
List<String> b=new ArrayList<String>();
Class c1=a.getClass();
Class c2=b.getClass();
System.out.println(c1==c2);
//result为true,可知,在执行过程中集合是去泛型化的
try {
//我们都知道集合有add方法可以添加数据进去,这里我们通过反射来调用此方法
Method method=c2.getDeclaredMethod("add",Object.class);
method.invoke(b,3);
method.invoke(b,"你好");
System.out.println(b);
/*
* 输入结果为[3, 你好],可以看出虽然b集合被我们规定了泛型为String
* 但我们依旧添加成功了int数值3
* 说明泛型只存在于编译过程中进行约束,实际运行时是无效的
* */
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}