反射是框架设计的灵魂
(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))
一、反射的概述
class是一切反射的根源,JAVA反射机制是在运行状态中,对于任和一个类,通过反射都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
本人简单理解就是用一段字符串直接调取类及其该类的方法。
反射的作用
通过反射访问java对象的属性,方法,构造方法等
反射机制的相关类
与Java反射相关的类如下:
类名 | 用途 |
---|---|
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(成员变量也称为类的属性) |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
注意:都是Object类的子类
反射的基本机制
: 可以根据一个“类全名字符串” ,获得代表这个类的class对象,然后根据这个class对象构造出这个类的真正实例对象
可用Class.forName(“类的包名”)这个方法得到一个Class类
String className = "cn.edu360.javase24.reflect.demo.SerivceOne"; // 通常这个字符串常常存在文件当中,用io流调用
Class<?> forName = Class.forName(className); // 根据类名字符串“SerivceOne”获取class对象
SerivceOne o = (SerivceOne)forName.newInstance(); // 用class对象构造出这个类SerivceOne的实例对象
o.say();
然后该反射常常应用于接口
比如这里我们有一个接口Fuck还有其 实现类FuckImpl,然后约定好将该实现类的完整包名保存入文件当中。
然后我们调用该接口的时候就可以这样
public class Menu {
public static void main(String[] args) throws Exception {
// 从约定的文件中读取所需类的实现类全名
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("f:/a.txt")));
String ClassName = br.readLine(); /将文件中的按行包名输出
Class<?> forName = Class.forName(ClassName); // forName代表的是serviceClassName字符串所指定的类的类class模板
// 根据类全名构造这个service实现类的实例
Fuck fuck = (Fuck) forName.newInstance();`}}
三、通过反射获取类的构造方法、方法以及属性
Class<?> forName = Class.forName(ClassName);
// 根据类全名构造这个service实现类的实例
Fuck fuck = (Fuck) forName.newInstance();`
//methodName存的是方法名的字符串,从forName这个class模板中获取到指定的方法
Method method=forName.getMethod(methodName) ;
//让Method在对象上执行,()中写对象和参数
Object invoke=method.invoke(fuck,12);
-------------------------------------------------------------------------
//如果存在同名方法,则有参数的需要这样输入
Method method2=forName.getMethod(methodName,String.Class) ;
Object invoke=method.invoke(fuck,12);
配置文件用到的小工具Properties()
Properties中的主要方法
(1)load(InputStream inStream)
这个方法可以从.properties属性文件对应的文件输入流中,加载属性列表到Properties类对象。如下面的代码:
Properties pro = new Properties();
FileInputStream in = new FileInputStream("a.properties");
pro.load(in);
in.close();
(2)store(OutputStream out, String comments)
这个方法将Properties类对象的属性列表保存到输出流中。如下面的代码:
FileOutputStream oFile = new FileOutputStream(file, "a.properties");
pro.store(oFile, "Comment");
oFile.close();
如果comments不为空,保存后的属性文件第一行会是#comments,表示注释信息;如果为空则没有注释信息。
注释信息后面是属性文件的当前保存时间信息。
(3)getProperty/setProperty
这两个方法是分别是获取和设置属性信息。
反射与属性配置文件的加载
Properties props = new Properties();
//加载xx.properties属性配置文件
props.load(Test.class.getClassLoader().getResourceAsStream("xx.properties"));
//取配置参数
String value = props.getProperty("key");
Class<?> forName = Class.forName(value); // forName代表的是serviceClassName字符串所指定的类的类class模板
// 根据类全名构造这个service实现类的实例
Fuck fuck = (Fuck) forName.newInstance();`
然后应该在同个包中直接建立***file***
内容是
key=value的形式
ClassName=fuckMan
Method=fuck
匿名内部类
匿名内部类也就是没有名字的内部类
正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写
但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口
实例1:不使用匿名内部类来实现抽象方法
abstract class Person {
public abstract void eat();
}
class Child extends Person {
public void eat() {
System.out.println("eat something");
}
}
public class Demo {
public static void main(String[] args) {
Person p = new Child();
p.eat();
}
}
运行结果:eat something
可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用
但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类岂不是很麻烦?
这个时候就引入了匿名内部类
实例1:不使用匿名内部类来实现抽象方法
abstract class Person {
public abstract void eat();
}
class Child extends Person {
public void eat() {
System.out.println("eat something");
}
}
public class Demo {
public static void main(String[] args) {
Person p = new Child();
p.eat();
}
}
运行结果:eat something
可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用
但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类岂不是很麻烦?
这个时候就引入了匿名内部类
实例2:匿名内部类的基本实现
abstract class Person {
public abstract void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
运行结果:eat something
可以看到,我们直接将抽象类Person中的方法在大括号中实现了
这样便可以省略一个类的书写
并且,匿名内部类还能用于接口上
实例3:在接口上使用匿名内部类
interface Person {
public void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
运行结果:eat something