Java复习——反射

反射机制

什么是反射

一般而言,使用一个类,应该先知道这个类,而后通过这个类产生实例化对象,而“反”指的是通过对象找到类。

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 +
                '}';
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值