java在运行时动态识别对象和类信息的方式有两种:
(1)传统的RTTI(Run-Time Type Identification),他假定我们编译时已经知道了所有类型;
(2)反射机制,允许我们在运行时发现和使用类的信息;
RTTI运行时类型标识主要表现在三个方面:
(1)Class对象: 每个类都有一个Class对象,便以一个新类都会产生Class对象;
(2)强制类型转换:
Parent parent = new Child( );
Child child = (Child)parent;
(3)instanceof关键字用于检查对象是不是属于特定类型;
多态是基于RTTI实现的,其功能主要由Class类实现,Class类是"类的类",如果说类是对象的抽象和集合的话,那么Class类就是对类的抽象和集合,正是由于Class对象的存在,java不会因为类型的向上转型而迷失,这就是多态的原理;
RTTI与反射最大的区别在于:
RTTI在编译时需要知道最重要的东西---类名,而反射在编译期不需要做任何事情,匿名对象信息只有在运行时获取到即可以啦;
下面用多个例子来学习java反射:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class JavaReflect {
/**
* 获取一个类的包名、类名
*/
public static void test1()
{
Employee employee = new Employee();
System.out.println("完整包名: "+employee.getClass().getPackage());
System.out.println("包含包名的类名1: "+employee.getClass().getName());
System.out.println("包含包名的类名2: "+employee.getClass().getCanonicalName());
System.out.println("简单类名1: "+employee.getClass().getSimpleName());
}
/**
* 反射生成实例并且设置实例的属性值
* 通过获得无参构造器生成实例
* 通过public有参构造器生成实例
* 通过private有参构造器生成实例
*/
public static void test2()
{
try {
Class clazz = Class.forName("com.hzw.day33.Employee");
Employee employee = (Employee) clazz.newInstance();//反射生成实例,这里需要Employee对象必须具有无参构造器
employee.setAge(24);
System.out.println("采用无参构造器设置age: "+employee.getAge());
Constructor[] constructors = clazz.getConstructors();
System.out.println("所有的public类型构造器为: ");
for(Constructor constructor :constructors)
{
System.out.println(constructor.getName());
}
Constructor[] constructors2 = clazz.getDeclaredConstructors();
System.out.println("所有构造器(包括public和private的类型)");
for(Constructor constructor:constructors2)
{
System.out.println(constructor.getName());
}
try {
Constructor constructor3 = clazz.getDeclaredConstructor(String.class,int.class);
Employee employee2 = (Employee) constructor3.newInstance("hzw",20);
System.out.println("采用public有参构造器设置age值: "+employee2.age);
Constructor constructor4 = clazz.getDeclaredConstructor(String.class);
constructor4.setAccessible(true);//设置私有构造器为可以访问
Employee employee3 = (Employee) constructor4.newInstance("huzhiwei");
System.out.println("采用private有参构造器设置name值: "+employee3.name);
} catch (Exception e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* 通过反射操作成员变量
*/
public static void test3()
{
try {
Class clazz = Class.forName("com.hzw.day33.Employee");
Employee employee = (Employee) clazz.newInstance();
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(employee, "huzhiwei");
System.out.println("通过反射生成设置employee的name属性为: "+employee.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 通过反射获取到父类以及接口
*/
public static void test4()
{
try {
Class clazz = Class.forName("com.hzw.day33.Employee");
System.out.println("父类是: "+clazz.getSuperclass());
Class[] interfaces = clazz.getInterfaces();
System.out.println("所有接口为: ");
for(Class c:interfaces)
{
System.out.println(c);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 通过反射获取所有类方法(包括私有的)并且调用类方法
*/
public static void test5()
{
try {
Class clazz = Class.forName("com.hzw.day33.Employee");
Method[] methods = clazz.getDeclaredMethods();//获取到所有的method
System.out.println("获取到的所有method方法如下: ");
for(Method method:methods)
{
System.out.println("函数方法名: "+method.getName()+" 函数返回类型: "+method.getReturnType()+" 函数访问修饰符"+Modifier.toString(method.getModifiers())+" 函数本身: "+method);
}
//反射调用函数
Method method1 = clazz.getDeclaredMethod("print");
method1.setAccessible(true);//需要设置print函数是可访问的
System.out.println("反射调用无参函数: ");
method1.invoke(clazz.newInstance(),null);//还有一种写法:method1.invoke(clazz.newInstance());
System.out.println("反射调用有参函数: ");
Method method2 = clazz.getDeclaredMethod("printName",String.class);
method2.setAccessible(true);
method2.invoke(clazz.newInstance(), "山西");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 通过反射获得类加载器
*/
public static void test6()
{
try {
Class clazz = Class.forName("com.hzw.day33.Employee");
System.out.println("类加载器为: "+clazz.getClassLoader());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println("test1");
test1();
System.out.println("---------------------------------------");
System.out.println("test2");
test2();
System.out.println("---------------------------------------");
System.out.println("test3");
test3();
System.out.println("---------------------------------------");
System.out.println("test4");
test4();
System.out.println("---------------------------------------");
System.out.println("test5");
test5();
System.out.println("---------------------------------------");
System.out.println("test6");
test6();
System.out.println("---------------------------------------");
}
}
class Employee extends Manager implements DoSomething,CompleteSomething
{
public String name;
public int age;
public Employee() {
}
private Employee(String name)
{
this.name = name;
}
public Employee(String name,int age) {
this.name = name;
this.age = age;
}
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 int changeAge()
{
age = age+1;
return age;
}
private void print()
{
System.out.println("正在调用print方法");
}
public void printName(String name)
{
System.out.println("调用printName输出名字为: "+name);
}
}
class Manager
{
}
interface DoSomething
{
}
interface CompleteSomething
{
}
/*
输出:
test1
完整包名: package com.hzw.day33
包含包名的类名1: com.hzw.day33.Employee
包含包名的类名2: com.hzw.day33.Employee
简单类名1: Employee
---------------------------------------
test2
采用无参构造器设置age: 24
所有的public类型构造器为:
com.hzw.day33.Employee
com.hzw.day33.Employee
所有构造器(包括public和private的类型)
com.hzw.day33.Employee
com.hzw.day33.Employee
com.hzw.day33.Employee
采用public有参构造器设置age值: 20
采用private有参构造器设置name值: huzhiwei
---------------------------------------
test3
通过反射生成设置employee的name属性为: huzhiwei
---------------------------------------
test4
父类是: class com.hzw.day33.Manager
所有接口为:
interface com.hzw.day33.DoSomething
interface com.hzw.day33.CompleteSomething
---------------------------------------
test5
获取到的所有method方法如下:
函数方法名: getName 函数返回类型: class java.lang.String 函数访问修饰符public 函数本身: public java.lang.String com.hzw.day33.Employee.getName()
函数方法名: setName 函数返回类型: void 函数访问修饰符public 函数本身: public void com.hzw.day33.Employee.setName(java.lang.String)
函数方法名: print 函数返回类型: void 函数访问修饰符private 函数本身: private void com.hzw.day33.Employee.print()
函数方法名: setAge 函数返回类型: void 函数访问修饰符public 函数本身: public void com.hzw.day33.Employee.setAge(int)
函数方法名: getAge 函数返回类型: int 函数访问修饰符public 函数本身: public int com.hzw.day33.Employee.getAge()
函数方法名: printName 函数返回类型: void 函数访问修饰符public 函数本身: public void com.hzw.day33.Employee.printName(java.lang.String)
函数方法名: changeAge 函数返回类型: int 函数访问修饰符public 函数本身: public int com.hzw.day33.Employee.changeAge()
反射调用无参函数:
正在调用print方法
反射调用有参函数:
调用printName输出名字为: 山西
---------------------------------------
test6
类加载器为: sun.misc.Launcher$AppClassLoader@6c68bcef
---------------------------------------
*/
注意点:
(1)getConstructors与getDeclaredConstructor的区别:
getConstructors得到的是所有public类型的构造函数,getDeclaredConstructor得到的是所有构造函数,包括public、private等等类型的;
(2)setAccessible(true)的用途:设置某个private类型的函数可以访问;