Java面向对象之 通过反射创建对象、通过反射访问类中的成员 及 案例练习

1、通过反射创建对象

1.1、基本说明

在这里插入图片描述

1.2、案例演示

测试 1:通过反射创建某类的对象,要求该类中必须有 public 的无参构造
测试 2:通过调用某个特定构造器的方式,实现创建某类的对象

package reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 通过反射机制创建实例
 */
public class ReflecCreateInstance {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        // 1. 先获取到 User 类的 Class 对象
        Class<?> userClass = Class.forName("reflection.User");
        // 2. 通过 public 的无参构造器创建实例
        Object o = userClass.newInstance();
        System.out.println(o);  // User [age=10, name=张三]
        // 3. 通过 public 的有参构造器创建实例
        /*
        constructor 对象就是
        public User(String name) {  // public 的有参构造器
            this.name = name;
        }
        */
        // 3.1 先得到对应构造器
        Constructor<?> constructor = userClass.getConstructor(String.class);
        // 3.2 创建实例, 并传入实参
        Object jack = constructor.newInstance("jack");
        System.out.println("jack=" + jack);  // jack=User [age=10, name=jack]
        // 4. 通过非 public 的有参构造器创建实例
        // 4.1 得到 private 的构造器对象
        Constructor<?> declaredConstructor = userClass.getDeclaredConstructor(int.class, String.class);
        // 4.2 创建实例
        // 暴破[暴力破解], 使用反射可以访问 private 构造器/方法/属性, 反射面前, 都是纸老虎
        declaredConstructor.setAccessible(true);
        Object lucy = declaredConstructor.newInstance(100, "lucy");
        System.out.println("lucy=" + lucy);  // lucy=User [age=100, name=lucy]
    }
}

class User {  // User 类
    private int age = 10;
    private String name = "张三";

    public User() {  // 无参 public
    }

    public User(String name) {  // public 的有参构造器
        this.name = name;
    }

    private User(int age, String name) {  // private 有参构造器
        this.age = age;
        this.name = name;
    }

    public String toString() {
        return "User [age=" + age + ", name=" + name + "]";
    }
}

2、通过反射访问类中的成员

2.1、访问属性

在这里插入图片描述

package reflection;

import java.lang.reflect.Field;

/**
 * 反射操作属性
 */
public class ReflecAccessProperty {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        // 1. 得到 Student 类对应的 Class 对象
        Class<?> stuClass = Class.forName("reflection.Student");
        // 2. 创建对象
        Object o = stuClass.newInstance();
        System.out.println(o.getClass());  // o 的运行类型就是 class reflection.Student
        // 3. 使用反射得到 age 属性对象
        Field age = stuClass.getField("age");
        age.set(o, 80);  // 通过反射来操作属性
        System.out.println(o);  // Student [age=80, name=null]
        System.out.println(age.get(o));  // 返回 age 属性的值 80
        // 4. 使用反射操作 name 属性
        Field name = stuClass.getDeclaredField("name");
        // 对 name 进行暴破, 可以操作 private 属性
        name.setAccessible(true);
        name.set(o, "tom");
        System.out.println(o);  // Student [age=80, name=tom]
        name.set(null, "lily");  // 因为 name 是 static 属性, 因此 o 也可以写成 null
        System.out.println(o);  // Student [age=80, name=lily]
        System.out.println(name.get(o));  // 获取属性值 lily
        System.out.println(name.get(null));  // 获取属性值, 要求 name 是 static  lily
    }
}

class Student {  // 类
    public int age;
    private static String name;

    public Student() {  // 构造器
    }

    public String toString() {
        return "Student [age=" + age + ", name=" + name + "]";
    }
}
2.2、访问方法

在这里插入图片描述

package reflection;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 通过反射调用方法
 */
@SuppressWarnings({"all"})
public class ReflecAccessMethod {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        // 1. 得到 Boss 类对应的 Class 对象
        Class<?> bossClass = Class.forName("reflection.Boss");
        // 2. 创建对象
        Object o = bossClass.newInstance();
        // 3. 调用 public 的 hi 方法
        // Method hi = bossClass.getMethod("hi", String.class);
        // 3.1 利用getDeclaredMethod 得到 hi 方法对象 (公开方法和非公开方法都能用)
        Method hi = bossClass.getDeclaredMethod("hi", String.class);
        // 3.2 调用
        hi.invoke(o, "jack");  // hi jack
        // 4. 调用 private static 方法
        // 4.1 得到 say 方法对象
        Method say = bossClass.getDeclaredMethod("say", int.class, String.class, char.class);
        // 4.2 因为 say 方法是 private, 所以需要暴破,原理和前面构造器和属性一样
        say.setAccessible(true);
        System.out.println(say.invoke(o, 100, "lucy", '男'));  // 100 lucy 男
        // 4.3 因为 say 方法是 static 的, 还可以这样调用, 可以传入 null
        System.out.println(say.invoke(o, 30, "lily", '女'));  // 30 lily 女
        // 5. 在反射中, 如果方法有返回值, 统一返回 Object, 但是他运行类型和方法定义的返回类型一致
        Object reVal = say.invoke(null, 300, "allen", '男');
        System.out.println("reVal 的运行类型=" + reVal.getClass());  // reVal 的运行类型=class java.lang.String
        // 一个返回的案例
        Method m1 = bossClass.getDeclaredMethod("m1");
        Object reVal2 = m1.invoke(o);
        System.out.println("reVal2 的运行类型=" + reVal2.getClass());  // reVal2 的运行类型=class reflection.Monster
    }
}

class Monster {
}

class Boss {  // 类
    public int age;
    private static String name;

    public Boss() {  // 构造器
    }

    public Monster m1() {
        return new Monster();
    }

    private static String say(int n, String s, char c) {  // 静态方法
        return n + " " + s + " " + c;
    }

    public void hi(String s) {  // 普通 public 方法
        System.out.println("hi " + s);
    }
}

3、案例练习

在这里插入图片描述

package reflection;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Homework01 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
        /**
         * 定义PrivateTest类, 有私有name属性,并且属性值为hellokitty
         * 提供getName的公有方法
         * 创建PrivateTest的类, 利用Class类得到私有的name属性, 修改私有的name属性值, 并调用getName()的方法打印name属性值
         */
        // 1. 得到 PrivateTest类对应的Class对象
        Class<PrivateTest> privateTestClass = PrivateTest.class;
        // 2. 创建对象实例
        PrivateTest privateTest = privateTestClass.newInstance();
        // 3. 得到name属性对象
        Field name = privateTestClass.getDeclaredField("name");
        // 4. 暴破name
        name.setAccessible(true);
        name.set(privateTest, "helloworld");
        System.out.println(name.get(privateTest));  // helloworld
        // 5. 得到getName方法对象
        Method method = privateTestClass.getMethod("getName");
        // 6. 因为getName() 是public, 所有直接调用
        Object invoke = method.invoke(privateTest);
        System.out.println("name属性值=" + invoke);  // name属性值=helloworld
    }
}

class PrivateTest {
    private String name = "hellokitty";

    // 默认无参构造器
    public String getName() {
        return name;
    }
}

在这里插入图片描述

package reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Homework02 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        /**
         * 利用Class类的forName方法得到File类的class 对象
         * 在控制台打印File类的所有构造器
         * 通过newInstance的方法创建File对象,并创建E:\mynew.txt文件
         */
        // 1. Class类的forName方法得到File类的class 对象
        Class<?> fileClass = Class.forName("java.io.File");
        // 2. 得到所有的构造器
        Constructor<?>[] declaredConstructors = fileClass.getDeclaredConstructors();
        // 3. 遍历输出
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
            /*
                public java.io.File(java.lang.String,java.lang.String)
                public java.io.File(java.lang.String)
                private java.io.File(java.lang.String,java.io.File)
                public java.io.File(java.io.File,java.lang.String)
                public java.io.File(java.net.URI)
                private java.io.File(java.lang.String,int)
            */
        }
        // 4. 指定的得到 public java.io.File(java.lang.String)
        Constructor<?> declaredConstructor = fileClass.getDeclaredConstructor(String.class);
        String fileAllPath = "e:\\mynew.txt";
        Object file = declaredConstructor.newInstance(fileAllPath);  // 创建File对象
        // 5. 得到createNewFile 的方法对象
        Method createNewFile = fileClass.getMethod("createNewFile");
        createNewFile.invoke(file);  // 创建文件, 调用的是 createNewFile
        // file的运行类型就是File
        System.out.println(file.getClass());  // class java.io.File
        System.out.println("创建文件成功: " + fileAllPath);  // 创建文件成功: e:\mynew.txt
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值