反射机制基础

获取类对象

三种方式

  1. Class.forName
  2. Hero.class
  3. new Hero().getClass()

获取类对象的时候,会导致类属性被初始化(类加载),但是Hero.Class这种方式不会初始化!

package reflect;
/*
 * 获取对象的三种方式
 * Class.forname(类对象)
 * 类.class
 * 类对象.getclass()
 */
public class TestreflectA {
	public static void main(String[] args) {
		Hero hero=new Hero();
		Class c1=Hero.class;
		Class c2=hero.getClass();
		try {
			Class c3=Class.forName("reflect.Hero");
			System.out.println(c3==c1);			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
			
	}
}
class Hero{
	String name;
	public Hero() {
		
	}
	public Hero(String name) {
		this.name=name;
	}
}

创建对象

创建方式为:
先获取类c,然后c.newInstance()方法创建一个实例!
.newInstance()调用的是一个无参数的构造器,如果类只有一个有参构造器,将会报错。要么没有构造器,要么就必须的iyou无参构造器!

package reflect;
/*
 * 获取对象的三种方式
 * Class.forname(类对象)
 * 类.class
 * 类对象.getclass()
 */
public class TestreflectA {
	public static void main(String[] args) {
		Hero hero=new Hero("name");
		Class c1=Hero.class;
		Class c2=hero.getClass();
		try {
			Class c3=Class.forName("reflect.Hero");		
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
		try {
			Object o1=c2.newInstance();
		} catch (InstantiationException | IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}
}

class Hero{
	String name;
	public Hero() {
		System.out.println("创建了一个实例");
	}
	public Hero(String name) {
		this.name=name;
	}
}

访问属性

通过反射机制修改对象的属性
语法:
Field f=类实例.getDeclaredField(属性)
f.set(类对象,修改的值)

package reflect;

import java.lang.reflect.Field;

/*
 * 获取对象的三种方式
 * Class.forname(类对象)
 * 类.class
 * 类对象.getclass()
 */
public class TestreflectA {
	public static void main(String[] args) {
		Hero hero=new Hero("gareen");
		System.out.println(hero);	
		
		Class c1=hero.getClass();
		
		try {
			Field f1 = c1.getDeclaredField("name");
			f1.set(hero, "teemo");
		} catch (Exception e) {

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

class Hero{
	public String name;
	public float hp;
	public int damage;
	public int id;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Hero() {

	}

	public Hero(String string) {
		name = string;
	}

	@Override
	public String toString() {
		return "Hero [name=" + name + "]";
	}

	public boolean isDead() {
		// TODO Auto-generated method stub
		return false;
	}

	public void attackHero(Hero h2) {
		System.out.println(this.name + " 正在攻击 " + h2.getName());
	}
}

getField和getDeclaredField的区别

getField和getDeclaredField这两个方法都是用于获取字段;
getField只能获取public的,包括从父类继承的。
getDeclaredField可以获取本类所有的字段,包括private,但是不能获取继承来的字段( 这里只能获取到private的字段,但并不能访问该private字段的值,除非加上setAccessible(true))

//name是private的
public class TestreflectA {
	public static void main(String[] args) {
		Hero hero=new Hero("gareen");
		System.out.println(hero);
		
		Class c1=hero.getClass();		
		try {
			Field f1 = c1.getDeclaredField("name");
	//		f1.setAccessible(true);没有这一行就会导致出现异常,set函数不执行因为异常处理机制
			f1.set(hero, "teemo");//无法访问和获取
		} catch (Exception e) {
		}
		System.out.println(hero);			
	}
}

调用方法

Hero里面有一个setName(String s)函数!
Method m=类实例.getClass().getMethod("实例方法名字",参数类型)
m.invoke(类实例,参数)

public class TestreflectA {
	public static void main(String[] args) {
		Hero hero=new Hero();
		System.out.println(hero);		
		Class c1=hero.getClass();		
		try {			
			Method m1 = c1.getMethod("setName",String.class);
			m1.invoke(hero, "gareen");			
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println(hero);			
	}
}

用途

举一个使用反射方式的例子!
通过springtest.txt文本档实现调用函数的功能!

//springtest.txt文本的内容
class=reflect.Service1
method=doservice1

首先写两个类:

public class Service1 {
	public void doservice1() {
		System.out.println("1");
	}
}
public class Service2 {
	public void doservice2() {
		System.out.println("2");
	}
}
package reflect;

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;
public class TestreflectB {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		File file=new File("F:/Wangchuang/springreflect.txt");
		
		Properties p=new Properties();//key-value Hashmap!
		
		try {		
			p.load(new FileInputStream(file));//加载字节流
			String classname=(String) p.get("class");//获取类名
			String methodname=(String) p.get("method");//获取类方法			
			Class c=Class.forName(classname);
			Method m=c.getMethod(methodname);
			Constructor con=c.getConstructor(String.class);//获取构造对象
			Object o1=con.newInstance("d");//根据构造器获取实例对象
		//	Object obj=c.newInstance();	//参考newInstance的使用方法		
			m.invoke(o1);
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
	}
}

如果想执行另一个类的方法,直接在文本里面修改就行了!
1.先把文件以字节流的形式加载到Properties实例对象中去
2.通过Properties实例对象的方法分别得到类名和方法名字段
3.通过类名构造类对象,由类对象构造实例方法,并将实例方法放到Method中运行
Properties解析

获取文件的绝对路径(可移植),通用!!!!!

文件是放在src文件下面的!
String path2=Thread.currentThread().getContextClassLoader().getResource("com/biji/javja/dab.properties").getPath();
getContextClassLoader()是线程对象的方法,可以获取到当前线程的类加载器对象
getResource【获取资源】这是类加载器对象的方法,当前线程的类加载器默认从类的根路径下加载资源。
改进版
直接以流的方式返回
InputStream reader =Thread.currentThread().getContextClassLoader().getResourceAsStream("src下面的文件相对路径")

资源绑定器
java.util包下面有一个资源绑定器,便于获取属性配制文件中的内容,前提条件配置文件xxx.properties必须放到类路径下,文件的属性必须为properties!
ResourceBundle bundle=ResourceBundle.get("classinfo2");
String classname=bundle.getString("className");

类加载器

1、准备负责加载类的命令/工具ClassLoader(类加载器)

2、执行代码比如:String s=“1”;
代码开始前会将所需要类全部加载到JVM当中,通过类加载器加载,看到以上代码类加载器找到String.class文件,找到就加载!
执行步骤
①首先通过“启动类加载器”加载(父)
启动类加载器专门加载:rt.jar,其全部都是JDK的核心类库
②如果启动类加载器加载不到的时候会通过“扩展类加载器”加载(母)
扩展类加载器专门加载ext文件下的类
③如果所有扩展类加载器没有加载到,那么会通过“应用类加载器”加载
应用类加载器专门加载:classpath中类(系统设置的环境变量)

3、 双亲委派机制:保证类加载的安全
优先从启动类加载器中加载,这个称为父,如果父无法加载到,再从扩展类加载器中加载,这个称为母。如果都加载不到才会考虑从应用类加载器中记载。知道加载到为止!

可变长参数

形如:m(类型名…args)
其中args相当于一个数组 ,具有数组属性,参数可以是数组形式,取出的时候能够是一个数组。
可变长参数只能有一个,并且只能放在参数列表的最后一个位置!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值