1.class类的使用
java.lang.Class类的实例。
创建一个类类型的三种方法:
1)Foo类的对象是 foo1
Foo foo1=new Foo();
Class c2 = foo1.getClass() --->已知该类的对象,通过该类的对象通过getClass方 法获取Foo类的类类型
2)Foo类的类类型c1指的是Class的对象
Class c1 = Foo.class; //任何一个类都有一个隐含的静态成员变量
3)Class c3=Class.forName("com.imooc.reflect.Foo");
三种方式创建的类类型都相等,都是Foo的类类型;
Class的用法:
可以通过类的类类型创建Foo的实例对象
Foo foo=(Foo)c1.newInstance(); //注意需要强制类型转换,且需要有一个无参的构造方法
2. Java 动态加载类
这里我们首先要区分什么是动态加载什么是静态加载
Class.forName(“类的全称”)
- 不仅表示了类的类类型,还代表了动态加载类
- 请大家区分编译、运行,不要把编译运行混为一谈
- 编译时刻加载类是静态加载类、运行时刻加载类是动态加载类
类分为 2 种:
1、静态加载类
编译时,加载的类是静态加载类。
Foo foo = new Foo();
创建对象是静态加载类,编译时就要加载所有要用到的类,如果其中 1 个类有问题,就无法通过编译。解决该问题,可以使用动态加载类。
2、动态加载类
运行时,加载的类是动态加载类
Class.forName(“com.reflect.Foo”);
编译时不检查用到的类是否存在,运行时再检查。可以通过实现同一个接口的方式,来对类的规范进行统一。功能性的类最好还是使用动态加载,而不是静态加载。动态加载类指的是程序运行时加载类,而静态加载指的是编译时加载类,编译时加载的缺点是程序中所有的功能都不能有差错,否则的话程序就不能用了,而动态加载类的好处就是我们需要使用哪一个类虚拟机就会动态加载根据我们的需要动态的加载这个类,这样程序的使用就不会受到其他的影响。
新建一个接口,A继承它,新建一个类,用反射技术通过一个类的名字得到其类类型at,然后接口类Interface a = (Interface)ai.newInstance();来实例化,这样就可以在不实现B的情况下实现A。
3.Java 获取方法信息
基本的数据类型,void关键字等都存在类类型
public class interfaceDemo1 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Class c1=int.class;//int的类类型
Class c2=String.class;//Strng的类类型
Class c3=double.class;
Class c4=Double.class;
Class c5=void.class;
System.out.println(c1.getName());//输出结果int
System.out.println(c2.getName());//输出结果java.lang.String
System.out.println(c2.getSimpleName());//不包含包名的类的名称,输出结果String
System.out.println(c5.getName());//输出结果void
}
}
Class类的基本API操作,写一个案例,拿到类的全部信息
public class interfaceDemo2 {
//打印类的信息,包括类的成员函数,成员变量。obj对象所属类的信息
public static void printClassMethodMessage(Object obj) {
//要获取类的信息,首先要获取类的类类型
Class c=obj.getClass();//因为Object类是一切类的父类,传递的是哪个子类的对象
//c就是该子类的类类型
//获取类的名字
System.out.println("类的名称是:"+c.getName());
//接下来我们想获取它的方法,方法也是对象,在java里,方法是Method对象
//Method[] ms=c.getDeclaredMethods();//获取所有该类自己声明的方法,不问访问权限,继承来的就没有了
Method[] ms=c.getMethods();//获取所有public的函数,包括父类继承而来的
for (Method method : ms) {
//获取方法的返回值类型的类类型,要拿到名字还得进行第二步
Class returnType=method.getReturnType();
System.out.print(returnType.getName()+" ");
//获取方法名
System.out.print(method.getName()+"(");
//后面应该是参数1和参数2的类型,所以前面的方法名后面加一个括号
//获取参数类型,得到的是参数列表的类型的类类型
Class[] paramTypes=method.getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName()+",");
}
System.out.print(")");
//方法信息都获取到了
System.out.println();
printFieldMessage(c);
}
}
4.获取成员变量构造函数信息
/**
* 获取成员变量的信息
* @param obj
*/
public static void printFieldMessage(Object obj) {
//获取成员变量信息
//成员变量也是对象
//java.lang.reflect.Field类,Field类封装了关于成员变量的操作
//getFields()方法获取的是所有public成员变量的信息
//Field[] fs=c.getFields();
//getDeclaredFields()获取的是该类自己声明的成员变量的信息
Class c=obj.getClass();
Field[] f=c.getDeclaredFields();
for (Field field : f) {
//得到成员变量的类型的类类型
Class fieldType=field.getType();
String typeName=fieldType.getName();
//得到成员变量的名称
String fieldName=field.getName();
System.out.println(typeName+","+fieldName );
}
}
/**
* 打印对象的构造函数的信息
*/
public static void printConMessage(Object obj) {
Class c=obj.getClass();
//构造函数也是对象,java.lang.Constructor中封装了构造函数的信息
//Constructor[] con=c.getConstructors();//获取所有的共有的构造方法
Constructor[] cs=c.getDeclaredConstructors();//获取自己声明的所有构造函数
for (Constructor constructor : cs) {
//构造方法没有返回值类型,所以直接名字加参数
System.out.print(constructor.getName()+"(");
//获取构造函数的参数列表
Class[] paramTypes=constructor.getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName()+",");
}
System.out.println(")");
}
}
public class interfaceDemo3 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
// String s="hello";
// interfaceDemo2.printClassMethodMessage(s);
//
// Integer n1=1;
// interfaceDemo2.printClassMethodMessage(n1);
interfaceDemo2.printConMessage("hello");
}
}
5.方法反射的基本操作
package interfaceDemo;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodDemo1 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
//要获取print方法,print(int,int)
//1.要获取一个方法,就是获取类的信息,获取类的信息首先要获取类的类类型
//假设是A的对象
A a1=new A();
Class c=a1.getClass();
//2.获取方法,方法必须要有名称和参数列表来决定
//c.getMethod(...)获取的是public方法
//c.getDeclaredMethod(..)获取的是自己声明的方法
try {
Method m=c.getMethod("print", int.class,int.class);//两种都可以
//Method m=c.getDeclaredMethod("print", new Class[] {int.class,int.class});
//方法的反射操作
//a1.print(10, 20);
//方法的反射操作是用m对象来进行方法的调用,和上面的调用效果完全相同
//方法如果没有返回值,返回null。有返回值返回具体的返回值。
//用m也就是print方法的对象反过来调用a1对象以及参数。
//Object o=m.invoke(a1,new Object[] {10,20});
m.invoke(a1, 10,20);//这样也可以,帮助里参数...就可以有几个传几个或者直接传数组。
System.out.println("---------------------------");
Method n=c.getDeclaredMethod("print", String.class,String.class);
//a1.print("hello", "World");
n.invoke(a1,"hello","World");
} catch (NoSuchMethodException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (SecurityException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
class A{
public void print(int a,int b) {
System.out.println(a+b);
}
public void print(String a,String b) {
System.out.println(a.toUpperCase()+","+b.toLowerCase());
}
}
无参直接不写参数单独写一个对象即可。
6.Java 通过反射了解集合泛型的本质
通过Class,Method来认识泛型的本质
public class interfaceDemo4 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
ArrayList a1=new ArrayList();
ArrayList<String> a2=new ArrayList<String>();
Class c1=a1.getClass();
Class c2=a2.getClass();
System.out.println(c1==c2);
//反射的操作都是编译之后的操作
//这里的结果是true,编译后是去泛型化的,所以结果为true,编译之后没有泛型
//JAVA中集合的泛型是防止错误输入的,只在编译阶段有效,绕过编译就无效了。
//验证我们可以通过方法的反射来操作绕过编译。
try {
Method m=c1.getMethod("add", Object.class);
m.invoke(a2,20);
System.out.println(a2.size());
System.out.println(a2);
//此时注意不能使用foreach遍历a2集合,因为遍历的时候它还会默认是String类型,这样就会报错
} catch (NoSuchMethodException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (SecurityException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
7.根据对象的属性名获取其属性值
import java.lang.reflect.Method;
public class BeanUtil {
/**
* 根据标准javaBean对象的属性名获取其属性值
*
* @param obj
* @param propertyName
* @return
*/
public static Object getValueByPropertyName(Object obj, String propertyName) {
// 1.根据属性名称就可以获取其get方法
String getMethodName = "get"
+ propertyName.substring(0, 1).toUpperCase()
+ propertyName.substring(1);
//2.获取方法对象
Class c = obj.getClass();
try {
//get方法都是public的且无参数
Method m= c.getMethod(getMethodName);
//3 通过方法的反射操作方法
Object value = m.invoke(obj);
return value;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}