java反射创建类_Java基础:反射机制详解c++string类型
⼀、什么是反射:
(1)Java反射机制的核⼼是在程序运⾏时动态加载类并获取类的详细信息,从⽽操作类或对象的属性和⽅法。本质是JVM得到class对象之后,再通过class对象进⾏反编译,从⽽获取t对象的各种信息。
(2)Java属于先编译再运⾏的语⾔,程序中对象的类型在编译期就确定下来了,⽽当程序在运⾏时可能需要动态加载某些类,这些类因为之前⽤不到,所以没有被加载到JVM。通过反射,可以在运⾏时动态地创建对象并调⽤其属性,不需要提前在编译期知道运⾏的对象是谁。
⼆、反射的原理:
下图是类的正常加载过程、反射原理与class对象:
Class对象的由来是将class⽂件读⼊内存,并为之创建⼀个Class对象。
三、反射的优缺点:
1、优点:在运⾏时获得类的各种内容,进⾏反编译,对于Java这种先编译再运⾏的语⾔,能够让我们
很⽅便的创建灵活的代码,这些代码可以在运⾏时装配,⽆需在组件之间进⾏源代码的链接,更加容易实现⾯向对象。
2、缺点:(1)反射会消耗⼀定的系统资源,因此,如果不需要动态地创建⼀个对象,那么就不需要⽤反射;
(2)反射调⽤⽅法时可以忽略权限检查,因此可能会破坏封装性⽽导致安全问题。
四、反射的⽤途:
1、反编译:.class-->.java
2、通过反射机制访问java对象的属性,⽅法,构造⽅法等
3、当我们在使⽤IDE,⽐如Ecplise时,当我们输⼊⼀个对象或者类,并想调⽤他的属性和⽅法是,⼀按点号,编译器就会⾃动列出他的属性或者⽅法,这⾥就是⽤到反射。
4、反射最重要的⽤途就是开发各种通⽤框架。⽐如很多框架(Spring)都是配置化的(⽐如通过XML⽂件配置Bean),为了保证框架的通⽤性,他们可能需要根据配置⽂件加载不同的类或者对象,调⽤不同的⽅法,这个时候就必须使⽤到反射了,运⾏时动态加载需要的加载的对象。
5、例如,在使⽤Strut2框架的开发过程中,我们⼀般会在l⾥去配置Action,⽐如
/shop/shop-index.jsp
login.jsp
⽐如我们请求login.action时,那么StrutsPrepareAndExecuteFilter就会去解析l⽂件,从action中查出name为login的Action,并根据class属性创建SimpleLoginAction实例,并⽤Invoke⽅法来调⽤execute⽅法,这个过程离不开反射。配置⽂件与Action 建⽴了⼀种映射关系,当View层发出请求时,请求会被StrutsPrepareAndExecuteFilter拦截,然后StrutsPrepareAndExecuteFilter会去动态地创建Action实例。
⽐如,加载数据库驱动的,⽤到的也是反射。
Class.forName("sql.jdbc.Driver"); // 动态加载mysql驱动
五、反射机制常⽤的类:
Java.lang.Class;
flect.Constructor;
flect.Field;
flect.Method;
flect.Modifier;
六、反射的基本使⽤:
1、获得Class:主要有三种⽅法:
(1)Object-->getClass
(2)任何数据类型(包括基本的数据类型)都有⼀个“静态”的class属性
(3)通过class类的静态⽅法:forName(String className)(最常⽤)
package fanshe;
public class Fanshe{
public static void main(String[] args){
/
/第⼀种⽅式获取Class对象
Student stu1 = new Student();//这⼀new 产⽣⼀个Student对象,⼀个Class对象。
Class stuClass = Class();//获取Class对象
System.out.Name());
//第⼆种⽅式获取Class对象
Class stuClass2 = Student.class;
System.out.println(stuClass == stuClass2);//判断第⼀种⽅式获取的Class对象和第⼆种⽅式获取的是否是同⼀个
//第三种⽅式获取Class对象
try {
Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
System.out.println(stuClass3 == stuClass2);//判断三种⽅式是否获取的是同⼀个Class对象
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
注意,在运⾏期间,⼀个类,只有⼀个Class对象产⽣,所以打印结果都是true;
三种⽅式中,常⽤第三种,第⼀种对象都有了还要反射⼲什么,第⼆种需要导⼊类包,依赖太强,不导包就抛编译错误。⼀般都使⽤第三种,⼀个字符串可以传⼊也可以写在配置⽂件中等多种⽅法。
2、判断是否为某个类的⽰例:
⼀般的,我们使⽤instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中Class对象的isInstance()⽅法来判断时候为某个类的实例,他是⼀个native⽅法。
public native boolean isInstance(Object obj);
3、创建实例:通过反射来⽣成对象主要有两种⽅法:
(1)使⽤Class对象的newInstance()⽅法来创建Class对象对应类的实例。
Class> c = String.class;
Object str = c.newInstance();
(2)先通过Class对象获取指定的Constructor对象,再调⽤Constructor对象的newInstance()⽅法来创建对象,这种⽅法可以⽤指定的构造器构造类的实例。
//获取String的Class对象
Class> str = String.class;
//通过Class对象获取指定的Constructor构造器对象
Constructor Constructor(String.class);
//根据构造器创建实例:
Object obj = wInstance(“hello reflection”);
4、通过反射获取构造⽅法并使⽤:
(1)批量获取的⽅法:
public Constructor[] getConstructors():所有"公有的"构造⽅法
public Constructor[] getDeclaredConstructors():获取所有的构造⽅法(包括私有、受保护、默认、公有)
(2)单个获取的⽅法,并调⽤:
public Constructor parameterTypes):获取单个的"公有的"构造⽅法:
public Constructor parameterTypes):获取"某个构造⽅法"可以是私有的,或受保护、默认、公有;
(3) 调⽤构造⽅法:
Constructor--> initargs)
newInstance是 Constructor类的⽅法(管理构造函数的类)
api的解释为: initargs) ,使⽤此 Constructor 对象表⽰的构造⽅法来创建该构造⽅法的声明类的新实例,并⽤指定的初始化参数初始化该实例。
它的返回值是T类型,所以newInstance是创建了⼀个构造⽅法的声明类的新实例对象,并为之调⽤。
例⼦:
Student类:共六个构造⽅法。
package fanshe;
public class Student{
//---------------构造⽅法-------------------
//(默认的构造⽅法)
Student(String str){
System.out.println("(默认)的构造⽅法 s = " + str);
}
//⽆参构造⽅法
public Student(){
System.out.println("调⽤了公有、⽆参构造⽅法执⾏了。。。");
}
//有⼀个参数的构造⽅法
public Student(char name){
System.out.println("姓名:" + name);
}
//有多个参数的构造⽅法
public Student(String name ,int age){
System.out.println("姓名:"+name+"年龄:"+ age);//这的执⾏效率有问题,以后解决。
}
//受保护的构造⽅法
protected Student(boolean n){
System.out.println("受保护的构造⽅法 n = " + n);
}
//私有构造⽅法
private Student(int age){
System.out.println("私有的构造⽅法  年龄:"+ age);
}
}
测试类:
package fanshe;
import flect.Constructor;
/*
* 通过Class对象可以获取某个类中的:构造⽅法、成员变量、成员⽅法;并访问成员;
*
* 1.获取构造⽅法:
* 1).批量的⽅法:
* public Constructor[] getConstructors():所有"公有的"构造⽅法
public Constructor[] getDeclaredConstructors():获取所有的构造⽅法(包括私有、受保护、默认、公有)
* 2).获取单个的⽅法,并调⽤:
* public Constructor parameterTypes):获取单个的"公有的"构造⽅法:
* public Constructor parameterTypes):获取"某个构造⽅法"可以是私有的,或受保护、默认、公有;
* 3).调⽤构造⽅法:
* Constructor--> initargs)
*/
public class Constructors{
public static void main(String[] args) throws Exception{
//1.加载Class对象
Class clazz = Class.forName("fanshe.Student");
//2.获取所有公有构造⽅法
System.out.println("**********************所有公有构造⽅法*********************************");
Constructor[] conArray = Constructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("************所有的构造⽅法(包括:私有、受保护、默认、公有)***************"); conArray = DeclaredConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("*****************获取公有、⽆参的构造⽅法*******************************");
Constructor con = Constructor(null);
/
/1>、因为是⽆参的构造⽅法所以类型是⼀个null,不写也可以:这⾥需要的是⼀个参数的类型,切记是类型//2>、返回的是描述这个⽆参构造函数的类对象。
System.out.println("con = " + con);
//调⽤构造⽅法
Object obj = wInstance();
//System.out.println("obj = " + obj);
//Student stu = (Student)obj;
System.out.println("******************获取私有构造⽅法,并调⽤*******************************");
con = DeclaredConstructor(char.class);
System.out.println(con);
//调⽤构造⽅法
con.setAccessible(true);//暴⼒访问(忽略掉访问修饰符)
obj = wInstance('男');
}
}
控制台输出:
**********************所有公有构造⽅法*********************************
public fanshe.Student(java.lang.String,int)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。