欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

初学者对java反射的深入理解

程序员文章站 2022-03-29 17:09:40
...

java反射的深入理解

1.反射的class类代表生成的字节码对应的类,代表了类的类

通过对类的字节码文件的操作,生成字节码对象和实例的对象

2.获取一个类的Class有三种方式

  • 方式一: 对应的类的实例对象打点.getClass();
  • 方式二:大写的类名或者接口直接打点 String.class
  • 方式三:Class.forName(“java.util.List”) 将全类名写在小括号里

创建实例:Class.forName(“java.util.List”).newInstance()
如果构造方法有参数直接写在.newInstance(“123”)小括号中

3.java反射的作用

  • *增加灵活性* 很大的程度上实现动态编译的效果
  • 之所以能够实现动态编译 是因为能够根据类名动态的创建实例
  • 代码中许多地方需要动态的创建实例,可以放在配置文件中,每次修改配置文件即可
  • 反射拥有逆向的一个好处,很大程度提高了代码的可拓展性,比如一个软件先开发的,但是可以动态的添加插件,很多时候就使用了反射的机制
  • 我们经常说 jdbc 使用了反射机制,这样做的目的主要就是解耦,字符串是驱动的全类名,修改驱动的版本和不同数据库驱动简单了很多
  • 反射机制的效率不是很高,所以一般写在关键的地方

4.反射可以获取的类的一下信息:

Constructor:代表类的单个构造方法,通过Constructor我们可执行一个类的某个构造方法(有参或者无参)来创建对象时。

Method:代表类中的单个方法,可以用于执行类的某个普通方法,有参或无参,并可以接收返回值。

Field:代表类中的单个属性,用于set或get属性

AccessibleObject:以上三个类的父类,提供了构造方法,普通方法,和属性的访问控制的能力。

5.反射获取一个方法的所有构造函数

Constructor<?>[] constructors = String.class.getConstructors();
    for (Constructor con : constructors) {
        System.out.println(con);
    }
  • 也可以获取私有的(非公开的)构造函数 使用方法in.getDeclaredConstructor();

6.获取一个类的私有属性

  • 获取公开的属性使用FanSheBean02.class.getFields()
  • 获取所有的属性,包括私有的属性 FanSheBean02.class.getDeclaredFields()
  • fields[i].get(fan)获取具体的类的属性值

示例代码:

public class FanSheTest02 {
    @Test
    public void fanshetest02(){
        FanSheBean02 fan = new FanSheBean02("peter",18);
        Field[] fields = FanSheBean02.class.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            //允许暴力** 设置或取消访问检查
            fields[i].setAccessible(true);
            try {
                System.out.println(fields[i].get(fan));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
}

class FanSheBean02 {
    private String name;
    private int age;

    public FanSheBean02(){}
    public FanSheBean02(String name, int age) {
        this.name = name;
        this.age = age;
    }

}

7. 获取私有方法是同样的

示例代码:

 public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    Class<String>  ccl = String.class;
    Constructor<String> con = ccl.getConstructor(String.class);
    String str = con.newInstance("adfagfesg");
    char c = str.charAt(0);
    Method m = ccl.getMethod("charAt", int.class);
    //执行这个方法  第二个参数执行方法的参数
    char cc = (char) m.invoke(str, 0);

    //获取私有方法
    Method mm = ccl.getDeclaredMethod("lastIndexOfSupplent", int.class);
    //暴力**
    m.setAccessible(true);
    int i = (int) m.invoke(str, 0);
    System.out.println(i);
    //获取方法的返回值类型
    Class rc = mm.getReturnType();
    System.out.println(rc);
    //获取方法的参数列表
    Class[] cslb = mm.getParameterTypes();
    for (int j = 0; j < cslb.length; j++) {
        System.out.println(cslb[j]);
    }
    //获取方法抛出了哪些异常
    Class[] ycsz = mm.getExceptionTypes();
    for (int j = 0; j < ycsz.length; j++) {
        System.out.println(ycsz[j]);
    }
}

8.反射的方法大全

示例代码:

public static void main(String[] args) {
    Class<String> clz = String.class;
    //获取实现的所有接口
    Class[] is = clz.getInterfaces();
    for (Class class1 : is) {
        System.out.println(class1);
    }
    //获取全类名
    System.out.println(clz.getName());
    //获取所在包
    System.out.println(clz.getPackage());
    //只获取类名
    System.out.println(clz.getSimpleName());
    //获取父类
    System.out.println(clz.getSuperclass());
    //判断是否是一个注解类型
    System.out.println(clz.isAnnotation());
    //判断是不是一个匿名内部类
    Class ccc = new A(){}.getClass();
    System.out.println(ccc.isAnonymousClass());
    //判断是不是一个枚举
    System.out.println(clz.isEnum());
    //判断参数对象是不是字节码对象的实例
    System.out.println(clz.isInstance(ccc));
    //判断是不是一个接口
    System.out.println(clz.isInterface());
    //判断是不是一个方法内部类
    System.out.println(clz.isLocalClass());
    //判断是不是一个成员内部类
    System.out.println(clz.isMemberClass());
    //判断是不是一个基本数据类型
    System.out.println(clz.isPrimitive());
}

9.java反射应用的实例(摘抄)

我们为什么要使用反射,它的作用是什么,它在实际的编程中有什么应用。

  首先我们先明确两个概念,静态编译和动态编译。

  静态编译:在编译时确定类型,绑定对象,即通过。
  动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多
  态的应用,有以降低类之间的藕合性。

  我们可以明确的看出动态编译的好处,而反射就是运用了动态编译创建对象。

  那么我们再来看看实际中反射又有什么好处那?

  往往对比能更加直观的向我们展示两者的不同。
  
  若是不用反射,它是这样的

interface fruit{
public abstract void eat();
}

class Apple implements fruit{
public void eat(){
System.out.println(“Apple”);
}
}

class Orange implements fruit{
public void eat(){
System.out.println(“Orange”);
}
}

// 构造工厂类
// 也就是说以后如果我们在添加其他的实例的时候只需要修改工厂类就行了
class Factory{
public static fruit getInstance(String fruitName){
fruit f=null;
if(“Apple”.equals(fruitName)){
f=new Apple();
}
if(“Orange”.equals(fruitName)){
f=new Orange();
}
return f;
}
}
class hello{
public static void main(String[] a){
fruit f=Factory.getInstance(“Orange”);
f.eat();
}

}
  可以发现,每当我们要添加一种新的水果的时候,我们将不得不改变Factory中的源码,而往往改变原有正确代码是一种十分危险的行为。而且随着水果种类的增加,你会发现你的factory类会越来越臃肿,

不得不说这是一种十分–的做法。(初学者可能会问,我们为什么不直接在main方法中new水果那,我们可能会需要getInstance方法做一些别的事情。。。所以不直接new);

 而反射无疑是一种聪明的办法,看代码。

复制代码
interface fruit{
public abstract void eat();
}

class Apple implements fruit{
public void eat(){
System.out.println(“Apple”);
}
}

class Orange implements fruit{
public void eat(){
System.out.println(“Orange”);
}
}

class Factory{
public static fruit getInstance(String ClassName){
fruit f=null;
try{
f=(fruit)Class.forName(ClassName).newInstance();
}catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class hello{
public static void main(String[] a){
fruit f=Factory.getInstance(“Reflect.Apple”);
if(f!=null){
f.eat();
}
}
}
  在出现新品种水果的时候,你完全不用去修改原有代码。

  从上面的案例中,我们可以清楚的体会到反射的优越性。

  那么有的人又会问,这个例子能完全明白,但是如果放到实际的编程,应用中,我们又会在什么情况下用到反射那?

  举一个看到过的例子,在实际开发中,我们需要把一个包中的class new出来,但是这个包中的类总是需要变动,那么怎么办,难道总是修改main方法中xxx=new xxx()吗。这样无疑是麻烦的。而运用反射。我们可以相应的增加一个配置文件,在里面记录包中所有的类名,包中类增加时就加一个类名,删除时就删除一个类名。让main方法去读取这个配置文件中的类名,通过反射获得实例,完全不用我们去修改main方法中的代码。

  反射还有什么用那?他甚至可以修改其他类中的私有属性。android开发中,我们需要改变一个私有标志位的时候,android源码并没有提供set方法,我们又不能改变源码,怎么办,反射可以完美解决这个问题。

  说了这么多,那么我们的开发中,为什么不全部都用反射那?一个原因,开销,它的开销是什么昂贵的,随意尽量在最需要的地方使用反射。

相关标签: java