java中的反射总结

刚开始学习java的时候真的很难理解反射究竟是个什么东西java

一些书籍,哪怕是很经典的书籍都解释的让人感受懵懵的,或许的确是我太笨程序员

何况,网上说在未来学习框架的时候须要常常应用到反射机制,这样一来总让人内心有些不安数组

就方才偶然又把讲解反射的章节和视频看了一点,以为能理解一些了安全

如今决定一气呵成,边看边写,顺便把一些主要的内容和操做都记载到这里框架

我想,对于我这么一个笨笨的人来讲,学习的最好方法也许就是不断重复学习

遇到不懂的知识就停下来把以往的从新学一遍,虽然浪费了不少时间,但对我也有些效果this

 

个人理解是:所谓反射,就是根据一个已经实例化了的对象来还原类的完整信息编码

至少对我而言,我认为它带给个人好处是,让我从下往上的又了解了一遍面向对象spa

x_x 在此又痛恨一边那些厚部头们,把个人脑细胞搞死一片设计

 

Class类

若是要完成反射,那么必须了解Class类

实例1:经过对象取得包名和类名

1
2
3
4
5
6
7
8
9
10
11
12
13
package  org.siu;
 
class  Test {
     
}
 
public  class  Demo {
     public  static  void  main(String[] args) {
         Test t = new  Test();
         System.out.println(t.getClass());
         System.out.println(t.getClass().getName());
     }
}

编译结果以下,注意包的编译方式便可

此处的getClass()方法是默认继承自Object类的

 

在java中,Object类是全部类的父类,一样,全部类的实例化对象也都是Class类的实例

所以,这样一来就会牵扯到向上转型和向下转型的概念

因为向下转型的不安全因素,在这里泛型也会接踵而来

(不过我想说的是,此处的泛型设计很刺眼!尼玛,整个java的语法设计一样刺眼,超恶心!!!)

 

实例2:Class类的实例化

因为Class类没有构造方法,因此实例化Class类的方式有点特殊,有三种方式:

  • 对象.getClass( )
  • 类.Class
  • forName( )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class  Test {
     
}
 
public  class  Demo {
     public  static  void  main(String[] args) {
         //方式一:
         Test t = new  Test();
         Class<? extends  Test> c1 = t.getClass();
         System.out.println(c1);
         
         //方式二:
         //为了不特殊性,这里不用Test类,而用java库中的String类
         Class<String> c2 = String. class ;
         System.out.println(c2);
         
         //方式三:
         //forName()方法会抛出异常
         Class<?> c3 = null ;
         try  {
             c3 = Class.forName( "Test" );
         } catch  (ClassNotFoundException e) {
             e.printStackTrace();
         }
         System.out.println(c3);
     }
}

 其中,forName( )方法须要重点掌握,由于它能够在类不肯定的状况下实例化Class,更具灵活性

 

Class类的应用

Class类中有一个方法叫作newInstance( ),它能够用来建立一个Class类对象的新实例

怎么说呢?Class对象包含的内容就是反射好的那个类,咱们要构造那个类的新实例(新对象)

实例3:Class类的无参构造对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public  class  Demo {
     public  static  void  main(String[] args) {
         //实例化Class对象,forName()方法会抛异常
         Class<?> c = null ;
         try  {
             //这里须要完整的包名和类名
             c = Class.forName( "java.lang.String" );
         } catch  (ClassNotFoundException e) {
             e.printStackTrace();
         }
         
         //生成一个字符串的引用
         String s = null ;
         try  {
             //将构造好的对象向下转型为String类
             //newInstance()方法会抛异常
             s = (String) c.newInstance();
         } catch  (InstantiationException e) {
             e.printStackTrace();
         } catch  (IllegalAccessException e) {
             e.printStackTrace();
         }
         System.out.println( "字符串长度: "  + s.length());
     }
}

这样就经过无参数的形式构造了一个新的对象,如同正常模式中

经过无参构造方法来构造新对象同样

咱们知道,类中除了有无参构造方法,还会存在有参数的构造方法

那在反射中如何经过有参数的形式构造对象呢?接着看

 

实例4:Class类的有参构造对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import  java.lang.reflect.Constructor;
 
public  class  Demo {
     //下面的几个方法抛出来的异常太多,为了代码的紧凑性,这里就直接抛给虚拟机了
     public  static  void  main(String[] args) throws  Exception {
         Class<?> c = null ;
         try  {
             c = Class.forName( "java.lang.String" );
         } catch  (ClassNotFoundException e) {
             e.printStackTrace();
         }
         char [] ch = { 'h' , 'e' , 'l' , 'l' , 'o' };
         String s = null ;
         //得到Class类对象的有参构造方法,括号里面参数的写法是:类型.class
         Constructor<?> con = c.getConstructor( char []. class );
         //用此构造方法构造一个新的字符串对象,参数为一个char数组
         s = (String) con.newInstance(ch);
         System.out.println( "构造的字符串:"  + s);
     }
}

咱们仍是使用String类作例,由于String类用的比较多,便于理解

这里须要注意的是,构造方法须要使用getConstructor( )方法得到

至于参数类型则是:原有类型.class

还有一点,不管是有参仍是无参,这里所使用的构造方法,本来的类里面必须对应存在

那么,如何才能知道原有类里面的构造方法,普通方法,继承的父类等详细信息呢?接着看

 

获取类的结构

要经过反射获取类的结构咱们这里要导入一个新的包java.lang.reflect

实例5:取得类的构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import  java.lang.reflect.Constructor;
import  java.util.Arrays;
 
public  class  Demo {
     //下面的几个方法抛出来的异常太多,为了代码的紧凑性,这里就直接抛给虚拟机了
     public  static  void  main(String[] args) throws  Exception {
         Class<?> c = null ;
         try  {
             c = Class.forName( "java.lang.Boolean" );
         } catch  (ClassNotFoundException e) {
             e.printStackTrace();
         }
         //这里的getConstructors()方法返回的是一个Constructor数组
         Constructor<?>[] cons = c.getConstructors();
         //打印的方式你能够本身写,为了方便我用Arrays.toString(),凑合着看
         System.out.println(Arrays.toString(cons));
     }
}

 我选择了Boolean类来作例,由于Boolean类的构造方法就两个,方便看

 

实例6:取得类所实现的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import  java.util.Arrays;
 
public  class  Demo {
     public  static  void  main(String[] args) throws  Exception {
         Class<?> c = null ;
         try  {
             c = Class.forName( "java.lang.Boolean" );
         } catch  (ClassNotFoundException e) {
             e.printStackTrace();
         }
         Class<?>[] in = c.getInterfaces();
         System.out.println(Arrays.toString(in));
     }
}

 没什么好说的,看结果

 

实例7:取得父类

1
2
3
4
5
6
7
8
9
10
11
12
13
public  class  Demo {
     public  static  void  main(String[] args) throws  Exception {
         Class<?> c = null ;
         try  {
             c = Class.forName( "java.lang.Boolean" );
         } catch  (ClassNotFoundException e) {
             e.printStackTrace();
         }
         //注意了,这里不会是数组,why?
         Class<?> su = c.getSuperclass();
         System.out.println(su);
     }
}

 别忘了,java中是单继承,父类只有一个

 

实例8:取得类的所有方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import  java.lang.reflect.Method;
 
public  class  Demo {
     public  static  void  main(String[] args) throws  Exception {
         Class<?> c = null ;
         try  {
             c = Class.forName( "java.lang.Boolean" );
         } catch  (ClassNotFoundException e) {
             e.printStackTrace();
         }
         Method[] m = c.getMethods();
         //好吧,此次我就大发慈悲的写个打印列表出来
         for  ( int  i = 0 ; i < m.length; i++) {
             System.out.println(m[i]);
         }
     }
}

 截取一部分,看看,意思下就好了……这几个例子都比较简单

 

实例9:取得本类的所有属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import  java.lang.reflect.Field;
 
class  Person {
     private  String name;
     private  int  age;
}
 
public  class  Demo {
     public  static  void  main(String[] args) throws  Exception {
         Class<?> c = null ;
         try  {
             c = Class.forName( "Person" );
         } catch  (ClassNotFoundException e) {
             e.printStackTrace();
         }
         Field[] f = c.getDeclaredFields();
         for  ( int  i = 0 ; i < f.length; i++) {
             System.out.println(f[i]);
         }
     }
}

getDeclaredFielsd()方法能够获取所有属性,getFields()只能获取公共属性

 

实例10:获取本类中属性的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import  java.lang.reflect.Field;
 
class  Person {
     public  String name;
     private  int  age;
     
     public  Person(String name, int  age) {
         this .name = name;
         this .age = age;
     }
}
 
public  class  Demo {
     public  static  void  main(String[] args) throws  Exception {
         Person p = new  Person( "zhangsan" , 12 );
 
         Class<?> c = p.getClass();
         
         //获取公共属性的值
         Field f1 = c.getField( "name" );
         //get(p)代表要获取是哪一个对象的值
         String str = (String) f1.get(p);
         System.out.println( "姓名: "  + str);
         
         //获取私有属性的值
         Field f2 = c.getDeclaredField( "age" );
         //age是私有属性,因此要设置安全检查为true
         f2.setAccessible( true );
         int  age = ( int ) f2.get(p);
         System.out.println( "年龄: "  + age);
     }
}

 要注意的是:setAccessible()方法能够设置是否访问和修改私有属性

 

坦白说,java学到如今我还没发现什么能亮瞎我钛金眼的知识在里边

每次都是写一堆繁琐的语法实现个小玩意儿,否则就是拼命调用API,拼命的抛异常

让自己显得不够紧凑的代码变得愈发累赘

若是我喜欢一门语言,在我利用它作出东西来以前,它自己的特性必须可以打动我

显然,java并不让我快乐,也许不少程序员跟我同样是被迫使用java的

仅以此来安抚我那颗孤独编码的心,下面接着看内容

 

反射的应用

实例11:经过反射修改属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import  java.lang.reflect.Field;
 
class  Person {
     private  String name;
     
     public  Person(String name) {
         this .name = name;
     }
     
     public  String toString() {
         return  "姓名: "  + this .name;
     }
}
 
public  class  Demo {
     public  static  void  main(String[] args) throws  Exception {
         Person p = new  Person( "王二狗" );
         System.out.println(p);
         Class<?> c = p.getClass();
     
         //定义要修改的属性
         Field f = c.getDeclaredField( "name" );
         f.setAccessible( true );
         //修改属性,传入要设置的对象和值
         f.set(p, "张二蛋" );
         System.out.println(p);
     }
}

 几个方法都是有联系的,若是看不懂就先熟悉上面几个例子

 

实例12:经过反射调用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import  java.lang.reflect.Method;
 
class  Person {
     public  void  print( int  i) {
         System.out.println( "我在写数字: "  + i);
     }
     
     public  static  void  say(String str) {
         System.out.println( "我在说: "  + str);
     }
}
 
public  class  Demo {
     public  static  void  main(String[] args) throws  Exception {
         Person p = new  Person();
         Class<?> c = p.getClass();
     
         //getMethod()方法须要传入方法名,和参数类型
         Method m1 = c.getMethod( "print" , int . class );
         //invoke()表示调用的意思,须要传入对象和参数
         m1.invoke(p, 10 );
         
         Method m2 = c.getMethod( "say" , String. class );
         //这里的null表示不禁对象调用,也就是静态方法
         m2.invoke( null , "你妹" );
     }
}

这里演示了一个普通的有参方法和一个静态方法

既然有参数的都写出来了,那么无参的就更简单了,直接传入一个对象便可

 

实例13:经过反射操做数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import  java.lang.reflect.Array;
 
public  class  Demo {
     public  static  void  main(String[] args) throws  Exception {
         int [] arr = { 1 , 2 , 3 , 4 , 5 };
         Class<?> c = arr.getClass().getComponentType();
         
         System.out.println( "数组类型: "  + c.getName());
         int  len = Array.getLength(arr);
         System.out.println( "数组长度: "  + len);
         System.out.print( "遍历数组: " );
         for  ( int  i = 0 ; i < len; i++) {
             System.out.print(Array.get(arr, i) + " " );
         }
         System.out.println();
         //修改数组
         System.out.println( "修改前的第一个元素: "  + Array.get(arr, 0 ));
         Array.set(arr, 0 , 3 );
         System.out.println( "修改后的第一个元素: "  + Array.get(arr, 0 ));
     }
}

 这里要注意一点,getComponentType( )返回的是数组元素的Class

 

暂时就写这么多,我看的书中还有反射在工厂模式中的应用

无非是用forName()方法替换一下,没什么可说的

我是个java初级黑,我恨java那种恶心的语法和设计

这都是为了Android,为了打基础,为了适应之后的工做

Fuck java……

相关文章
相关标签/搜索