java 反射机制
以下只是个人在学习反射过程中的笔记,如有错误请指出纠正。
1. 通过例子理解反射
- 获取类的类类型的三种方法
package Reflect;
public class ClassReflect {
public static void main(String[] args) {
ClassReflect cr = new ClassReflect();
//方法一:
Class c = cr.getClass();
//方法二:
Class c1 =ClassReflect.class;//c1和c表示ClassReflect类的类类型
//方法三:
try {
Class.forName("Reflect.ClassReflect");//常用
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
- 通过类名获取类的实例及类的方法,类的构造方法
package Reflect;
public class Person {
public Person(String name, int age) {
this.age=age;
this.name=name;
}
//无参构造函数一定得加上,否则报错空指针
public Person(){
}
public Person(String name){
this.name=name;
}
public Person(int age){
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 "["+this.name+" "+this.age+"]";
}
private String name;
private int age;
}
注意一下,当我们把Person中的默认的无参构造函数取消的时候,比如自己定义只定义一个有参数的构造函数之后,会出现错误
package Reflect;
import java.io.ObjectInputStream.GetField;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.StringTokenizer;
public class exampleOne {
public static void main(String[] args) throws Exception {
Class c = Class.forName("Reflect.Person");//获得person类
Person per = (Person) c.newInstance();//person实例化
Class exampleclass= Class.forName("Reflect.exampleOne");
exampleOne example = (exampleOne) exampleclass.newInstance();
try {
Method m = exampleclass.getDeclaredMethod("print", int.class,int.class);//根据方法名及对象参数获取唯一的一个方法
//Method m1 = c.getMethod("print", new Class[]{int.class,int.class});
//c.getDeclaredMethod(name, parameterTypes); getMethod()是获取public方法,getDeclareMethod()是获取自己声明的方法
int num =m.getModifiers();
System.out.println(num);//当权限修饰符是public时,i是1,private 时,是2,protected时是4
String priv = Modifier.toString(num);
System.out.println("权限修饰符:"+priv);
System.out.println("方法名:"+m.getName());
m.invoke(example, 10,20);//方法的反射操作是,用m对象来进行方法调用
System.out.println(" 获取构造方法及对应参数 ");
Constructor[] constructor=c.getConstructors();
for(int i=0;i<constructor.length;i++){
System.out.print(Modifier.toString(constructor[i].getModifiers())+" ");;
System.out.print (constructor[i].getName() +"(");
Class[] param = constructor[i].getParameterTypes();
for(int j=0;j<param.length;j++){
System.out.print(param[j].getName()+" arg"+j);
if(j<param.length-1){
System.out.print(", ");
}
}
System.out.println(")");
}
Method[] method = c.getMethods();
for(int i=0;i<method.length;i++){
System.out.print(Modifier.toString(method[i].getModifiers())+" ");
System.out.print (method[i].getReturnType()+" ");
System.out.print (method[i].getName()+"(");
Class<?>[] method_param = method[i].getParameterTypes();
for(int j =0;j<method_param.length;j++){
System.out.print (method_param[j].getName()+" arg"+j);
if(j<method_param.length-1){
System.out.print (",");
}
}System.out.print (")");
Class<?>[] exceptionType =method[i].getExceptionTypes();
for(int k=0;k<exceptionType.length;k++){
System.out.println("throws "+exceptionType[k].getName());
}
}
} catch ( Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
private void print(int a,int b){
System.out.println("计算结果:"+(a+b));
}
结果:
2
权限修饰符:private
方法名:print
计算结果:30
获取构造方法及对应参数
public Reflect.Person(java.lang.String arg0, int arg1)
public Reflect.Person(int arg0)
public Reflect.Person(java.lang.String arg0)
public Reflect.Person()
public int getAge()public void setAge(int arg0)public class java.lang.String toString()public class java.lang.String getName()public void setName(java.lang.String arg0)public final native class java.lang.Class getClass()public native int hashCode()public boolean equals(java.lang.Object arg0)public final native void notify()public final native void notifyAll()public final void wait()throws java.lang.InterruptedException
public final void wait(long arg0,int arg1)throws java.lang.InterruptedException
public final native void wait(long arg0)throws java.lang.InterruptedException
- 调用其他类的set和get方法
package Reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class UseMethod {
public static void main(String[] args) {
Class<?> demo =null;
Object obj =null;
try {
demo=Class.forName("Reflect.Person");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
obj = demo.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
setter(obj, "Age",20, int.class);
getter(obj, "Age");
}
public static void getter(Object obj,String attr){
try {
Method method = obj.getClass().getMethod("get"+attr);
System.out.println(method.invoke(obj));
} catch ( Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void setter(Object obj, String attr, Object value,
Class<?> type) {
try {
Method method = obj.getClass().getMethod("set"+attr,type);
method.invoke(obj, value);
} catch ( Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
输出结果:20
- 通过反射操作属性,修改数组
package Reflect;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
public class test01 {
public static void main(String[] args) throws Exception {
Class<?> demo = null;
Object obj = null;
demo = Class.forName("Reflect.Person");
obj = demo.newInstance();
Field field = demo.getDeclaredField("name");
field.setAccessible(true);
field.set(obj, "hlx");
System.out.println(field.get(obj));
test();
}
public static void test(){
int[] temp={1,2,3,4,5};
Class<?>demo=temp.getClass().getComponentType();
System.out.println("数组类型: "+demo.getName());
System.out.println("数组长度 "+Array.getLength(temp));
System.out.println("数组的第一个元素: "+Array.get(temp, 0));
Array.set(temp, 0, 100);
System.out.println("修改之后数组第一个元素为: "+Array.get(temp, 0));
}
}
输出结果:
hlx
数组类型: int
数组长度 5
数组的第一个元素: 1
修改之后数组第一个元素为: 100
- 通过反射修改数组
package Reflect;
import java.lang.reflect.Array;
public class testArray {
public static void main(String[] args) {
int[] arr1 ={1,2,3,4};
int[] arr2=null;
Class<?> c = arr1.getClass().getComponentType();
arr2 =(int[]) Array.newInstance(c, 15);
int len =Array.getLength(arr1);
System.out.println(len);
System.arraycopy(arr1, 0, arr2, 0, len);
Class<?> c1 = arr2.getClass();
if(!c1.isArray()){
return;
}
System.out.println("新数组的长度:"+Array.getLength(arr2));
for(int i=0;i<Array.getLength(arr2);i++){
System.out.print(Array.get(arr2, i));
}
}
}
输出结果:
4
新数组的长度:15
123400000000000
- 查看类加载器
//查看类加载器
test01 t = new test01();
System.out.println("类加载器:"+t.getClass().getClassLoader().getClass().getName());
输出结果:类加载器:sun.misc.Launcher$AppClassLoader
在java中有三种类类加载器。
1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。
2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类
3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。
如果想要完成动态代理,首先需要定义一个InvocationHandler接口的子类,已完成代理的具体操作。
package Reflect;
import java.lang.reflect.*;
//定义项目接口
interface Subject {
public String say(String name, int age);
}
// 定义真实项目
class RealSubject implements Subject {
@Override
public String say(String name, int age) {
return name + " " + age;
}
}
class MyInvocationHandler implements InvocationHandler {
private Object obj = null;
public Object bind(Object obj) {
this.obj = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object temp = method.invoke(this.obj, args);
return temp;
}
}
class hello {
public static void main(String[] args) {
MyInvocationHandler demo = new MyInvocationHandler();
Subject sub = (Subject) demo.bind(new RealSubject());
String info = sub.say("Rollen", 20);
System.out.println(info);
}
}
输出结果:Rollen 20
- 反射用于工厂设计模式
package Reflect;
public class Apple implements fruit{
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("apple");
}
}
package Reflect;
public class Orange implements fruit {
public void eat() {
// TODO Auto-generated method stub
System.out.println("orange");
}
}
package Reflect;
public interface fruit {
public void eat();
}
package Reflect;
public class Factory {
public static fruit getInstance(String fruitName) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
fruit f =null;
f= (fruit) Class.forName(fruitName).newInstance();
return f;
}
}
package Reflect;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class init {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
/*fruit f = Factory.getInstance("Reflect.Apple");
f.eat();*///未用properties配置文件时
try {
Properties p = getData();
fruit f =Factory.getInstance(p.getProperty("apple"));
if(f!=null){
f.eat();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
*
* @return
* @throws FileNotFoundException
* @throws IOException
*/
public static Properties getData() throws FileNotFoundException, IOException{
Properties p = new Properties();
File f = new File("fruit.properties");
if(f.exists()){
p.load(new FileInputStream(f));
}else{
p.setProperty("apple","Reflect.Apple");
p.setProperty("orange", "Reflect.Orange");
p.store(new FileOutputStream(f), "FRUIT CLASS");
}
return p;
}
}
- 反射与new的区别
1、反射是动态编译,new是静态编译,静态编译就是在编译的时候把你所有的模块都编译进exe里去。动态编译的时候那些模块都没有编译进去,这样启动程序(初始化)的时候这些模块不会被加载,而是在运行的时候,用到那个模块就调用哪个模块
2、new对象,无法调用该类里面私有的东西,反射反之,