反射(下)

目录

调用构造

可以利用反射获取构造方法进行实例化。
在这里插入图片描述

常用方法:

方法说明
public Constructor getConstructor(Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException根据指定的参数类型获取指定的构造方法 (public)
public Constructor<?>[] getConstructors() throws SecurityException获取类中的所有构造方法,以数组的形式返回 (public)
public Constructor getDeclaredConstructor(Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException获取指定的构造方法 (public default protected)
public Constructor<?>[] getDeclaredConstructors() throws SecurityException获取类中的所有构造方法,以数组的形式返回 (public default protected)

getDeclaredConstructor()可以获取的构造方法类型要比getConstructor()多。

示例:

public class TestConstructor {
    public static void main(String[] args) throws NoSuchMethodException {
        int number;
        Class<?> clazz = BasketBall.class;
        //获取构造方法(获取无参构造)
        System.out.println("---getConstructor---");
        Constructor<?> constructor = clazz.getConstructor();
        System.out.println("|-BasketBall无参构造:" + constructor);
        //获取构造方法(获取有参构造)
        Constructor<?> constructorNot = clazz.getConstructor(String.class, double.class);
        System.out.println("|-BasketBall有参构造:" + constructorNot);
        //获取所有构造方法
        System.out.println("---getConstructors---");
        Constructor<?>[] constructors = clazz.getConstructors();
        number = 0;
        for (Constructor con : constructors) {
            System.out.println("|-BasketBall构造方法" + ++number + "【" + con + "】");
        }
        System.out.println();
        //获取父类的无参构造
        System.out.println("获取父类的无参构造:"+clazz.getSuperclass().getConstructor());

        System.out.println();
        System.out.println("---getDeclaredConstructor---");
        //获取构造方法(获取无参构造)
        Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();
        System.out.println("|-BasketBall无参构造:" + declaredConstructor);
        //获取构造方法(获取有参构造)
        Constructor<?> declaredConstructorNot = clazz.getConstructor(String.class, double.class);
        System.out.println("|-BasketBall有参构造:" + declaredConstructorNot);
        System.out.println("---getDeclaredConstructors---");
        //获取所有构造方法
        Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
        number = 0;
        for (Constructor con : declaredConstructors) {
            System.out.println("|-BasketBall构造方法" + ++number + "【" + con + "】");
        }
    }
}

结果:

---getConstructor---
|-BasketBall无参构造:public com.tx.test.constructor.BasketBall()
|-BasketBall有参构造:public com.tx.test.constructor.BasketBall(java.lang.String,double)
---getConstructors---
|-BasketBall构造方法1public com.tx.test.constructor.BasketBall()|-BasketBall构造方法2public com.tx.test.constructor.BasketBall(java.lang.String,double)】

获取父类的无参构造:public com.tx.test.constructor.AbstractBall()

---getDeclaredConstructor---
|-BasketBall无参构造:public com.tx.test.constructor.BasketBall()
|-BasketBall有参构造:public com.tx.test.constructor.BasketBall(java.lang.String,double)
---getDeclaredConstructors---
|-BasketBall构造方法1public com.tx.test.constructor.BasketBall()|-BasketBall构造方法2public com.tx.test.constructor.BasketBall(java.lang.String,double)

在反射中可以利用newInstance()利用反射对类调用指定的构造方法进行实例化操作:

示例:

public class TestNewInstance {(JDK1.9推荐的方法)
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<?> clazz = BasketBall.class;
        BasketBall basketBallA = (BasketBall) clazz.getConstructor(String.class, double.class).newInstance("361", 199);	//getConstructor获取不到protected修饰的构造方法
    	//getDeclaredConstructor(传入属性的类型的类对象(String.class))
        BasketBall basketBallB = (BasketBall) clazz.getDeclaredConstructor(String.class, String.class, double.class).newInstance("篮球", "李宁牌", 199.0);
        System.out.println(basketBallA);
        System.out.println(basketBallB);
    }
}

结果:

BasketBall{name='null', brand='361', price=199.0}
BasketBall{name='篮球', brand='李宁牌', price=199.0}

在JDK1.8及以前主要有两个不同的进行实例化的方法:

  • Class类: public T newInstance() throws InstantiationException, IllegalAccessException**(在JDK1.8中使用此方法只能调用无参构造)**

    在JDK1.9被替换成 clazz.getDeclaredConstructor(设置调用的构造方法).newInstance(根据调用的构造方法传值)

  • Constructor类: public T newInstance(Object… initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException

调用成员(对成员进行操作)

通过反射调用成员属性,获取属性的类型进行操作。
在这里插入图片描述

常用方法:

方法说明
public Field getField(String name) throws NoSuchFieldException, SecurityException获取指定的成员属性 (public)
public Field[] getFields() throws SecurityException获取所有的成员属性 (public)
public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException获取指定的成员属性 (所有修饰符)
public Field[] getDeclaredFields() throws SecurityException获取所有的成员属性 (所有修饰符)
public Class<?> getType()获取成员属性类型
public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException获取属性内容
public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException可以给数据赋值,设置属性内容(解锁后)
public void setAccessible(boolean flag)锁,可以解除成员属性封装

示例:

public class TestFiled {
    public static void main(String[] args) throws Exception{
        Class<?> clazz = BasketBall.class;
        //只可以获取public修饰的属性
        Field[] fields = clazz.getFields();
        System.out.println(Arrays.toString(fields));
        System.out.println();
        //可以获取所有修饰符修饰的属性
        Field[] fieldAll = clazz.getDeclaredFields();
        for (Field field : fieldAll) {
            System.out.println(field);
        }
        //进行实例化操作,获取BasketBall的实例化对象
        BasketBall basketBall = (BasketBall) clazz.getDeclaredConstructor().newInstance();
        //获取name属性(所有修饰符修饰的属性都可以获取)
        Field fieldName = clazz.getDeclaredField("name");
        System.out.println(fieldName);
        System.out.println();
        //获取属性类型的名字
        System.out.println(fieldName.getType().getName());
        //获取属性的名字
        System.out.println(fieldName.getName());
        //解锁(private的属性不能使用set赋值,要先解锁)
        fieldName.setAccessible(true);
        //给name赋值
        fieldName.set(basketBall, "篮球");
        //输出name的值
        System.out.println(fieldName.get(basketBall));
    }
}

结果:

[]

private java.lang.String com.tx.test.constructor.BasketBall.name
private java.lang.String com.tx.test.constructor.BasketBall.brand
private double com.tx.test.constructor.BasketBall.price
private java.lang.String com.tx.test.constructor.BasketBall.name

java.lang.String
name
篮球

封装只局限于标准语法,反射可以解除封装对数据进行操作(一般不要用)。

调用方法

利用反射调用setter和getter,实现代码重用。
在这里插入图片描述
常用方法:

方法说明
public Method getDeclaredMethod(String name(方法名称), Class<?>… parameterTypes(参数的类型)) throws NoSuchMethodException, SecurityException获取本类中指定的方法
public Method[] getDeclaredMethods() throws SecurityException获取本类中所有的方法
public Method getMethod(String name(方法名称), Class<?>… parameterTypes(参数的类型)) throws NoSuchMethodException, SecurityException获取指定的公共方法(包括父类)
public Method[] getMethods() throws SecurityException获取所有的公共方法(包括父类)

示例: 方法的使用

public class TestMethod {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("com.tx.test.constructor.BasketBall");
        Object object = clazz.getDeclaredConstructor().newInstance();
        Method methodNotAll = clazz.getMethod("wait");
        //geMethod:获取指定公共方法(包括父类)
        System.out.println(methodNotAll);
        System.out.println("--------------------------------------------------------------");
        //geMethods:获取所有公共方法(包括父类)
        Method[] methodPublic = clazz.getMethods();
        for(Method method:methodPublic){
            System.out.println(method);
        }
        System.out.println("--------------------------------------------------------------");
        Method methodBody = clazz.getMethod("toString");
        //geMethod:获取指定公共方法(包括父类)
        System.out.println(methodNotAll);
        System.out.println("--------------------------------------------------------------");
        //获取本类所有的方法
        Method[] methodAll = clazz.getDeclaredMethods();
        for(Method method:methodAll){
            System.out.println(method);
        }
    }
}

**示例:**获取全部的公共方法(包括父类),进行还原

public class TestMethodGet {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("com.tx.test.constructor.BasketBall");
        Object object = clazz.getDeclaredConstructor().newInstance();
        //获取全部的公共方法(包括父类)
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            //method.getModifiers():返回一串数字,是用来表示修饰符,Modifier.toString()可以解析
            System.out.print(Modifier.toString(method.getModifiers()) + " ");
            //删除掉(java.lang.String)和(java.lang.Class)的 (java.lang.)
            if ((String.class.getName().equals(method.getReturnType().getName())) || Class.class.getName().equals(method.getReturnType().getName())) {
                //method.getReturnType().getName():获取返回值类型
                System.out.print(method.getReturnType().getName().substring(10) + " ");
            } else {
                System.out.print(method.getReturnType().getName() + " ");
            }
            //method.getName():方法名
            System.out.print(method.getName() + "(");
            //获取参数
            Parameter[] parameters = method.getParameters();
            for (int i = 0; i < parameters.length; ++i) {
                if (Object.class.getName().equals(parameters[i].getType().getName())) {
                    System.out.print(parameters[i].getType().getName().substring(10) + " " + parameters[i].getName());
                } else {
                    System.out.print(parameters[i]);

                }
                if (i < parameters.length - 1) {
                    System.out.print(",");
                }
            }
            System.out.print(")");
            //method.getExceptionTypes():获取异常
            Class<?>[] methodException = method.getExceptionTypes();
            for (int i = 0; i < methodException.length; ++i) {
                System.out.print(" throws " + methodException[i].getTypeName().substring(10));
                if (methodException.length - 1 > i) {
                    System.out.print(",");
                }
            }

            System.out.println();
            System.out.println();
        }
    }
}

结果:

public String toString()

public final native void wait(long arg0) throws InterruptedException

public final void wait(long arg0,int arg1) throws InterruptedException

public final void wait() throws InterruptedException

public boolean equals(Object arg0)

public native int hashCode()

public final native Class getClass()

public final native void notify()

public final native void notifyAll()
方法说明
public Object invoke(Object obj, Object… args)可以依据Object的实例化对象(不一定是具体类型)实现反射方法调用

示例: invoke()的用法

public class TestGetAndSet {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("com.tx.test.constructor.BasketBall");
        Object object = clazz.getDeclaredConstructor().newInstance();
        String fileName = "name";
        String fileValue = "篮球";
        Method methodSet =  clazz.getDeclaredMethod( "set" + StringUtil.toUpperCaseString(fileName),String.class);
        //赋值
        methodSet.invoke(object,fileValue);
        Method methodGet =  clazz.getDeclaredMethod( "get" + StringUtil.toUpperCaseString(fileName));
        Object method =  methodGet.invoke(object);
       System.out.println(methodGet.getName()+"():"+method);
    }
}
/**
 * 首字母大写
 */
class StringUtil {
    public static String toUpperCaseString(String fileName) {
        if (fileName == null || "".equals(fileName)) {
            return fileName;
        }

        if(fileName.length() == 1){
            return fileName.toUpperCase();
        }
        return fileName.substring(0,1).toUpperCase() + fileName.substring(1);
    }
}

结果:

getName():篮球

UnSafe

Unsafe打破了JVM的对象模型,可以跳过实例化机制,直接调用普通方法,表示所有的处理全有程序自己完成,会导致回收机制失效。

示例: 懒汉式单例在没有实例化的情况下,使用Unsafe直接调用普通方法

public class TestUnsafe {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, NoSuchFieldException, IllegalAccessException {
        //获取Animal
        Class<?> clazz = Class.forName("com.tx.test.unsafe.Animal");
        //获取Unsafe
        Class<?> c = Class.forName("sun.misc.Unsafe");
        //获取Unsafe的成员属性
        Field unsafeField = c.getDeclaredField("theUnsafe");
        //解锁(解除封装)
        unsafeField.setAccessible(true);
        //获取Unsafe对象
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        //获取Animal对象
        Animal animal = (Animal) unsafe.allocateInstance(clazz);
        //调用print方法
        animal.print();
    }
}

class Animal {
    private static Animal animal;

    private Animal() {
    }

    public static Animal getInstance() {
        if (animal == null) {
            synchronized (Animal.class) {
                if(animal == null){
                    animal = new Animal();
                }
            }
        }
        return animal;
    }

    public void print(){
        System.out.println("输出");
    }
}

结果:

输出

(注意)笔试编写单例模式:

1、单例模式要使用懒汉式单例模式。

2、要针对数据的的同步做出处理。

3、利用Unsafe可以直接跳过懒汉式单例模式的实例化操作,直接调用普通方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值