一、反射概述
1、反射机制中主要掌握的类型:
java.lang.Class;//类整体
java.lang.reflect.Constructor;//构造方法
java.lang.reflect.Field;//属性
java.lang.reflect.Medthod;//方法
java.lang.reflect.Modifier;//修饰符
以上类都可以创建对象
class User{
String name;
User(){}
public void m1(){}
}
反射机制的作用:
1、反编译:.class———》.java
2、通过反射机制访问java类的的属性,方法,构造方法等
二、获取class的三种方式
/*
获取class类型对象的三种方式
*/
public class ReflectTest01{
public static void main(String args[]) throws Exception{
//第一种方式
Class c1 = Class.forName("Employee");//c1引用保存内存地址指向堆中对象,该对象代表的是Employee整个类
//第二种方式
//java种每个类型都有class属性
Class c2 = Employee.class;
//第三种方式
//java语言中任何一个对象都有getClass方法
Employee e = new Employee();
Class c3 = e.getClass();//c3是运行时类,e的运行时类时Employee
//因为Employee这个类在JVM中只有一个,所以c1,c2,c3的内存地址时相同的,指向堆中的一个对象
System.out.println(c1==c2);//true
System.out.println(c3==c2);//true
Class c5 = Class.forName("java.util.Data");//必须写全名,类全,名带有包名
Date d = new Date();
Class c6 = d.getClass();
System.out.println(c4==c5);//true
System.out.println(c5==c6);//true
//c7代表int类型
Class c7 = int.class;
}
}
public class Employee{
//Filed
private String name;
//Constructor
Employee(){
}
Employee(String name){
this.name = name;
}
//Medthod
public void m1(){
System.out.println(name+" 在工作 ");
}
}
三、通过Class类对象创建java对象
public class ReflectTest02{
public static void main(String args[]){
//将A.class文件装载到JVM中的过程
Class.forName("A");
//不会执行静态语句块
Class c = A.class;
}
}
class A{
static{
System.out.println("A......");
}
}
/*
获取Class类型的对象之后,可以创建该类的对象
*/
import java.util.*;
import java.text.*;
public class ReflectTest03{
public static void main(String args[]) throw Exception{
Class c = Class.forName("Employee");
//创建此Class对象所表示类的一个新实例
Object o = c.newInstance();//调用Employee的无参数构造方法
System.out.println(o);
Class c1 = Class.forName("java.util.Date");
Object o1 = c1.newInstance();
if(o1 instanceof Date){
Data t = (Data)o1;
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:ss:mm SSS").format(t));
}
}
}
四、可变长参数
/*
关于java中的可变长参数
*/
import java.util.*;
public class Test01{
//m1方法中有一个int类型的可变长参数
public static void m1(int... a){
System.out.println("Test");//m1方法调用的时候,传递的参数可以是0-N个
}
//如果有精确匹配的方法,则调用该方法,不会再去执行可变长参数的那个方法
public static void m1(int a){
System.out.println(a);
}
//可变长参数可以等同看做数组
public static void m2(String... args){
for(int i = 0;i<args.length;i++){
System.out.println(args[i]);
}
}
public static void m3(Class... args) throw Exception{
for(int i = 0;i<args.length;i++){
Class c = args[i];
System.out.println(c.newInstance());
}
}
//可变长参数只能出现一次,并且只能出现在所有参数的最后一位
//public static void m4(String... args,int i){}
public static void m4(int i,String... args){}
public static void main(String[] args) throw Exception{
m1();
m1(1);
m1(1,2);
m1(1,2,3);
m2("aaa","aaa","aaa","aaa");
String[] s = {"aaa","aaa","aaa","aaa"};
m2(s);
m3(Date.class,Employee.class);
}
}
五、IO和Properties的联合应用
/*
IO + Properties
dbinfo这样的文件我们成为配置文件
配置文件的作用就是:使程序更加灵活
注意:一般在程序中可变的东西不要写死,推荐写到配置文件中
运行同样的的程序将得到不同的结果
像dbinfo这样一个具有特殊内容的配置文件我们又叫做属性文件。
java规范中要求属性文件以“.properties”结尾
属性文件中数据要求:
key和value之间可以使用空格、冒号、等号
如果空格、冒号、等号都有,按最前的作为分割符
*/
import java.io.*;
import java.util.*;
public class Test01{
public static void main(String[] args){
//创建属性对象
Properties p = new Properties();//和Map一样,只不过key和value只能存储字符串
//key不能重复,如果重复,后者会覆盖前者
//创建流
FileInputStream fis = new FileInputStream("dbinfo.properties");
//将fis流中的所有数据加载到属性对象中
p.load(fis);//所以现在属性对象p中有了键值对(key=username,value=scott)
//关闭流
fis.close();
String v1 = p.getProperty("driver");
String v2 = p.getProperty("url");
String v3 = p.getProperty("username");//如果读取的是中文,可以先将中文转ascll码再写上去
String v4 = p.getProperty("password");
System.out.println(v1);
System.out.println(v2);
System.out.println(v3);
System.out.println(v4);
}
}
dbinfo.properties
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@127.0.0.1:3306:bjpowernode
username=zhangsan
password=tiger
六、反射+IO+Properties联合应用,动态创建java对象
import java.io.*;
import java.util.*;
public class Test01{
public static void main(String[] args){
//1、创建属性对象
Properties p = new Properties();
//2、创建流
FileReader fr = new FileReader("classInfo.properties");
//3、加载
p.load(fr);
//4、关闭流
fr.close();
//通过key获取value
String className = p.getProperty("className");
//通过反射创建对象
Class c = Class.forName(className);
//创建对象
Object o = c.newInstance();
System.out.println(o);
}
}
classInfo.properties
className=java.util.Date
七、反编译
public class User{
//Field
private String id;
public int age;
protected String addr;
boolean sex;
}
这里反编译类中的属性
/*
这里反编译类中的属性
java.lang.reflect.Field;//类中的属性
*/
import java.lang.reflect.*;
public class Test01{
public static void main(String args){
//获取整个类
Class c = Class.forName("User");
//获取属性Field
/*
//获取所有的public修饰的属性
Field[] fs = c.getFields();
System.out.println(fs.length);
System.out.println(fs[0].getName());
*/
//获取所有的属性
Field[] fs = c.getDeclareFields();
/*
for(Field field:fs){
int i = field.getModifiers();
//System.out.println(i);
String strModifier Modifier.toString(i);
System.out.println(strModifier);
Class type = field.getType();
//System.out.println(type.getName());
System.out.println(type.getSimpleName());
System.out.println(field.getName());
}
*/
StringBuffer sb = new StringBuffer();
sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() + "{\n");
for(Field field:fs){
sb.append(\t);
sb.append(Modifier.toString(field.getModifiers()) + " ");
sb.append(field.getType().getSimpleName() + " ");
sb.append(field.getName()+";\n");
}
sb.append("}");
System.out.println(sb);
}
}
通过反编译获取某个类的具体的某个属性
/*
通过反编译获取某个类的具体的某个属性
*/
import java.lang.reflect.*;
public class Test02{
public static void main(Stirng[] args) throws Exception{
//以前的方式
/*
User u = new User();
u.age = 12;
System.out.println(u.age);
*/
//获取类
Class c = Class.forName("User");
//获取id属性
Field id = c.getDeclaredField("id");
//创建对象
Object o = c.newInstance();
//打破封装
id.setAccessible(true);
//使用反射机制可以打破分装,但同时也导致了java对象的不安全
//给o对象的id属性赋值“110”
id.set(o,"110");
//get
System.out.println(id.get(o));
}
}
反编译某个类的所有方法
/*
反编译某个类的所有方法
*/
import java.lang.reflect.*;
public class Test03{
public static void main(String[] args) throws Exception{
//获取类
Class c = Class.forName("java.lang.String");
//获取所有方法
Method[] ms = c.getDeclareMethods();
for(Method m:ms){
//修饰符号
System.out.println(Modifier.toString(m.getModifiers()));
//方法的返回值类型
Class returnType = m.getReturnType();
System.out.println(returnTyipe.getSimpleName());
//方法名
System.out.println(m.getName());
//方法的形式参数列表
Class[] p = m.getParameterTypes();
for(Class p:p){
System.out.println(p.getSimpleName());
}
}
}
}
获取某个特定的方法,通过反射机制执行
/*
获取某个特定的方法,通过反射机制执行
以前:
Test t = new Test();
t.login();
*/
import java.lang.reflect.*;
public class Test04{
public static void main(String[] args) throws Exception{
//获取类
Class c = Class.forName("CustomerService");
//获取某个特定的方法
//通过:方法名+形式参数列表
Method m = c.getDeclaredMethod("login",String.class,String.class);
//通过反射机制执行方法
Object o = c.newInstance();
Object retValue = m.invoke(o,"admin","123");
System.out.println(retValue);
}
}
反编译构造方法
/*
反编译构造方法
*/
import java.lang.reflect.*;
public class Test05{
public static void main(String[] args) throws Exception{
//获取类
Class c = Class.forName("java.lang.String");
//获取所有的构造方法
Constructor[] cs = c.getDeclaredContructors();
for(Contructor con:cs){
//获取修饰符
System.out.println(Modifier.toString(con.getModifiers()));
//获取名称
System.out.println(c.getName());
//获取参数列表
Class[] parameterTypes = con.getParameterTypes();
for(Class parameterType:parameterTypes){
System.out.println(parameterType.getSimpleName());
}
}
}
}
获取某个特定的构造方法
/*
获取某个特定的构造方法
*/
import java.lang.reflect.*;
public class Test06{
public static void main(String[] args) throws Exception{
//获取类
Class c = Class.forName("Customer");
//获取特定的构造方法
Constructor con = c.getDeclaredCOnstructor(String.class,String.class);
//创建对象
Object o = con.newInstance("张三",23);
System.out.println(o);
}
}
class Customer{
String name;
int age;
Customer(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return "Customer["+name+","+age+"]";
}
}
获取一个类的父类和父接口
/*
获取一个类的父类和父接口
*/
import java.lang.reflect.*;
public class Test07{
//获取String类的父类和父接口
public static void main(String[] args) throws Exception{
Class c = Class.forName("java.lang.String");
//获取父类
Class superClass = c.getSuperclass();
//获取父接口
Class[] ins = c.getInterfaces();
}
}
反射机制的两大缺点
1、性能问题:性能比不上直接调用
2、安全问题:打破了封装,使得数据不安全
参考:https://www.bilibili.com/video/BV1kx411h7jv