反射机制
什么是反射
一般而言,使用一个类,应该先知道这个类,而后通过这个类产生实例化对象,而“反”指的是通过对象找到类。
public class Temp {
public static void main(String[] args){
Person person = new Person(11);// 正着操作
System.out.print(person.getClass().getName());// 反着操作,输出 包名.类名,getClass()是Object的方法(public final Class<?> getClass()),Class是发起一切发射操作的开端
}
}
class Person {
private int age;
public Person(int age){
this.age = age;
}
public void say(){
System.out.print("age = "+age);
}
}
获取Class的实例化对象(三种方式)
/**
* 通过getClass()取得
*/
public class Temp {
public static void main(String[] args){
Person person = new Person(11);
Class<? extends Person> cls = person.getClass();
System.out.print(cls.getName());
}
}
class Person {
private int age;
public Person(int age){
this.age = age;
}
public void say(){
System.out.print("age = "+age);
}
}
/**
* 通过类.class取得
*/
public class Temp {
public static void main(String[] args){
Class<? extends Person> cls = Person.class;
System.out.print(cls.getName());
}
}
class Person {
private int age;
public Person(int age){
this.age = age;
}
public void say(){
System.out.print("age = "+age);
}
}
/**
* 通过Class的静态方法取得(主要使用)
*/
public class Temp {
public static void main(String[] args){
try {
Class<?> aClass = Class.forName("com.xxx.xxx.Person");
System.out.print(aClass.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Person {
private int age;
public Person(int age){
this.age = age;
}
public void say(){
System.out.print("age = "+age);
}
}
每种类型的Class对象只有1个 = 地址只有1个
// 对于2个String类型对象,它们的Class对象相同
Class c1 = "xxx".getClass();
Class c2 = Class.forName("java.lang.String");
// 用==运算符实现两个类对象地址的比较
System.out.println(c1 ==c2);
// 输出结果:true
通过反射实例化一个对象
/**
* 通过Class的静态方法取得(主要使用)
*/
public class Temp {
public static void main(String[] args){
try {
Class<?> aClass = Class.forName("com.xxx.xxx.Person");// 需无参构造
Object obj = aClass.newInstance(); // 通过该方法实例化一个对象
Person person = (Person) obj;
System.out.print(person);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Person {
private int age;
public Person(){// 保证有个无参构造
this.age = 88;
}
public Person(int age){
this.age = age;
}
public void say(){
System.out.print("age = "+age);
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
'}';
}
}
作用
程序开发中,一直强调减少耦合,最好的做法是使用接口,但是就算使用了接口,也逃不出关键字new,所以new才是造成耦合的关键。
工厂设计模式:
public class Temp {
public static void main(String[] args){
Fruit fruit = Factory.getInstance("Apple");
fruit.eat();
}
}
interface Fruit{
void eat();
}
class Apple implements Fruit {
@Override
public void eat() {
System.out.println("eat Apple");
}
}
class Factory{
public static Fruit getInstance(String fruitName){
Fruit fruit = null;
switch (fruitName) {
case "Apple":
fruit = new Apple();
break;
default:
break;
}
return fruit;
}
}
通过反射实现工厂设计模式:
public class Temp {
public static void main(String[] args) {
Fruit fruit = Factory.getInstance("com.xxx.xxx.Apple");
fruit.eat();
}
}
interface Fruit {
void eat();
}
class Apple implements Fruit {
@Override
public void eat() {
System.out.println("eat Apple");
}
}
class Factory {
public static Fruit getInstance(String fruitName) {
Fruit fruit = null;
switch (fruitName) {
case "com.xxx.xxx.Apple":
try {
Class<?> cls = Class.forName("com.xxx.xxx.Apple");
fruit = (Fruit) cls.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
break;
default:
break;
}
return fruit;
}
}
反射的深入应用
对于实例化对象而言,需要调用类中的构造方法、普通方法、属性。这些操作都可以通过反射完成。
调用构造
在Class类中已定义:
getDeclaredConstructor()与getConstructor的区别:
首先看getDeclaredConstructor(Class<?>… parameterTypes)
这个方法会返回制定参数类型的所有构造器,包括public的和非public的,当然也包括private的。
getDeclaredConstructors()的返回结果就没有参数类型的过滤了。
再来看getConstructor(Class<?>… parameterTypes)
这个方法返回的是上面那个方法返回结果的子集,只返回制定参数类型访问权限是public的构造器。
getConstructors()的返回结果同样也没有参数类型的过滤
import java.lang.reflect.Constructor;
public class Temp {
public static void main(String[] args){
try {
Class<?> cls = Class.forName("com.xxx.xxx.Person");
Constructor<?>[] constructors = cls.getConstructors();// 取得该类的全部构造
for (int i = 0;i < constructors.length;i++){
System.out.println("constructors:"+constructors[i]);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Person{
private String name;
private int age;
public Person(){}
public Person(String name){}
public Person(String name,int 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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
结果:
constructors:public com.xxx.Person(java.lang.String,int)
constructors:public com.xxx.Person(java.lang.String)
constructors:public com.xxx.Person()
import java.lang.reflect.Constructor;
public class Temp {
public static void main(String[] args) {
try {
Class<?> cls = Class.forName("com.xxx.xxx.Person");
Constructor<?> constructor = cls.getConstructor(String.class, int.class);
Object tom = constructor.newInstance("tom", 11);//相当于类中,调用了含两个参数的构造方法
System.out.print("tom = "+tom.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Person {
private String name;
private int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
tom = Person{name=‘tom’, age=11}
普通方法
在Class类中已定义:
getDeclaredMethod和getMethod的区别:
getDeclaredMethod:获取当前类的所有声明的方法,包括public、protected和private修饰的方法。需要注意的是,这些方法一定是在当前类中声明的,从父类中继承的不算,实现接口的方法由于有声明所以包括在内。
getMethod:获取当前类和父类的所有public的方法。这里的父类,指的是继承层次中的所有父类。比如说,A继承B,B继承C,那么B和C都属于A的父类。
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Temp {
public static void main(String[] args) {
try {
Class<?> cls = Class.forName("com.xxx.Person");
Method[] methods = cls.getMethods();// 取得所有方法
for (int i = 0;i < methods.length;i++){
System.out.println("Methods :"+methods[i]);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Person {
private String name;
private int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
得到Method类对象的最大作用不在于将类中的所有方法全部列出,而是取得了Method类对象后,可以直接利用反射调用类中的方法:
public native Object invoke(Object obj, Object... args)throws IllegalAccessException,IllegalArgumentException,InvocationTargetException;
实例:
import java.lang.reflect.Method;
public class Temp {
public static void main(String[] args) {
try {
Class<?> cls = Class.forName("com.xxx.Person");
Object obj = cls.newInstance();// 实例化对象
Method setName = cls.getMethod("setName", String.class);
setName.invoke(obj,"tom");// 相当于调用Person实例.setName("tom");
Method getName = cls.getMethod("getName");
System.out.print(getName.invoke(obj));// 相当于调用Person实例.getName();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Person {
private String name;
private int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
调用成员
在Class类中已定义:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Temp {
public static void main(String[] args) {
try {
Class<?> cls = Person.class;
Field[] fields = cls.getDeclaredFields();
for (int i = 0;i < fields.length;i++){
System.out.println("fields :"+fields[i]);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Person {
private String name;
private int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
getDeclaredField和getField的区别:
getDeclaredField() 是可以获取一个类本身的所有字段.
getField() 只能获取类及其父类的public 字段.
如果要调用Filed类中的set()跟get()方法,首先必须调用setAccessible(),让属性对外可见(取消封装):
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Temp {
public static void main(String[] args) {
try {
Class<?> cls = Person.class;
Person obj = (Person) cls.newInstance();// 实例化一个Person对象
Field name = cls.getDeclaredField("name");
name.setAccessible(true);// 接触name属性的封装
name.set(obj,"james");// 相当于对象.属性 = 内容
System.out.println(name.get(obj));// 相当于对象.属性
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Person {
private String name;
private int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}