类是对象,类是java.lang.Class类的实例对象java
public class MyClass {
public static void main(String[] args) {
// People的实例对象
People people = new People();
// 任何一个类,都是java.lang.Class的实例对象
}
}
// People自己就是一个对象,是java.lang.Class的对象
class People { }
复制代码
Class类的三种表达方式android
Class c1 = People.class;
// 方法2:经过已知类对象的getClass方法
Class c2 = people.getClass();
// 方法3:经过Class类静态方法forName()
Class c3 = Class.forName("com.nj.reflect.People");
/* * c一、c2表示了People类的类类型(class type) * 类也是对象,是Class类的实例对象,这个对象咱们称为该类的类类型 */
// 无论是c一、c2仍是c3都表明People的类类型,一个类只多是Class类的一个实例对象。
System.out.print(c1 == c2); // true
System.out.print(c1 == c3); // true
复制代码
获取对象实例git
// 经过People类的类类型c一、c2或c3建立该类的实例对象。
People people1 = (People) c1.newInstance(); // 须要有无参构造方法
复制代码
Class.forName("类的全称")github
静态加载类数组
public class Animal {
public static void main(String[] args) {
if (args[0].equals("Dog")) {
Dog dog = new Dog();
dog.eat();
}
if (args[0].equals("Cat")) {
Cat cat = new Cat();
cat.eat();
}
}
}
class Dog {
public void eat() { }
}
class Cat {
public void eat() { }
}
复制代码
静态加载类的缺点ide
1.若是Dog或者Cat不存在,会报错。可是Dog和Cat不必定会使用。函数
2.经过new建立对象是静态加载类,在编译时刻,就须要加载全部可能使用到的类。spa
动态加载类code
经过Class.forName()动态加载类,就不会在编译时报错了。对象
public class AnimalManager {
public static void main(String[] args){
try {
// 动态加载类,在运行时刻加载。编译不会再报错。
Class c = Class.forName(args[0]);
// 建立对象,经过类类型建立该类的对象
Object o = c.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
复制代码
可是咱们经过c.newInstance()建立类对象的时候,问题来了,是该转换成Dog,仍是该转换成Cat。因此,须要统一标准,建立Animals接口,使Dog和Cat都实现Animals接口。
public class AnimalManager {
public static void main(String[] args){
try {
// 动态加载类,在运行时刻加载。编译不会再报错。
Class c = Class.forName(args[0]);
// 建立对象,经过类类型建立该类的对象
Animals animals = (Animals) c.newInstance();
animals.eat();
} catch (Exception e) {
e.printStackTrace();
}
}
}
interface Animals{
void eat();
}
class Dog implements Animals{
@Override
public void eat() {}
}
class Cat implements Animals{
@Override
public void eat() {}
}
复制代码
优势
1.动态加载,更加灵活
2.方便拓展,若是想要加个Pig类,直接建立Pig类,实现Animals接口和方法便可,无需再修改AnimalManager类。
获取class对象的相关信息
1.获取class对象的成员变量
// 获取class1对象的全部成员变量,不包括父类的成员变量
Field[] allFields = class1.getDeclaredFields();
// 获取class1对象的public成员变量,包括父类里面的成员变量
Field[] publicFields = class1.getFields();
// 获取class1对象指定的成员变量,父类的没法获取
Field name1 = class1.getDeclaredField("name");
// 获取class1对象指定的public成员变量,包括查找父类
Field name2 = class1.getField("name");
// 获取变量的名称
String name = field.getName();
// 获取变量的类型
Class type = field.getType();
复制代码
2.获取class对象的方法
// 获取class1对象的全部方法,不包括父类的方法
Method[] allMethods = class1.getDeclaredMethods();
// 获取class1对象的public方法,包括父类的public方法
Method[] publicMethods = class1.getMethods();
// 获取class1对象指定的方法,父类的没法获取
Method method1 = class1.getDeclaredMethod("getName");
// 获取class1对象指定的方法,而且有一个int类型参数的方法
Method method2 = class1.getDeclaredMethod("getName", int.class);
// 获取class1对象有两个参数的指定方法
Method method3 = class1.getDeclaredMethod("getName", int.class, String.class);
// 获取class1对象指定的public方法,包括父类的public方法。
Method method4 = class1.getMethod("getName");
复制代码
3.获取class对象的构造函数
// 获取class1对象全部的构造函数
Constructor[] allConstructors = class1.getDeclaredConstructors();
// 获取class1对象public的构造函数
Constructor[] publicConstructors = class1.getConstructors();
// 获取class1对象指定参数的构造函数
Constructor constructor1 = class1.getDeclaredConstructor(int.class);
// 获取class1对象指定参数而且为public的构造函数
Constructor constructor2 = class1.getConstructor(int.class, String.class);
复制代码
4.class对象的其余方法
Annotation[] annotations = class1.getAnnotations();// 获取class对象的全部注解
Annotation annotation = class1.getAnnotation(Override.class);// 获取class对象指定注解
Class superclass = class1.getSuperclass(); // 获取class对象直接父类的类对象
Type genericSuperclass = class1.getGenericSuperclass(); // 获取class对象的直接父类的Type
Type[] genericInterfaces = class1.getGenericInterfaces(); // 获取class对象全部接口的Type集合
String name = class1.getName(); // 获取class对象名称,包括报名路径
String simpleName = class1.getSimpleName(); // 获取class类名
Package aPackage = class1.getPackage(); // 获取class包信息
boolean annotation = class1.isAnnotation();// 判断是否为注解类
boolean anEnum = class1.isEnum();// 判断是否为枚举
boolean anInterface = class1.isInterface();// 判断是否为接口类
boolean array = class1.isArray();//判断是否为集合类型
boolean primitive = class1.isPrimitive(); // 判断是否为原始类型(8个基础类型)
boolean anonymousClass = class1.isAnonymousClass(); // 判断是不是匿名内部类
boolean annotation1 = class1.isAnnotationPresent(Override.class);//判断是否被某个注解类修饰
复制代码
5.Method的相关方法
Method method = class1.getMethod("getName", String.class);
String name = method.getName(); // 获取方法名称
// 获取方法的返回值类型的类类型
Class returnType = method.getReturnType();
// 获取方法的参数列表类型的类类型的数组
Class[] parameterTypes = method.getParameterTypes();
复制代码
Java反射的使用
1.生成来的实例对象
// 方法一:调用newInstance()方法,可是这个方法要求class1的类必须有无参构造函数。
Dog dog = (Dog) class1.newInstance();
// 方法二:经过getConstructor获取有参的Constructor构造函数,再调用newInstance()建立实例
Constructor constructor = class1.getConstructor(String.class);
Dog dog1 = (Dog) constructor.newInstance("dog");
复制代码
2.调用类的方法
// 第一步:生成类对象
Dog dog = (Dog) class1.newInstance();
// 第二步:经过class对象的getMethod()等方法,得到具体须要执行的Method对象。
Method method = class1.getDeclaredMethod("getName", String.class);
// 若是方法是private修饰,直接调用invoke,会报错,Java要求程序必须有调用该方法的权限。
// 调用setAccessible,并将参数设置为true,就会取消Java语言的访问权限检查。
method.setAccessible(true);
// 调用Method对象的invoke方法,第一个参数是调用该方法的实例对象,第二个参数是对应须要传入的参数。
// invoke的返回值:若是方法的返回值为void,则invoke返回null,若是不是void,则返回具体的返回值
// 至关于 dog.getName("dog");
Object o = method.invoke(dog, "dog");
复制代码
3.访问成员变量的值
// 第一步:生成类对象
Dog dog = (Dog) class1.newInstance();
// 第二步:经过getDeclaredField等方法,获取相应的Field对象
Field field = class1.getDeclaredField("age");
// 取消Java权限检查
field.setAccessible(true);
// 获取dog对象中age成员变量的值
int age = field.getInt(dog);
// 修改dog对象中age成员变量的值
field.setInt(dog, 25);
// 获取dog对象中String类型的成员变量
Field field1 = class1.getDeclaredField("name");
// 取消Java权限检查
field1.setAccessible(true);
// 获取name变量的值
Object o = field1.get(dog);
// 修改name变量的值
field1.set(dog, "sam");
复制代码
参考资料
1.Java反射